I know this post is a little older but I agree with the hybrid approach. There are certain situations where the query builder syntax provides good feedback for a "bad" query being written which is great.
On the opposite side, I have some queries that I think would just become too verbose written using the builder so I use .raw. Here is an example of a query that I would consider as keeping in the .raw format.
select
s.client_id,
s.package_id,
p.products as pp,
s.products as sp
from (
# grouped subscribed products
select
client_id,
package_id,
group_concat(product_id order by product_id) as products
from subscriptions where package_id is not null
group by client_id, package_id) as s
inner join (
# grouped package products
select
package_id,
group_concat(product_id order by product_id) as products
from package_products
group by package_id) as p
on p.package_id = s.package_id where p.products <> s.products
order by s.client_id
I could certainly use the builder but I find the raw SQL a lot easier to grasp with nested selects. I also create an abstract class to simplify down into a micro-ORM.
class Table {
constructor() {
// nothing
}
static tableName = null;
/**
* Find by id
* @param {Integer} userId
* @return {Promise}
*
* Example:
* Table.findById(id).then(result => {
* console.log(result)
* }).catch(err => {
* console.error(err);
* })
*/
static findById(itemId) {
return this.findOneBy({id: itemId});
}
/**
* Generic findBy
* @param {String|Object} column or objcet with keys
* @param {Any} value
*/
static findOneBy(column, value = null) {
return this.findBy(column, value).then(results => {
return results[0];
});
}
/**
* Generic findBy
* @param {String|Object} column or objcet with keys
* @param {Any} value
*/
static findBy(column, value = null) {
return database.getConnection().then(conn => {
const schema = this.schemaName;
const query = conn.select().from(this.tableName);
if (schema){
query.withSchema(schema);
}
if (typeof column === 'object '&& !Array.isArray(column) && value === null) {
for (const col in column) {
query.where(col, column[col]);
}
} else {
query.where(column, value);
}
return query;
});
}
}
This allows me to create models by using:
class Client extends Table {
static tableName = 'clients';
constructor() {
super();
}
}
Client.findById(1).then(result => {
console.log(result);
}).catch(console.error);