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.
72 lines (71 loc) • 2.58 kB
JavaScript
import { isComparisonWhere } from "../core/where.js";
import { fieldToStr } from "../sql/pg.js";
import { and, arrayContained, arrayContains, arrayOverlaps, asc, desc, eq, gt, gte, ilike, inArray, isNull, like, lt, lte, not, or, sql } from "drizzle-orm";
//#region src/drizzle/pg.ts
const opMap = {
"=": eq,
">": gt,
">=": gte,
"<": lt,
"<=": lte,
like,
ilike
};
const setOps = {
"@>": arrayContains,
"<@": arrayContained,
"&&": arrayOverlaps
};
const _toDrizzleWhere = (table, where) => {
if (!where) return void 0;
if (where.op === "not") {
const subCondition = _toDrizzleWhere(table, where.condition);
return subCondition ? not(subCondition) : void 0;
}
if (where.op === "and" || where.op === "or") {
const conditions = where.conditions.map((c) => _toDrizzleWhere(table, c)).filter((c) => !!c);
if (conditions.length === 0) return;
return where.op === "and" ? and(...conditions) : or(...conditions);
}
if (!isComparisonWhere(where)) return;
const [rootKey, ...segments] = where.field;
const column = table[rootKey];
if (!column) {
console.warn(`Field ${rootKey} does not exist on table`);
return;
}
const target = segments.length === 0 ? column : sql.raw(fieldToStr(where.field));
if (where.op === "in") return inArray(target, where.values);
if (where.op === "is null") return isNull(target);
if (where.op in setOps) {
const opFn = setOps[where.op];
if (!opFn) return;
return opFn(target, where.value);
}
const opFn = opMap[where.op];
if (!opFn) return;
return opFn(target, where.value);
};
const toDrizzleWhere = (table, where, extraConditions) => {
const whereConditions = _toDrizzleWhere(table, where);
if (!extraConditions) return whereConditions;
if (!whereConditions) return extraConditions;
return and(extraConditions, whereConditions);
};
const toDrizzleOrderBy = (table, orderBy) => {
if (!orderBy) return [];
return orderBy.map((c) => {
const col = table[c.field[0]];
return (c.direction === "desc" ? desc : asc)(col);
});
};
const toDrizzle = (db, table, querySchema) => {
if (!querySchema) return db.select().from(table);
const query = db.select().from(table).where(toDrizzleWhere(table, querySchema.where)).orderBy(...toDrizzleOrderBy(table, querySchema.orderBy));
if (querySchema.limit && querySchema.offset) return query.limit(querySchema.limit).offset(querySchema.offset);
if (querySchema.limit) return query.limit(querySchema.limit);
if (querySchema.offset) return query.offset(querySchema.offset);
return query;
};
//#endregion
export { opMap, toDrizzle, toDrizzleOrderBy, toDrizzleWhere };