@devbro/sql-generator
Version:
generic sql generator
217 lines • 5.85 kB
JavaScript
function toUpperFirst(str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
class QueryGrammar {
sqlParts = [
"select",
"table",
"join",
"where",
"groupBy",
"having",
"orderBy",
"limit",
"offset"
];
toSql(query) {
let sql = "";
let bindings = [];
for (const part of this.sqlParts) {
const funcName = "compile" + toUpperFirst(part);
const r = this[funcName](query.parts[part]);
if (!sql) {
sql = r.sql;
} else if (r.sql) {
sql += " " + r.sql;
}
bindings = [...bindings, ...r.bindings];
}
return { sql, bindings };
}
compileSelect(selects) {
const rc = selects.map((v) => {
return v;
}).join(", ");
return { sql: "select " + rc, bindings: [] };
}
compileTable(tableName) {
let rc = "";
if (tableName.length) {
rc = "from " + tableName;
}
return { sql: rc, bindings: [] };
}
compileJoin(joins) {
let sql = "";
let bindings = [];
for (const j of joins) {
sql += " " + j.type + " join " + j.table + " on ";
const where = this.compileWhere(j.conditions);
if (where.sql.startsWith("where ")) {
where.sql = where.sql.substring("where ".length);
}
sql += "(";
sql += where.sql;
sql += ")";
bindings = [...bindings, ...where.bindings];
}
return { sql, bindings };
}
compileWhere(wheres) {
let sql = "";
let bindings = [];
for (const w of wheres) {
sql += " " + w.joinCondition + " ";
if (w.negateCondition) {
sql += "not ";
}
const funcName = "compileWhere" + toUpperFirst(w.type);
const wh = this[funcName](w);
sql += wh.sql;
bindings = [...bindings, ...wh.bindings];
}
if (sql.startsWith(" and ")) {
sql = "where " + sql.substring(" and ".length);
} else if (sql.startsWith(" or ")) {
sql = "where " + sql.substring(" or ".length);
}
return { sql, bindings };
}
compileWhereOperation(w) {
return {
sql: `${w.column} ${w.operation} ${this.getVariablePlaceholder()}`,
bindings: [w.value]
};
}
compileWhereOperationColumn(w) {
return {
sql: `${w.column1} ${w.operation} ${w.column2}`,
bindings: []
};
}
compileOrderBy(orderBy) {
let rc = "";
if (orderBy.length) {
rc = "order by " + orderBy.join(", ");
}
return { sql: rc, bindings: [] };
}
compileLimit(limit) {
let rc = "";
if (limit !== null) {
rc = "limit " + limit;
}
return { sql: rc, bindings: [] };
}
compileOffset(offset) {
let rc = "";
if (offset !== null) {
rc = "offset " + offset;
}
return { sql: rc, bindings: [] };
}
compileWhereNull(w) {
return {
sql: `${w.column} is null`,
bindings: []
};
}
compileInsert(query, data) {
let sql = "insert into " + query.parts.table + " (";
const columns = [];
const bindings = [];
const values = [];
for (const [k, v] of Object.entries(data)) {
columns.push(k);
bindings.push(v);
values.push(this.getVariablePlaceholder());
}
sql += columns.join(", ") + ") values (" + values + ")";
return { sql, bindings };
}
compileUpdate(query, data) {
let sql = "update " + query.parts.table + " set ";
const bindings = [];
const setParts = [];
for (const [k, v] of Object.entries(data)) {
setParts.push(`${k} = ${this.getVariablePlaceholder()}`);
bindings.push(v);
}
sql += setParts.join(", ");
const where_csql = this.compileWhere(query.parts.where);
sql += " " + where_csql.sql;
bindings.push(...where_csql.bindings);
return { sql, bindings };
}
compileDelete(query) {
let sql = "delete from " + query.parts.table;
const where_csql = this.compileWhere(query.parts.where);
sql += " " + where_csql.sql;
return { sql, bindings: where_csql.bindings };
}
compileUpsert(query, data, conflictFields, updateFields) {
let sql = "insert into " + query.parts.table + " (";
const columns = [];
const bindings = [];
const values = [];
for (const [k, v] of Object.entries(data)) {
columns.push(k);
bindings.push(v);
values.push(this.getVariablePlaceholder());
}
sql += columns.join(", ") + ") values (" + values + ")";
sql += " on conflict (" + conflictFields.join(", ") + ") do update set ";
const setParts = [];
for (const f of updateFields) {
setParts.push(`${f} = excluded.${f}`);
}
sql += setParts.join(", ");
const where_csql = this.compileWhere(query.parts.where);
sql += " " + where_csql.sql;
bindings.push(...where_csql.bindings);
return { sql, bindings };
}
compileGroupBy(groupBy) {
let rc = "";
if (groupBy.length) {
rc = "group by " + groupBy.join(", ");
}
return { sql: rc, bindings: [] };
}
compileHaving(having) {
let sql = "";
let bindings = [];
for (const w of having) {
sql += " " + w.joinCondition + " ";
if (w.negateCondition) {
sql += "not ";
}
const funcName = "compileHaving" + toUpperFirst(w.type);
const wh = this[funcName](w);
sql += wh.sql;
bindings = [...bindings, ...wh.bindings];
}
if (sql.startsWith(" and ")) {
sql = "having " + sql.substring(" and ".length);
} else if (sql.startsWith(" or ")) {
sql = "having " + sql.substring(" or ".length);
}
return { sql, bindings };
}
compileHavingOperation(w) {
return {
sql: `${w.column} ${w.operation} ${this.getVariablePlaceholder()}`,
bindings: [w.value]
};
}
compileHavingRaw(w) {
return {
sql: w.sql,
bindings: w.bindings
};
}
}
export {
QueryGrammar
};
//# sourceMappingURL=QueryGrammar.mjs.map