workers-qb
Version:
Zero dependencies Query Builder for Cloudflare Workers
1,172 lines (1,161 loc) • 37.6 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
ConflictTypes: () => ConflictTypes,
D1QB: () => D1QB,
DOQB: () => DOQB,
FetchTypes: () => FetchTypes,
JoinTypes: () => JoinTypes,
OrderTypes: () => OrderTypes,
PGQB: () => PGQB,
Query: () => Query,
QueryBuilder: () => QueryBuilder,
QueryWithExtra: () => QueryWithExtra,
Raw: () => Raw,
asyncLoggerWrapper: () => asyncLoggerWrapper,
asyncMigrationsBuilder: () => asyncMigrationsBuilder,
defaultLogger: () => defaultLogger,
syncLoggerWrapper: () => syncLoggerWrapper,
syncMigrationsBuilder: () => syncMigrationsBuilder,
trimQuery: () => trimQuery
});
module.exports = __toCommonJS(index_exports);
// src/enums.ts
var OrderTypes = /* @__PURE__ */ ((OrderTypes3) => {
OrderTypes3["ASC"] = "ASC";
OrderTypes3["DESC"] = "DESC";
return OrderTypes3;
})(OrderTypes || {});
var FetchTypes = /* @__PURE__ */ ((FetchTypes2) => {
FetchTypes2["ONE"] = "ONE";
FetchTypes2["ALL"] = "ALL";
return FetchTypes2;
})(FetchTypes || {});
var ConflictTypes = /* @__PURE__ */ ((ConflictTypes3) => {
ConflictTypes3["ROLLBACK"] = "ROLLBACK";
ConflictTypes3["ABORT"] = "ABORT";
ConflictTypes3["FAIL"] = "FAIL";
ConflictTypes3["IGNORE"] = "IGNORE";
ConflictTypes3["REPLACE"] = "REPLACE";
return ConflictTypes3;
})(ConflictTypes || {});
var JoinTypes = /* @__PURE__ */ ((JoinTypes2) => {
JoinTypes2["INNER"] = "INNER";
JoinTypes2["LEFT"] = "LEFT";
JoinTypes2["CROSS"] = "CROSS";
return JoinTypes2;
})(JoinTypes || {});
// src/logger.ts
function defaultLogger(query, meta) {
console.log(`[workers-qb][${meta.duration}ms] ${JSON.stringify(query)}`);
}
async function asyncLoggerWrapper(query, loggerFunction, innerFunction) {
const start = Date.now();
try {
return await innerFunction();
} catch (e) {
throw e;
} finally {
if (loggerFunction) {
if (Array.isArray(query)) {
for (const q of query) {
await loggerFunction(q.toObject(), { duration: Date.now() - start });
}
} else {
await loggerFunction(query.toObject(), { duration: Date.now() - start });
}
}
}
}
function syncLoggerWrapper(query, loggerFunction, innerFunction) {
const start = Date.now();
try {
return innerFunction();
} catch (e) {
throw e;
} finally {
if (loggerFunction) {
if (Array.isArray(query)) {
for (const q of query) {
loggerFunction(q.toObject(), { duration: Date.now() - start });
}
} else {
loggerFunction(query.toObject(), { duration: Date.now() - start });
}
}
}
}
// src/modularBuilder.ts
var SelectBuilder = class _SelectBuilder {
_debugger = false;
_options = {};
_fetchAll;
_fetchOne;
constructor(options, fetchAll, fetchOne) {
this._options = options;
this._fetchAll = fetchAll;
this._fetchOne = fetchOne;
}
setDebugger(state) {
this._debugger = state;
}
tableName(tableName) {
return new _SelectBuilder(
{
...this._options,
tableName
},
this._fetchAll,
this._fetchOne
);
}
fields(fields) {
return this._parseArray("fields", this._options.fields, fields);
}
where(conditions, params) {
const subQueryPlaceholders = this._options.subQueryPlaceholders ?? {};
let subQueryTokenNextId = this._options.subQueryTokenNextId ?? 0;
const existingConditions = this._options.where && typeof this._options.where === "object" && "conditions" in this._options.where ? this._options.where.conditions : [];
const existingParams = this._options.where && typeof this._options.where === "object" && "params" in this._options.where && this._options.where.params ? this._options.where.params : [];
const currentInputConditions = Array.isArray(conditions) ? conditions : [conditions];
const currentInputParams = params === void 0 ? [] : Array.isArray(params) ? params : [params];
const processedNewConditions = [];
const collectedPrimitiveParams = [];
let paramIndex = 0;
for (const conditionStr of currentInputConditions) {
if (!conditionStr.includes("?")) {
processedNewConditions.push(conditionStr);
continue;
}
const conditionParts = conditionStr.split("?");
let builtCondition = conditionParts[0] ?? "";
for (let j = 0; j < conditionParts.length - 1; j++) {
if (paramIndex >= currentInputParams.length) {
throw new Error('Mismatch between "?" placeholders and parameters in where clause.');
}
const currentParam = currentInputParams[paramIndex++];
const isSubQuery = typeof currentParam === "object" && currentParam !== null && ("tableName" in currentParam || "getOptions" in currentParam) && !currentParam.hasOwnProperty("_raw") || currentParam instanceof _SelectBuilder;
if (isSubQuery) {
const token = `__SUBQUERY_TOKEN_${subQueryTokenNextId++}__`;
subQueryPlaceholders[token] = currentParam instanceof _SelectBuilder ? currentParam.getOptions() : "getOptions" in currentParam && typeof currentParam.getOptions === "function" ? currentParam.getOptions() : currentParam;
builtCondition += token;
} else {
builtCondition += "?";
if (currentParam !== void 0) {
collectedPrimitiveParams.push(currentParam);
}
}
builtCondition += conditionParts[j + 1] ?? "";
}
processedNewConditions.push(builtCondition);
}
if (paramIndex < currentInputParams.length) {
throw new Error('Too many parameters provided for the given "?" placeholders in where clause.');
}
return new _SelectBuilder(
{
...this._options,
subQueryPlaceholders,
subQueryTokenNextId,
where: {
conditions: existingConditions.concat(processedNewConditions),
params: existingParams.concat(collectedPrimitiveParams)
}
},
this._fetchAll,
this._fetchOne
);
}
whereIn(fields, values) {
let whereInCondition;
let whereInParams;
const seperateWithComma = (prev, next) => prev + ", " + next;
if (values.length === 0) {
return new _SelectBuilder(
{
...this._options
},
this._fetchAll,
this._fetchOne
);
}
if (!Array.isArray(fields)) {
whereInCondition = `(${fields}) IN (VALUES `;
whereInCondition += values.map(() => "(?)").reduce(seperateWithComma);
whereInCondition += ")";
whereInParams = values;
} else {
const fieldLength = fields.length;
whereInCondition = `(${fields.map((val) => val).reduce(seperateWithComma)}) IN (VALUES `;
const valuesString = `(${[...new Array(fieldLength).keys()].map(() => "?").reduce(seperateWithComma)})`;
whereInCondition += [...new Array(values.length).keys()].map(() => valuesString).reduce(seperateWithComma);
whereInCondition += ")";
whereInParams = values.flat();
}
return this.where(whereInCondition, whereInParams);
}
join(join) {
const joins = Array.isArray(join) ? join : [join];
const processedJoins = joins.map((j) => {
if (j && typeof j.table === "object") {
if (j.table instanceof _SelectBuilder) {
return { ...j, table: j.table.getOptions() };
}
}
return j;
});
return this._parseArray("join", this._options.join, processedJoins);
}
groupBy(groupBy) {
return this._parseArray("groupBy", this._options.groupBy, groupBy);
}
having(conditions, params) {
const subQueryPlaceholders = this._options.subQueryPlaceholders ?? {};
let subQueryTokenNextId = this._options.subQueryTokenNextId ?? 0;
const existingConditions = this._options.having && typeof this._options.having === "object" && "conditions" in this._options.having ? this._options.having.conditions : [];
const existingParams = this._options.having && typeof this._options.having === "object" && "params" in this._options.having && this._options.having.params ? this._options.having.params : [];
const currentInputConditions = Array.isArray(conditions) ? conditions : [conditions];
const currentInputParams = params === void 0 ? [] : Array.isArray(params) ? params : [params];
const processedNewConditions = [];
const collectedPrimitiveParams = [];
let paramIndex = 0;
for (const conditionStr of currentInputConditions) {
if (!conditionStr.includes("?")) {
processedNewConditions.push(conditionStr);
continue;
}
const conditionParts = conditionStr.split("?");
let builtCondition = conditionParts[0] ?? "";
for (let j = 0; j < conditionParts.length - 1; j++) {
if (paramIndex >= currentInputParams.length) {
throw new Error('Mismatch between "?" placeholders and parameters in having clause.');
}
const currentParam = currentInputParams[paramIndex++];
const isSubQuery = typeof currentParam === "object" && currentParam !== null && ("tableName" in currentParam || "getOptions" in currentParam) && !currentParam.hasOwnProperty("_raw") || currentParam instanceof _SelectBuilder;
if (isSubQuery) {
const token = `__SUBQUERY_TOKEN_${subQueryTokenNextId++}__`;
subQueryPlaceholders[token] = currentParam instanceof _SelectBuilder ? currentParam.getOptions() : "getOptions" in currentParam && typeof currentParam.getOptions === "function" ? currentParam.getOptions() : currentParam;
builtCondition += token;
} else {
builtCondition += "?";
if (currentParam !== void 0) {
collectedPrimitiveParams.push(currentParam);
}
}
builtCondition += conditionParts[j + 1] ?? "";
}
processedNewConditions.push(builtCondition);
}
if (paramIndex < currentInputParams.length) {
throw new Error('Too many parameters provided for the given "?" placeholders in having clause.');
}
return new _SelectBuilder(
{
...this._options,
subQueryPlaceholders,
subQueryTokenNextId,
having: {
conditions: existingConditions.concat(processedNewConditions),
params: existingParams.concat(collectedPrimitiveParams)
}
},
this._fetchAll,
this._fetchOne
);
}
orderBy(orderBy) {
return this._parseArray("orderBy", this._options.orderBy, orderBy);
}
offset(offset) {
return new _SelectBuilder(
{
...this._options,
offset
},
this._fetchAll,
this._fetchOne
);
}
limit(limit) {
return new _SelectBuilder(
{
...this._options,
limit
},
this._fetchAll,
this._fetchOne
);
}
_parseArray(fieldName, option, value) {
let val = [];
if (!Array.isArray(value)) {
val.push(value);
} else {
val = value;
}
if (option && Array.isArray(option)) {
val = [...option, ...val];
}
return new _SelectBuilder(
{
...this._options,
[fieldName]: val
},
this._fetchAll,
this._fetchOne
);
}
getQueryAll(options) {
return this._fetchAll({
...this._options,
...options
});
}
getQueryOne() {
return this._fetchOne(this._options);
}
execute(options) {
return this._fetchAll({
...this._options,
...options
}).execute();
}
all(options) {
return this._fetchAll({
...this._options,
...options
}).execute();
}
one() {
return this._fetchOne(this._options).execute();
}
count() {
return this._fetchOne(this._options).count();
}
getOptions() {
return this._options;
}
};
// src/tools.ts
var Raw = class {
isRaw = true;
content;
constructor(content) {
this.content = content;
}
};
var Query = class {
executeMethod;
query;
arguments;
fetchType;
constructor(executeMethod, query, args, fetchType) {
this.executeMethod = executeMethod;
this.query = trimQuery(query);
this.arguments = args;
this.fetchType = fetchType;
}
execute() {
return this.executeMethod(this);
}
toObject() {
return {
query: this.query,
args: this.arguments,
fetchType: this.fetchType
};
}
};
var QueryWithExtra = class extends Query {
countQuery;
constructor(executeMethod, query, countQuery, args, fetchType) {
super(executeMethod, query, args, fetchType);
this.countQuery = countQuery;
}
count() {
return this.executeMethod(
new Query(this.executeMethod, this.countQuery, this.arguments, "ONE" /* ONE */)
);
}
};
function trimQuery(query) {
return query.replace(/\s\s+/g, " ");
}
// src/builder.ts
var QueryBuilder = class {
options;
loggerWrapper = asyncLoggerWrapper;
constructor(options) {
this.options = options || {};
}
setDebugger(state) {
if (state === true) {
if (this.options.logger) {
return;
}
this.options.logger = defaultLogger;
} else {
this.options.logger = void 0;
}
}
execute(query) {
throw new Error("Execute method not implemented");
}
batchExecute(queryArray) {
throw new Error("Batch execute method not implemented");
}
lazyExecute(query) {
throw new Error("Execute lazyExecute not implemented");
}
createTable(params) {
return new Query(
(q) => {
return this.execute(q);
},
`CREATE TABLE ${params.ifNotExists ? "IF NOT EXISTS" : ""} ${params.tableName}
( ${params.schema})`
);
}
dropTable(params) {
return new Query(
(q) => {
return this.execute(q);
},
`DROP TABLE ${params.ifExists ? "IF EXISTS" : ""} ${params.tableName}`
);
}
select(tableName) {
return new SelectBuilder(
{
tableName
},
(params) => {
return this.fetchAll(params);
},
(params) => {
return this.fetchOne(params);
}
);
}
fetchOne(params) {
const queryArgs = [];
const countQueryArgs = [];
const selectParamsForCount = {
...params,
fields: "count(*) as total",
offset: void 0,
groupBy: void 0,
limit: 1
};
if (params.subQueryPlaceholders) {
selectParamsForCount.subQueryPlaceholders = params.subQueryPlaceholders;
}
const mainSql = this._select({ ...params, limit: 1 }, queryArgs);
const countSql = this._select(selectParamsForCount, countQueryArgs);
return new QueryWithExtra(
(q) => {
return this.execute(q);
},
mainSql,
countSql,
queryArgs,
// Use the populated queryArgs from the main _select call
"ONE" /* ONE */
);
}
fetchAll(params) {
const queryArgs = [];
const countQueryArgs = [];
const mainQueryParams = { ...params, lazy: void 0 };
const countQueryParams = {
...params,
fields: "count(*) as total",
offset: void 0,
groupBy: void 0,
limit: 1,
lazy: void 0
};
if (params.subQueryPlaceholders) {
countQueryParams.subQueryPlaceholders = params.subQueryPlaceholders;
}
const mainSql = this._select(mainQueryParams, queryArgs);
const countSql = this._select(countQueryParams, countQueryArgs);
return new QueryWithExtra(
(q) => {
return params.lazy ? this.lazyExecute(q) : this.execute(q);
},
mainSql,
countSql,
queryArgs,
// Use the populated queryArgs from the main _select call
"ALL" /* ALL */
);
}
raw(params) {
return new Query(
(q) => {
return this.execute(q);
},
params.query,
params.args,
params.fetchType
);
}
insert(params) {
let args = [];
if (typeof params.onConflict === "object") {
if (typeof params.onConflict?.where === "object" && !Array.isArray(params.onConflict?.where) && params.onConflict?.where?.params) {
args = args.concat(params.onConflict.where?.params);
}
if (params.onConflict.data) {
args = args.concat(this._parse_arguments(params.onConflict.data));
}
}
if (Array.isArray(params.data)) {
for (const row of params.data) {
args = args.concat(this._parse_arguments(row));
}
} else {
args = args.concat(this._parse_arguments(params.data));
}
const fetchType = Array.isArray(params.data) ? "ALL" /* ALL */ : "ONE" /* ONE */;
return new Query(
(q) => {
return this.execute(q);
},
this._insert(params),
args,
fetchType
);
}
update(params) {
let args = this._parse_arguments(params.data);
if (typeof params.where === "object" && !Array.isArray(params.where) && params.where?.params) {
if (Array.isArray(params.where?.params)) {
args = params.where?.params.concat(args);
} else {
args = [params.where?.params].concat(args);
}
}
return new Query(
(q) => {
return this.execute(q);
},
this._update(params),
args,
"ALL" /* ALL */
);
}
delete(params) {
return new Query(
(q) => {
return this.execute(q);
},
this._delete(params),
typeof params.where === "object" && !Array.isArray(params.where) && params.where?.params ? Array.isArray(params.where?.params) ? params.where?.params : [params.where?.params] : void 0,
"ALL" /* ALL */
);
}
_parse_arguments(row) {
return Object.values(row).filter((value) => {
return !(value instanceof Raw);
});
}
_onConflict(resolution) {
if (resolution) {
if (typeof resolution === "object") {
if (!Array.isArray(resolution.column)) {
resolution.column = [resolution.column];
}
const _update_query = this.update({
tableName: "_REPLACE_",
data: resolution.data,
where: resolution.where
}).query.replace(" _REPLACE_", "");
return ` ON CONFLICT (${resolution.column.join(", ")}) DO ${_update_query}`;
}
return `OR ${resolution} `;
}
return "";
}
_insert(params) {
const rows = [];
let data;
if (!Array.isArray(params.data)) {
data = [params.data];
} else {
data = params.data;
}
if (!data || !data[0] || data.length === 0) {
throw new Error("Insert data is undefined");
}
const columns = Object.keys(data[0]).join(", ");
let index = 1;
let orConflict = "";
let onConflict = "";
if (params.onConflict && typeof params.onConflict === "object") {
onConflict = this._onConflict(params.onConflict);
if (typeof params.onConflict?.where === "object" && !Array.isArray(params.onConflict?.where) && params.onConflict?.where?.params) {
if (Array.isArray(params.onConflict.where?.params)) {
index += (params.onConflict.where?.params).length;
} else {
index += 1;
}
}
if (params.onConflict.data) {
index += this._parse_arguments(params.onConflict.data).length;
}
} else {
orConflict = this._onConflict(params.onConflict);
}
for (const row of data) {
const values = [];
Object.values(row).forEach((value) => {
if (value instanceof Raw) {
values.push(value.content);
} else {
values.push(`?${index}`);
index += 1;
}
});
rows.push(`(${values.join(", ")})`);
}
return `INSERT ${orConflict} INTO ${params.tableName} (${columns}) VALUES ${rows.join(", ")}` + onConflict + this._returning(params.returning);
}
_update(params) {
const whereParamsLength = typeof params.where === "object" && !Array.isArray(params.where) && params.where?.params ? Array.isArray(params.where?.params) ? Object.keys(params.where?.params).length : 1 : 0;
let whereString = this._where(params.where);
let parameterIndex = 1;
if (whereString && whereString.match(/(?<!\d)\?(?!\d)/)) {
whereString = whereString.replace(/\?/g, () => `?${parameterIndex++}`);
}
const set = [];
let index = 1;
for (const [key, value] of Object.entries(params.data)) {
if (value instanceof Raw) {
set.push(`${key} = ${value.content}`);
} else {
set.push(`${key} = ?${whereParamsLength + index}`);
index += 1;
}
}
return `UPDATE ${this._onConflict(params.onConflict)}${params.tableName}
SET ${set.join(", ")}` + whereString + this._returning(params.returning);
}
_delete(params) {
return `DELETE
FROM ${params.tableName}` + this._where(params.where) + this._returning(params.returning) + this._orderBy(params.orderBy) + this._limit(params.limit) + this._offset(params.offset);
}
_select(params, queryArgs) {
let newQueryArgs = queryArgs;
const isTopLevelCall = queryArgs === void 0;
if (isTopLevelCall) {
newQueryArgs = [];
}
const currentQueryArgs = newQueryArgs;
const context = {
subQueryPlaceholders: params.subQueryPlaceholders,
queryArgs: currentQueryArgs,
toSQLCompiler: this._select.bind(this)
};
return `SELECT ${this._fields(params.fields)}
FROM ${params.tableName}` + this._join(params.join, context) + this._where(params.where, context) + this._groupBy(params.groupBy) + this._having(params.having, context) + this._orderBy(params.orderBy) + this._limit(params.limit) + this._offset(params.offset);
}
_fields(value) {
if (!value) return "*";
if (typeof value === "string") return value;
return value.join(", ");
}
_where(value, context) {
if (!value) return "";
const currentContext = context ?? { queryArgs: [] };
let conditionStrings;
let primitiveParams = [];
if (typeof value === "object" && !Array.isArray(value)) {
conditionStrings = Array.isArray(value.conditions) ? value.conditions : [value.conditions];
if (value.params) {
primitiveParams = Array.isArray(value.params) ? value.params : [value.params];
}
} else if (Array.isArray(value)) {
conditionStrings = value;
} else {
conditionStrings = [value];
}
if (conditionStrings.length === 0) return "";
let primitiveParamIndex = 0;
const processedConditions = [];
for (const conditionStr of conditionStrings) {
const parts = conditionStr.split(/(__SUBQUERY_TOKEN_\d+__|\?)/g).filter(Boolean);
let builtCondition = "";
for (const part of parts) {
if (part === "?") {
if (primitiveParamIndex >= primitiveParams.length) {
throw new Error(
'SQL generation error: Not enough primitive parameters for "?" placeholders in WHERE clause.'
);
}
currentContext.queryArgs.push(primitiveParams[primitiveParamIndex++]);
builtCondition += "?";
} else if (part.startsWith("__SUBQUERY_TOKEN_") && part.endsWith("__")) {
if (!currentContext.subQueryPlaceholders || !currentContext.toSQLCompiler) {
throw new Error("SQL generation error: Subquery context not provided for token processing.");
}
const subQueryParams = currentContext.subQueryPlaceholders[part];
if (!subQueryParams) {
throw new Error(`SQL generation error: Subquery token ${part} not found in placeholders.`);
}
const subQuerySql = currentContext.toSQLCompiler(subQueryParams, currentContext.queryArgs);
builtCondition += `(${subQuerySql})`;
} else {
builtCondition += part;
}
}
processedConditions.push(builtCondition);
}
if (primitiveParamIndex < primitiveParams.length && primitiveParams.length > 0) {
throw new Error(
'SQL generation error: Too many primitive parameters provided for "?" placeholders in WHERE clause.'
);
}
if (processedConditions.length === 0) return "";
if (processedConditions.length === 1) {
return ` WHERE ${processedConditions[0]}`;
}
return ` WHERE (${processedConditions.join(") AND (")})`;
}
_join(value, context) {
if (!value) return "";
let joinArray;
if (!Array.isArray(value)) {
joinArray = [value];
} else {
joinArray = value;
}
const joinQuery = [];
joinArray.forEach((item) => {
const type = item.type ? `${item.type} ` : "";
let tableSql;
if (typeof item.table === "string") {
tableSql = item.table;
} else if (item.table instanceof SelectBuilder) {
tableSql = `(${context.toSQLCompiler(item.table.getOptions(), context.queryArgs)})`;
} else {
tableSql = `(${context.toSQLCompiler(item.table, context.queryArgs)})`;
}
joinQuery.push(`${type}JOIN ${tableSql}${item.alias ? ` AS ${item.alias}` : ""} ON ${item.on}`);
});
return " " + joinQuery.join(" ");
}
_groupBy(value) {
if (!value) return "";
if (typeof value === "string") return ` GROUP BY ${value}`;
return ` GROUP BY ${value.join(", ")}`;
}
_having(value, context) {
if (!value) return "";
const currentContext = context ?? { queryArgs: [] };
let conditionStrings;
let primitiveParams = [];
if (typeof value === "object" && !Array.isArray(value)) {
conditionStrings = Array.isArray(value.conditions) ? value.conditions : [value.conditions];
if (value.params) {
primitiveParams = Array.isArray(value.params) ? value.params : [value.params];
}
} else if (Array.isArray(value)) {
conditionStrings = value;
} else {
conditionStrings = [value];
}
if (conditionStrings.length === 0) return "";
let primitiveParamIndex = 0;
const processedConditions = [];
for (const conditionStr of conditionStrings) {
const parts = conditionStr.split(/(__SUBQUERY_TOKEN_\d+__|\?)/g).filter(Boolean);
let builtCondition = "";
for (const part of parts) {
if (part === "?") {
if (primitiveParamIndex >= primitiveParams.length) {
throw new Error(
'SQL generation error: Not enough primitive parameters for "?" placeholders in HAVING clause.'
);
}
currentContext.queryArgs.push(primitiveParams[primitiveParamIndex++]);
builtCondition += "?";
} else if (part.startsWith("__SUBQUERY_TOKEN_") && part.endsWith("__")) {
if (!currentContext.subQueryPlaceholders || !currentContext.toSQLCompiler) {
throw new Error("SQL generation error: Subquery context not provided for token processing.");
}
const subQueryParams = currentContext.subQueryPlaceholders[part];
if (!subQueryParams) {
throw new Error(`SQL generation error: Subquery token ${part} not found in placeholders.`);
}
const subQuerySql = currentContext.toSQLCompiler(subQueryParams, currentContext.queryArgs);
builtCondition += `(${subQuerySql})`;
} else {
builtCondition += part;
}
}
processedConditions.push(builtCondition);
}
if (primitiveParamIndex < primitiveParams.length && primitiveParams.length > 0) {
throw new Error(
'SQL generation error: Too many primitive parameters provided for "?" placeholders in HAVING clause.'
);
}
if (processedConditions.length === 0) return "";
if (processedConditions.length === 1) {
return ` HAVING ${processedConditions[0]}`;
}
return ` HAVING (${processedConditions.join(") AND (")})`;
}
_orderBy(value) {
if (!value) return "";
if (typeof value === "string") return ` ORDER BY ${value}`;
const order = [];
if (Array.isArray(value)) {
for (const val of value) {
order.push(val);
}
} else {
order.push(value);
}
const result = order.map((obj) => {
if (typeof obj === "object") {
const objs = [];
Object.entries(obj).forEach(([key, item]) => {
objs.push(`${key} ${item}`);
});
return objs.join(", ");
}
return obj;
});
return ` ORDER BY ${result.join(", ")}`;
}
_limit(value) {
if (!value) return "";
return ` LIMIT ${value}`;
}
_offset(value) {
if (!value) return "";
return ` OFFSET ${value}`;
}
_returning(value) {
if (!value) return "";
if (typeof value === "string") return ` RETURNING ${value}`;
return ` RETURNING ${value.join(", ")}`;
}
};
// src/migrations.ts
var syncMigrationsBuilder = class {
_builder;
_migrations;
_tableName;
constructor(options, builder) {
this._tableName = options.tableName || "migrations";
this._migrations = options.migrations;
this._builder = builder;
}
initialize() {
this._builder.createTable({
tableName: this._tableName,
schema: `id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL`,
ifNotExists: true
}).execute();
return;
}
getApplied() {
this.initialize();
const result = this._builder.fetchAll({
tableName: this._tableName,
orderBy: "id"
}).execute();
return result.results || [];
}
getUnapplied() {
const appliedMigrations = this.getApplied().map((migration) => {
return migration.name;
});
const unappliedMigrations = [];
for (const migration of this._migrations) {
if (!appliedMigrations.includes(migration.name)) {
unappliedMigrations.push(migration);
}
}
return unappliedMigrations;
}
apply() {
const appliedMigrations = [];
for (const migration of this.getUnapplied()) {
this._builder.raw({
query: `
${migration.sql}
INSERT INTO ${this._tableName} (name)
values ('${migration.name}');`
}).execute();
appliedMigrations.push(migration);
}
return appliedMigrations;
}
};
var asyncMigrationsBuilder = class {
_builder;
_migrations;
_tableName;
constructor(options, builder) {
this._tableName = options.tableName || "migrations";
this._migrations = options.migrations;
this._builder = builder;
}
async initialize() {
await this._builder.createTable({
tableName: this._tableName,
schema: `id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL`,
ifNotExists: true
}).execute();
return;
}
async getApplied() {
await this.initialize();
const result = await this._builder.fetchAll({
tableName: this._tableName,
orderBy: "id"
}).execute();
return result.results || [];
}
async getUnapplied() {
const appliedMigrations = (await this.getApplied()).map((migration) => {
return migration.name;
});
const unappliedMigrations = [];
for (const migration of this._migrations) {
if (!appliedMigrations.includes(migration.name)) {
unappliedMigrations.push(migration);
}
}
return unappliedMigrations;
}
async apply() {
const appliedMigrations = [];
for (const migration of await this.getUnapplied()) {
await this._builder.raw({
query: `
${migration.sql}
INSERT INTO ${this._tableName} (name)
values ('${migration.name}');`
}).execute();
appliedMigrations.push(migration);
}
return appliedMigrations;
}
};
// src/databases/d1.ts
var D1QB = class extends QueryBuilder {
db;
constructor(db, options) {
super(options);
this.db = db;
}
migrations(options) {
return new asyncMigrationsBuilder(options, this);
}
async execute(query) {
return await this.loggerWrapper(query, this.options.logger, async () => {
let stmt = this.db.prepare(query.query);
if (query.arguments) {
stmt = stmt.bind(...query.arguments);
}
if (query.fetchType === "ONE" /* ONE */ || query.fetchType === "ALL" /* ALL */) {
const resp = await stmt.all();
const meta = resp.meta;
return {
changes: meta?.changes,
duration: meta?.duration,
last_row_id: meta?.last_row_id,
served_by: meta?.served_by,
rowsRead: meta?.rows_read,
rowsWritten: meta?.rows_written,
meta: resp.meta,
success: resp.success,
results: query.fetchType === "ONE" /* ONE */ ? resp.results[0] : resp.results
};
}
return stmt.run();
});
}
async batchExecute(queryArray) {
return await this.loggerWrapper(queryArray, this.options.logger, async () => {
const statements = queryArray.map((query) => {
let stmt = this.db.prepare(query.query);
if (query.arguments) {
stmt = stmt.bind(...query.arguments);
}
return stmt;
});
const responses = await this.db.batch(statements);
return responses.map(
(resp, i) => {
if (queryArray && queryArray[i] !== void 0 && queryArray[i]?.fetchType) {
return {
changes: resp.meta?.changes,
duration: resp.meta?.duration,
last_row_id: resp.meta?.last_row_id,
served_by: resp.meta?.served_by,
rowsRead: resp.meta?.rows_read,
rowsWritten: resp.meta?.rows_written,
meta: resp.meta,
success: resp.success,
results: queryArray[i]?.fetchType === "ONE" /* ONE */ ? resp.results?.[0] : resp.results
};
}
return {
changes: resp.meta?.changes,
duration: resp.meta?.duration,
last_row_id: resp.meta?.last_row_id,
served_by: resp.meta?.served_by,
rowsRead: resp.meta?.rows_read,
rowsWritten: resp.meta?.rows_written,
meta: resp.meta,
success: resp.success
};
}
);
});
}
};
// src/databases/do.ts
var DOQB = class extends QueryBuilder {
db;
loggerWrapper = syncLoggerWrapper;
constructor(db, options) {
super(options);
this.db = db;
}
migrations(options) {
return new syncMigrationsBuilder(options, this);
}
execute(query) {
return this.loggerWrapper(query, this.options.logger, () => {
let cursor;
if (query.arguments) {
cursor = this.db.exec(query.query, ...query.arguments);
} else {
cursor = this.db.exec(query.query);
}
const result = cursor.toArray();
const rowsRead = cursor.rowsRead;
const rowsWritten = cursor.rowsWritten;
if (query.fetchType == "ONE" /* ONE */) {
return {
results: result.length > 0 ? result[0] : void 0,
rowsRead,
rowsWritten
};
}
return {
results: result,
rowsRead,
rowsWritten
};
});
}
lazyExecute(query) {
return this.loggerWrapper(query, this.options.logger, () => {
let cursor;
if (query.arguments) {
cursor = this.db.exec(query.query, ...query.arguments);
} else {
cursor = this.db.exec(query.query);
}
return cursor;
});
}
};
// src/databases/pg.ts
var PGQB = class extends QueryBuilder {
db;
_migrationsBuilder = asyncMigrationsBuilder;
constructor(db, options) {
super(options);
this.db = db;
}
migrations(options) {
return new asyncMigrationsBuilder(options, this);
}
async connect() {
await this.db.connect();
}
async close() {
await this.db.end();
}
async execute(query) {
return await this.loggerWrapper(query, this.options.logger, async () => {
const queryString = query.query.replaceAll("?", "$");
let result;
if (query.arguments) {
result = await this.db.query({
values: query.arguments,
text: queryString
});
} else {
result = await this.db.query({
text: queryString
});
}
if (query.fetchType === "ONE" /* ONE */ || query.fetchType === "ALL" /* ALL */) {
return {
command: result.command,
lastRowId: result.oid,
rowCount: result.rowCount,
results: query.fetchType === "ONE" /* ONE */ ? result.rows[0] : result.rows
};
}
return {
command: result.command,
lastRowId: result.oid,
rowCount: result.rowCount
};
});
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ConflictTypes,
D1QB,
DOQB,
FetchTypes,
JoinTypes,
OrderTypes,
PGQB,
Query,
QueryBuilder,
QueryWithExtra,
Raw,
asyncLoggerWrapper,
asyncMigrationsBuilder,
defaultLogger,
syncLoggerWrapper,
syncMigrationsBuilder,
trimQuery
});