agnostic-query
Version:
Type-safe fluent builder for portable query schemas. Runtime-agnostic, database-agnostic — the same QuerySchema drives Drizzle, Kysely, db0, or raw SQL.
67 lines (66 loc) • 2.28 kB
JavaScript
import { isComparisonWhere } from "../core/where.js";
//#region src/sql/common.ts
const quoteIdent = (s) => `"${s.replace(/"/g, "\"\"")}"`;
const buildWhere = (where, fieldToStr, placeholderForIndex, startIndex = 1) => {
if (where.op === "not") {
const inner = buildWhere(where.condition, fieldToStr, placeholderForIndex, startIndex);
if (!inner) return;
return {
sql: `NOT (${inner.sql})`,
params: inner.params
};
}
if (where.op === "and" || where.op === "or") {
let idx = startIndex;
const parts = where.conditions.map((c) => {
const res = buildWhere(c, fieldToStr, placeholderForIndex, idx);
if (res) idx = idx + res.params.length;
return res;
}).filter((c) => c !== void 0);
if (parts.length === 0) return;
const joiner = ` ${where.op.toUpperCase()} `;
const sql = parts.map((p) => p.sql).join(joiner);
return {
sql: parts.length > 1 ? `(${sql})` : sql,
params: parts.flatMap((p) => p.params)
};
}
if (!isComparisonWhere(where)) return;
const fieldStr = fieldToStr(where.field);
if (where.op === "in") return {
sql: `${fieldStr} IN (${where.values.map((_, i) => placeholderForIndex(i + startIndex)).join(", ")})`,
params: where.values
};
if (where.op === "is null") return {
sql: `${fieldStr} IS NULL`,
params: []
};
return {
sql: `${fieldStr} ${where.op} ${placeholderForIndex(startIndex)}`,
params: [where.value]
};
};
const toSqlOrderBy = (orderBy, fieldToStr) => {
if (!orderBy) return;
return {
sql: orderBy.map((c) => `${fieldToStr(c.field)} ${c.direction.toUpperCase()}`).join(", "),
params: []
};
};
const _toSql = (json, fieldToStr, buildWhereFn) => {
if (!json.table) throw new Error("Table name is required");
const where = json.where ? buildWhereFn(json.where) : void 0;
const orderBy = json.orderBy?.length ? toSqlOrderBy(json.orderBy, fieldToStr) : void 0;
return {
sql: [
`SELECT * FROM ${quoteIdent(json.table)}`,
where ? `WHERE ${where.sql}` : "",
orderBy ? `ORDER BY ${orderBy.sql}` : "",
json.limit !== void 0 ? `LIMIT ${json.limit}` : "",
json.offset !== void 0 ? `OFFSET ${json.offset}` : ""
].filter(Boolean).join(" "),
params: [...where?.params ?? [], ...orderBy?.params ?? []]
};
};
//#endregion
export { _toSql, buildWhere, quoteIdent, toSqlOrderBy };