bun-query-builder 0.2.28 → 0.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +564 -371
- package/dist/browser.d.ts +2 -2
- package/dist/client.d.ts +7 -0
- package/dist/db.d.ts +29 -4
- package/dist/faker-compat.d.ts +83 -0
- package/dist/index.d.ts +1 -0
- package/dist/orm.d.ts +3 -3
- package/dist/schema.d.ts +2 -2
- package/dist/sql-fragments.d.ts +69 -0
- package/dist/src/index.js +564 -370
- package/dist/type-inference.d.ts +3 -3
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -11861,6 +11861,68 @@ import { Database } from "bun:sqlite";
|
|
|
11861
11861
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
11862
11862
|
import { dirname as dirname5 } from "path";
|
|
11863
11863
|
import process21 from "process";
|
|
11864
|
+
function bindNumberedPlaceholders(sql, params) {
|
|
11865
|
+
if (params.length === 0 || !/\$\d/.test(sql))
|
|
11866
|
+
return { sql, params };
|
|
11867
|
+
const out = [];
|
|
11868
|
+
let rewritten = "";
|
|
11869
|
+
let highest = 0;
|
|
11870
|
+
for (let i = 0;i < sql.length; i++) {
|
|
11871
|
+
const char = sql[i];
|
|
11872
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
11873
|
+
const end = skipQuoted(sql, i, char);
|
|
11874
|
+
rewritten += sql.slice(i, end);
|
|
11875
|
+
i = end - 1;
|
|
11876
|
+
continue;
|
|
11877
|
+
}
|
|
11878
|
+
if (char === "-" && sql[i + 1] === "-") {
|
|
11879
|
+
const end = sql.indexOf(`
|
|
11880
|
+
`, i);
|
|
11881
|
+
const stop = end === -1 ? sql.length : end;
|
|
11882
|
+
rewritten += sql.slice(i, stop);
|
|
11883
|
+
i = stop - 1;
|
|
11884
|
+
continue;
|
|
11885
|
+
}
|
|
11886
|
+
if (char === "/" && sql[i + 1] === "*") {
|
|
11887
|
+
const end = sql.indexOf("*/", i + 2);
|
|
11888
|
+
const stop = end === -1 ? sql.length : end + 2;
|
|
11889
|
+
rewritten += sql.slice(i, stop);
|
|
11890
|
+
i = stop - 1;
|
|
11891
|
+
continue;
|
|
11892
|
+
}
|
|
11893
|
+
if (char === "$") {
|
|
11894
|
+
const digits = /^\d+/.exec(sql.slice(i + 1))?.[0];
|
|
11895
|
+
if (digits) {
|
|
11896
|
+
const index = Number(digits);
|
|
11897
|
+
highest = Math.max(highest, index);
|
|
11898
|
+
if (index >= 1 && index <= params.length) {
|
|
11899
|
+
out.push(params[index - 1]);
|
|
11900
|
+
rewritten += "?";
|
|
11901
|
+
i += digits.length;
|
|
11902
|
+
continue;
|
|
11903
|
+
}
|
|
11904
|
+
}
|
|
11905
|
+
}
|
|
11906
|
+
rewritten += char;
|
|
11907
|
+
}
|
|
11908
|
+
if (highest > params.length)
|
|
11909
|
+
throw new Error(`SQL references $${highest} but only ${params.length} value${params.length === 1 ? " was" : "s were"} provided`);
|
|
11910
|
+
if (out.length === 0)
|
|
11911
|
+
return { sql, params };
|
|
11912
|
+
return { sql: rewritten, params: out };
|
|
11913
|
+
}
|
|
11914
|
+
function skipQuoted(sql, start, quote) {
|
|
11915
|
+
for (let i = start + 1;i < sql.length; i++) {
|
|
11916
|
+
if (sql[i] !== quote)
|
|
11917
|
+
continue;
|
|
11918
|
+
if (sql[i + 1] === quote) {
|
|
11919
|
+
i++;
|
|
11920
|
+
continue;
|
|
11921
|
+
}
|
|
11922
|
+
return i + 1;
|
|
11923
|
+
}
|
|
11924
|
+
return sql.length;
|
|
11925
|
+
}
|
|
11864
11926
|
|
|
11865
11927
|
class SQLiteWrapper {
|
|
11866
11928
|
db;
|
|
@@ -11875,12 +11937,14 @@ class SQLiteWrapper {
|
|
|
11875
11937
|
applySqliteBootstrapPragmas(this.db);
|
|
11876
11938
|
}
|
|
11877
11939
|
query(sql, params = []) {
|
|
11878
|
-
const
|
|
11879
|
-
|
|
11940
|
+
const bound = bindNumberedPlaceholders(sql, params);
|
|
11941
|
+
const stmt = this.db.prepare(bound.sql);
|
|
11942
|
+
return stmt.all(...bound.params);
|
|
11880
11943
|
}
|
|
11881
11944
|
run(sql, params = []) {
|
|
11882
|
-
const
|
|
11883
|
-
|
|
11945
|
+
const bound = bindNumberedPlaceholders(sql, params);
|
|
11946
|
+
const stmt = this.db.prepare(bound.sql);
|
|
11947
|
+
return stmt.run(...bound.params);
|
|
11884
11948
|
}
|
|
11885
11949
|
close() {
|
|
11886
11950
|
this.db.close();
|
|
@@ -12554,6 +12618,30 @@ var init_pivot = __esm(() => {
|
|
|
12554
12618
|
init_config();
|
|
12555
12619
|
});
|
|
12556
12620
|
|
|
12621
|
+
// src/sql-fragments.ts
|
|
12622
|
+
function renderWhereTerms(terms) {
|
|
12623
|
+
if (terms.length === 0)
|
|
12624
|
+
return "";
|
|
12625
|
+
const runs = [];
|
|
12626
|
+
for (const term of terms) {
|
|
12627
|
+
if (term.conn === "OR" && runs.length > 0)
|
|
12628
|
+
runs[runs.length - 1].push(term);
|
|
12629
|
+
else
|
|
12630
|
+
runs.push([term]);
|
|
12631
|
+
}
|
|
12632
|
+
return runs.map((run, i) => {
|
|
12633
|
+
const body = run.map((t) => t.sql).join(" OR ");
|
|
12634
|
+
const piece = run.length > 1 && runs.length > 1 ? `(${body})` : body;
|
|
12635
|
+
return i === 0 ? piece : `${run[0].conn} ${piece}`;
|
|
12636
|
+
}).join(" ");
|
|
12637
|
+
}
|
|
12638
|
+
function renderInPredicate(column, values, negated, placeholders) {
|
|
12639
|
+
if (values.length === 0)
|
|
12640
|
+
return negated ? TRUE_PREDICATE : FALSE_PREDICATE;
|
|
12641
|
+
return `${column} ${negated ? "NOT IN" : "IN"} (${placeholders})`;
|
|
12642
|
+
}
|
|
12643
|
+
var FALSE_PREDICATE = "1 = 0", TRUE_PREDICATE = "1 = 1";
|
|
12644
|
+
|
|
12557
12645
|
// src/client.ts
|
|
12558
12646
|
function isRawExpression(expr) {
|
|
12559
12647
|
return typeof expr === "object" && expr !== null && "raw" in expr && typeof expr.raw === "string";
|
|
@@ -12625,10 +12713,20 @@ function renderSelectColumn(col) {
|
|
|
12625
12713
|
}
|
|
12626
12714
|
throw new TypeError(`[query-builder] select(): unsupported column ${String(col)} \u2014 pass a column name, a string[], or a SQL fragment (e.g. sql\`count(*) as c\`)`);
|
|
12627
12715
|
}
|
|
12628
|
-
function
|
|
12629
|
-
|
|
12630
|
-
|
|
12631
|
-
|
|
12716
|
+
function hasTopLevelOrderBy(s) {
|
|
12717
|
+
const re = /\(|\)|\bORDER\s+BY\b/gi;
|
|
12718
|
+
let depth = 0;
|
|
12719
|
+
let m;
|
|
12720
|
+
while (m = re.exec(s)) {
|
|
12721
|
+
if (m[0] === "(") {
|
|
12722
|
+
depth++;
|
|
12723
|
+
} else if (m[0] === ")") {
|
|
12724
|
+
depth = Math.max(0, depth - 1);
|
|
12725
|
+
} else if (depth === 0) {
|
|
12726
|
+
return true;
|
|
12727
|
+
}
|
|
12728
|
+
}
|
|
12729
|
+
return false;
|
|
12632
12730
|
}
|
|
12633
12731
|
function validateIdentifier(name, context) {
|
|
12634
12732
|
if (!SQL_PATTERNS.IDENTIFIER.test(name)) {
|
|
@@ -13106,20 +13204,125 @@ function createQueryBuilder(state) {
|
|
|
13106
13204
|
function makeSelect(table, columns) {
|
|
13107
13205
|
const sql = _sql;
|
|
13108
13206
|
let text = columns && columns.length > 0 ? `SELECT ${columns.join(", ")} FROM ${String(table)}` : `SELECT * FROM ${String(table)}`;
|
|
13207
|
+
const whereTerms = [];
|
|
13208
|
+
const whereParams = [];
|
|
13209
|
+
let whereTail = false;
|
|
13109
13210
|
let built = null;
|
|
13110
13211
|
const ensureBuilt = () => {
|
|
13111
13212
|
if (built === null) {
|
|
13112
|
-
const finalText = reorderSelectClauses(
|
|
13213
|
+
const finalText = reorderSelectClauses(currentSql());
|
|
13113
13214
|
built = whereParams.length > 0 ? _sql.unsafe(finalText, whereParams) : _sql.unsafe(finalText);
|
|
13114
13215
|
}
|
|
13115
13216
|
return built;
|
|
13116
13217
|
};
|
|
13218
|
+
const pushWhere = (conn, clause) => {
|
|
13219
|
+
whereTerms.push({ conn, sql: clause });
|
|
13220
|
+
built = null;
|
|
13221
|
+
};
|
|
13117
13222
|
const addWhereText = (prefix, clause) => {
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13223
|
+
pushWhere(prefix === "OR" ? "OR" : "AND", clause);
|
|
13224
|
+
};
|
|
13225
|
+
const TAIL_CLAUSE = /\(|\)|\b(?:GROUP\s+BY|HAVING|ORDER\s+BY|LIMIT|OFFSET|WINDOW|UNION|INTERSECT|EXCEPT|FOR\s+UPDATE|FOR\s+SHARE|LOCK\s+IN\s+SHARE\s+MODE)\b/gi;
|
|
13226
|
+
const firstTailIndex = (s) => {
|
|
13227
|
+
TAIL_CLAUSE.lastIndex = 0;
|
|
13228
|
+
let depth = 0;
|
|
13229
|
+
let m;
|
|
13230
|
+
while (m = TAIL_CLAUSE.exec(s)) {
|
|
13231
|
+
if (m[0] === "(") {
|
|
13232
|
+
depth++;
|
|
13233
|
+
} else if (m[0] === ")") {
|
|
13234
|
+
depth = Math.max(0, depth - 1);
|
|
13235
|
+
} else if (depth === 0) {
|
|
13236
|
+
return m.index;
|
|
13237
|
+
}
|
|
13238
|
+
}
|
|
13239
|
+
return -1;
|
|
13240
|
+
};
|
|
13241
|
+
const currentSql = (extra) => {
|
|
13242
|
+
const body = renderWhereTerms(extra ? [...whereTerms, extra] : whereTerms);
|
|
13243
|
+
if (!body)
|
|
13244
|
+
return text;
|
|
13245
|
+
if (whereTail) {
|
|
13246
|
+
const kw = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
13247
|
+
return `${text} ${kw} ${body}`;
|
|
13248
|
+
}
|
|
13249
|
+
const cut = firstTailIndex(text);
|
|
13250
|
+
return cut >= 0 ? `${text.slice(0, cut)}WHERE ${body} ${text.slice(cut)}` : `${text} WHERE ${body}`;
|
|
13251
|
+
};
|
|
13252
|
+
const addWhereGroup = (conn, cb) => {
|
|
13253
|
+
const sub = makeSelect(table);
|
|
13254
|
+
cb(sub);
|
|
13255
|
+
const st = sub.__whereState?.();
|
|
13256
|
+
if (!st || !st.body) {
|
|
13257
|
+
throw new TypeError("[query-builder] whereGroup(callback): the callback added no conditions. " + "Add at least one where()/orWhere() to the builder it receives.");
|
|
13258
|
+
}
|
|
13259
|
+
const offset = whereParams.length;
|
|
13260
|
+
const body = offset > 0 && config5.dialect === "postgres" ? st.body.replace(/\$(\d+)/g, (_m, n) => `$${Number(n) + offset}`) : st.body;
|
|
13261
|
+
whereParams.push(...st.params);
|
|
13262
|
+
pushWhere(conn, `(${body})`);
|
|
13263
|
+
};
|
|
13264
|
+
const addBooleanWhere = (self, conn, label, expr, op, value) => {
|
|
13265
|
+
if (typeof expr === "string" && op !== undefined) {
|
|
13266
|
+
validateIdentifier(String(expr), `${label}(column)`);
|
|
13267
|
+
assertSafeWhereOperator(op, `${label}(operator)`);
|
|
13268
|
+
const paramIndex = whereParams.length + 1;
|
|
13269
|
+
whereParams.push(value);
|
|
13270
|
+
pushWhere(conn, `${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
|
|
13271
|
+
return self;
|
|
13272
|
+
}
|
|
13273
|
+
if (Array.isArray(expr)) {
|
|
13274
|
+
const [col, rawOp, val] = expr;
|
|
13275
|
+
const colName = String(col);
|
|
13276
|
+
validateIdentifier(colName, `${label}(column)`);
|
|
13277
|
+
const operator = assertSafeWhereOperator(rawOp, `${label}(operator)`);
|
|
13278
|
+
if (operator === "in" || operator === "not in") {
|
|
13279
|
+
const values = Array.isArray(val) ? val : [val];
|
|
13280
|
+
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
13281
|
+
const clause = renderInPredicate(colName, values, operator === "not in", placeholders);
|
|
13282
|
+
whereParams.push(...values);
|
|
13283
|
+
pushWhere(conn, clause);
|
|
13284
|
+
} else {
|
|
13285
|
+
const paramIndex = whereParams.length + 1;
|
|
13286
|
+
whereParams.push(val);
|
|
13287
|
+
pushWhere(conn, `${colName} ${operator} ${getPlaceholder(paramIndex)}`);
|
|
13288
|
+
}
|
|
13289
|
+
return self;
|
|
13290
|
+
}
|
|
13291
|
+
if (typeof expr === "function") {
|
|
13292
|
+
addWhereGroup(conn, expr);
|
|
13293
|
+
return self;
|
|
13294
|
+
}
|
|
13295
|
+
if (expr && typeof expr === "object" && !("raw" in expr)) {
|
|
13296
|
+
const conditions = [];
|
|
13297
|
+
for (const key of Object.keys(expr)) {
|
|
13298
|
+
validateIdentifier(key, `${label}(column)`);
|
|
13299
|
+
const v = expr[key];
|
|
13300
|
+
if (Array.isArray(v)) {
|
|
13301
|
+
const placeholders = getPlaceholders(v.length, whereParams.length + 1);
|
|
13302
|
+
conditions.push(renderInPredicate(key, v, false, placeholders));
|
|
13303
|
+
whereParams.push(...v);
|
|
13304
|
+
} else {
|
|
13305
|
+
const paramIndex = whereParams.length + 1;
|
|
13306
|
+
conditions.push(`${key} = ${getPlaceholder(paramIndex)}`);
|
|
13307
|
+
whereParams.push(v);
|
|
13308
|
+
}
|
|
13309
|
+
}
|
|
13310
|
+
if (conditions.length > 0)
|
|
13311
|
+
pushWhere(conn, conditions.length > 1 ? `(${conditions.join(" AND ")})` : conditions[0]);
|
|
13312
|
+
return self;
|
|
13313
|
+
}
|
|
13314
|
+
if (expr && typeof expr.raw !== "undefined") {
|
|
13315
|
+
pushWhere(conn, expr.raw);
|
|
13316
|
+
return self;
|
|
13317
|
+
}
|
|
13318
|
+
return self;
|
|
13121
13319
|
};
|
|
13122
13320
|
const appendSetOp = (op, other) => {
|
|
13321
|
+
if (whereTerms.length > 0) {
|
|
13322
|
+
text = currentSql();
|
|
13323
|
+
whereTerms.length = 0;
|
|
13324
|
+
}
|
|
13325
|
+
whereTail = true;
|
|
13123
13326
|
const st = other.__rawState?.();
|
|
13124
13327
|
if (st) {
|
|
13125
13328
|
const offset = whereParams.length;
|
|
@@ -13209,8 +13412,6 @@ function createQueryBuilder(state) {
|
|
|
13209
13412
|
text = `${text} LEFT JOIN ${resolved.pivotTable} ON ${resolved.pivotTable}.${resolved.fkParent} = ${parentTable}.${parentPk}`;
|
|
13210
13413
|
joinedTables.add(resolved.pivotTable);
|
|
13211
13414
|
};
|
|
13212
|
-
const whereConditions = [];
|
|
13213
|
-
const whereParams = [];
|
|
13214
13415
|
const addToSelectClause = (columnsToAdd) => {
|
|
13215
13416
|
if (SQL_PATTERNS.SELECT_STAR.test(text)) {
|
|
13216
13417
|
text = text.replace(SQL_PATTERNS.SELECT_STAR, `SELECT *, ${columnsToAdd}`);
|
|
@@ -13834,10 +14035,7 @@ function createQueryBuilder(state) {
|
|
|
13834
14035
|
} else {
|
|
13835
14036
|
throw new Error(`[query-builder] Unsupported relationship type '${type}' for whereHas`);
|
|
13836
14037
|
}
|
|
13837
|
-
|
|
13838
|
-
try {
|
|
13839
|
-
addWhereText("WHERE", `EXISTS (${subquerySQL})`);
|
|
13840
|
-
} catch {}
|
|
14038
|
+
addWhereText("WHERE", `EXISTS (${subquerySQL})`);
|
|
13841
14039
|
return this;
|
|
13842
14040
|
},
|
|
13843
14041
|
whereDoesntHave(relation, callback) {
|
|
@@ -13870,10 +14068,7 @@ function createQueryBuilder(state) {
|
|
|
13870
14068
|
} else {
|
|
13871
14069
|
throw new Error(`[query-builder] Unsupported relationship type '${type}' for whereDoesntHave`);
|
|
13872
14070
|
}
|
|
13873
|
-
|
|
13874
|
-
try {
|
|
13875
|
-
addWhereText("WHERE", `NOT EXISTS (${subquerySQL})`);
|
|
13876
|
-
} catch {}
|
|
14071
|
+
addWhereText("WHERE", `NOT EXISTS (${subquerySQL})`);
|
|
13877
14072
|
return this;
|
|
13878
14073
|
},
|
|
13879
14074
|
has(relation) {
|
|
@@ -13904,10 +14099,7 @@ function createQueryBuilder(state) {
|
|
|
13904
14099
|
} else {
|
|
13905
14100
|
throw new Error(`[query-builder] Unsupported relationship type '${type}' for has`);
|
|
13906
14101
|
}
|
|
13907
|
-
|
|
13908
|
-
try {
|
|
13909
|
-
addWhereText("WHERE", `EXISTS (${subquerySQL})`);
|
|
13910
|
-
} catch {}
|
|
14102
|
+
addWhereText("WHERE", `EXISTS (${subquerySQL})`);
|
|
13911
14103
|
return this;
|
|
13912
14104
|
},
|
|
13913
14105
|
doesntHave(relation) {
|
|
@@ -13938,10 +14130,7 @@ function createQueryBuilder(state) {
|
|
|
13938
14130
|
} else {
|
|
13939
14131
|
throw new Error(`[query-builder] Unsupported relationship type '${type}' for doesntHave`);
|
|
13940
14132
|
}
|
|
13941
|
-
|
|
13942
|
-
try {
|
|
13943
|
-
addWhereText("WHERE", `NOT EXISTS (${subquerySQL})`);
|
|
13944
|
-
} catch {}
|
|
14133
|
+
addWhereText("WHERE", `NOT EXISTS (${subquerySQL})`);
|
|
13945
14134
|
return this;
|
|
13946
14135
|
},
|
|
13947
14136
|
withCount(...relations) {
|
|
@@ -14024,17 +14213,14 @@ function createQueryBuilder(state) {
|
|
|
14024
14213
|
const val = value === undefined ? opOrValue : value;
|
|
14025
14214
|
const paramIndex = whereParams.length + 1;
|
|
14026
14215
|
const clause = `${resolved.pivotTable}.${column} ${op} ${getPlaceholder(paramIndex)}`;
|
|
14027
|
-
whereConditions.push(clause);
|
|
14028
14216
|
whereParams.push(val);
|
|
14029
|
-
|
|
14030
|
-
text = `${text} ${kw} ${clause}`;
|
|
14031
|
-
built = null;
|
|
14217
|
+
pushWhere("AND", clause);
|
|
14032
14218
|
if (resolved.hasConfig)
|
|
14033
14219
|
pivotConfigRelations.add(relation);
|
|
14034
14220
|
return this;
|
|
14035
14221
|
},
|
|
14036
14222
|
wherePivotIn(relation, column, values) {
|
|
14037
|
-
if (!meta || !Array.isArray(values)
|
|
14223
|
+
if (!meta || !Array.isArray(values))
|
|
14038
14224
|
return this;
|
|
14039
14225
|
const resolved = resolvePivotLocal(relation);
|
|
14040
14226
|
if (!resolved) {
|
|
@@ -14044,12 +14230,9 @@ function createQueryBuilder(state) {
|
|
|
14044
14230
|
validateIdentifier(column, "wherePivotIn (column)");
|
|
14045
14231
|
ensurePivotJoined(resolved);
|
|
14046
14232
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14047
|
-
const clause = `${resolved.pivotTable}.${column}
|
|
14048
|
-
whereConditions.push(clause);
|
|
14233
|
+
const clause = renderInPredicate(`${resolved.pivotTable}.${column}`, values, false, placeholders);
|
|
14049
14234
|
whereParams.push(...values);
|
|
14050
|
-
|
|
14051
|
-
text = `${text} ${kw} ${clause}`;
|
|
14052
|
-
built = null;
|
|
14235
|
+
pushWhere("AND", clause);
|
|
14053
14236
|
if (resolved.hasConfig)
|
|
14054
14237
|
pivotConfigRelations.add(relation);
|
|
14055
14238
|
return this;
|
|
@@ -14066,11 +14249,8 @@ function createQueryBuilder(state) {
|
|
|
14066
14249
|
ensurePivotJoined(resolved);
|
|
14067
14250
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14068
14251
|
const clause = `${resolved.pivotTable}.${column} NOT IN (${placeholders})`;
|
|
14069
|
-
whereConditions.push(clause);
|
|
14070
14252
|
whereParams.push(...values);
|
|
14071
|
-
|
|
14072
|
-
text = `${text} ${kw} ${clause}`;
|
|
14073
|
-
built = null;
|
|
14253
|
+
pushWhere("AND", clause);
|
|
14074
14254
|
if (resolved.hasConfig)
|
|
14075
14255
|
pivotConfigRelations.add(relation);
|
|
14076
14256
|
return this;
|
|
@@ -14085,11 +14265,7 @@ function createQueryBuilder(state) {
|
|
|
14085
14265
|
validateIdentifier(resolved.pivotTable, "wherePivotNull (pivot table)");
|
|
14086
14266
|
validateIdentifier(column, "wherePivotNull (column)");
|
|
14087
14267
|
ensurePivotJoined(resolved);
|
|
14088
|
-
|
|
14089
|
-
whereConditions.push(clause);
|
|
14090
|
-
const kw = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14091
|
-
text = `${text} ${kw} ${clause}`;
|
|
14092
|
-
built = null;
|
|
14268
|
+
pushWhere("AND", `${resolved.pivotTable}.${column} IS NULL`);
|
|
14093
14269
|
if (resolved.hasConfig)
|
|
14094
14270
|
pivotConfigRelations.add(relation);
|
|
14095
14271
|
return this;
|
|
@@ -14104,17 +14280,12 @@ function createQueryBuilder(state) {
|
|
|
14104
14280
|
validateIdentifier(resolved.pivotTable, "wherePivotNotNull (pivot table)");
|
|
14105
14281
|
validateIdentifier(column, "wherePivotNotNull (column)");
|
|
14106
14282
|
ensurePivotJoined(resolved);
|
|
14107
|
-
|
|
14108
|
-
whereConditions.push(clause);
|
|
14109
|
-
const kw = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14110
|
-
text = `${text} ${kw} ${clause}`;
|
|
14111
|
-
built = null;
|
|
14283
|
+
pushWhere("AND", `${resolved.pivotTable}.${column} IS NOT NULL`);
|
|
14112
14284
|
if (resolved.hasConfig)
|
|
14113
14285
|
pivotConfigRelations.add(relation);
|
|
14114
14286
|
return this;
|
|
14115
14287
|
},
|
|
14116
14288
|
where(expr, op, value) {
|
|
14117
|
-
const getWhereKeyword = () => SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14118
14289
|
if (typeof expr === "string" && op !== undefined) {
|
|
14119
14290
|
validateIdentifier(String(expr), "where(column)");
|
|
14120
14291
|
assertSafeWhereOperator(op, "where(operator)");
|
|
@@ -14122,18 +14293,14 @@ function createQueryBuilder(state) {
|
|
|
14122
14293
|
if (operator === "in" || operator === "not in") {
|
|
14123
14294
|
const values = Array.isArray(value) ? value : [value];
|
|
14124
14295
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14125
|
-
const clause =
|
|
14126
|
-
whereConditions.push(clause);
|
|
14296
|
+
const clause = renderInPredicate(String(expr), values, operator === "not in", placeholders);
|
|
14127
14297
|
whereParams.push(...values);
|
|
14128
|
-
|
|
14129
|
-
built = null;
|
|
14298
|
+
pushWhere("AND", clause);
|
|
14130
14299
|
return this;
|
|
14131
14300
|
}
|
|
14132
14301
|
const paramIndex = whereParams.length + 1;
|
|
14133
|
-
whereConditions.push(`${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
|
|
14134
14302
|
whereParams.push(value);
|
|
14135
|
-
|
|
14136
|
-
built = null;
|
|
14303
|
+
pushWhere("AND", `${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
|
|
14137
14304
|
return this;
|
|
14138
14305
|
}
|
|
14139
14306
|
if (Array.isArray(expr)) {
|
|
@@ -14144,16 +14311,13 @@ function createQueryBuilder(state) {
|
|
|
14144
14311
|
if (operator === "in" || operator === "not in") {
|
|
14145
14312
|
const values = Array.isArray(val) ? val : [val];
|
|
14146
14313
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14147
|
-
|
|
14314
|
+
const clause = renderInPredicate(colName, values, operator === "not in", placeholders);
|
|
14148
14315
|
whereParams.push(...values);
|
|
14149
|
-
|
|
14150
|
-
built = null;
|
|
14316
|
+
pushWhere("AND", clause);
|
|
14151
14317
|
} else {
|
|
14152
14318
|
const paramIndex = whereParams.length + 1;
|
|
14153
|
-
whereConditions.push(`${colName} ${operator} ${getPlaceholder(paramIndex)}`);
|
|
14154
14319
|
whereParams.push(val);
|
|
14155
|
-
|
|
14156
|
-
built = null;
|
|
14320
|
+
pushWhere("AND", `${colName} ${operator} ${getPlaceholder(paramIndex)}`);
|
|
14157
14321
|
}
|
|
14158
14322
|
return this;
|
|
14159
14323
|
}
|
|
@@ -14166,30 +14330,25 @@ function createQueryBuilder(state) {
|
|
|
14166
14330
|
const value2 = whereObject[key];
|
|
14167
14331
|
if (Array.isArray(value2)) {
|
|
14168
14332
|
const placeholders = getPlaceholders(value2.length, whereParams.length + 1);
|
|
14169
|
-
conditions.push(
|
|
14170
|
-
whereConditions.push(`${key} IN (${placeholders})`);
|
|
14333
|
+
conditions.push(renderInPredicate(key, value2, false, placeholders));
|
|
14171
14334
|
whereParams.push(...value2);
|
|
14172
14335
|
} else {
|
|
14173
14336
|
const paramIndex = whereParams.length + 1;
|
|
14174
14337
|
conditions.push(`${key} = ${getPlaceholder(paramIndex)}`);
|
|
14175
|
-
whereConditions.push(`${key} = ${getPlaceholder(paramIndex)}`);
|
|
14176
14338
|
whereParams.push(value2);
|
|
14177
14339
|
}
|
|
14178
14340
|
}
|
|
14179
|
-
if (conditions.length > 0)
|
|
14180
|
-
|
|
14181
|
-
built = null;
|
|
14182
|
-
}
|
|
14341
|
+
if (conditions.length > 0)
|
|
14342
|
+
pushWhere("AND", conditions.length > 1 ? `(${conditions.join(" AND ")})` : conditions[0]);
|
|
14183
14343
|
return this;
|
|
14184
14344
|
}
|
|
14185
14345
|
if (isRawExpression(expr)) {
|
|
14186
|
-
|
|
14187
|
-
text = `${text} ${getWhereKeyword()} ${expr.raw}`;
|
|
14188
|
-
built = null;
|
|
14346
|
+
pushWhere("AND", expr.raw);
|
|
14189
14347
|
return this;
|
|
14190
14348
|
}
|
|
14191
14349
|
if (typeof expr === "function") {
|
|
14192
|
-
|
|
14350
|
+
addWhereGroup("AND", expr);
|
|
14351
|
+
return this;
|
|
14193
14352
|
}
|
|
14194
14353
|
if (expr === undefined || expr === null) {
|
|
14195
14354
|
throw new TypeError("where() was called with no condition.");
|
|
@@ -14201,61 +14360,83 @@ function createQueryBuilder(state) {
|
|
|
14201
14360
|
},
|
|
14202
14361
|
whereNull(column) {
|
|
14203
14362
|
validateIdentifier(String(column), "whereNull(column)");
|
|
14204
|
-
|
|
14205
|
-
text = `${text} ${keyword} ${String(column)} IS NULL`;
|
|
14206
|
-
built = null;
|
|
14363
|
+
pushWhere("AND", `${String(column)} IS NULL`);
|
|
14207
14364
|
return this;
|
|
14208
14365
|
},
|
|
14209
14366
|
whereNotNull(column) {
|
|
14210
14367
|
validateIdentifier(String(column), "whereNotNull(column)");
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14368
|
+
pushWhere("AND", `${String(column)} IS NOT NULL`);
|
|
14369
|
+
return this;
|
|
14370
|
+
},
|
|
14371
|
+
orWhereNull(column) {
|
|
14372
|
+
validateIdentifier(String(column), "orWhereNull(column)");
|
|
14373
|
+
pushWhere("OR", `${String(column)} IS NULL`);
|
|
14374
|
+
return this;
|
|
14375
|
+
},
|
|
14376
|
+
orWhereNotNull(column) {
|
|
14377
|
+
validateIdentifier(String(column), "orWhereNotNull(column)");
|
|
14378
|
+
pushWhere("OR", `${String(column)} IS NOT NULL`);
|
|
14214
14379
|
return this;
|
|
14215
14380
|
},
|
|
14216
14381
|
whereBetween(column, start, end) {
|
|
14217
14382
|
validateIdentifier(String(column), "whereBetween(column)");
|
|
14218
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14219
14383
|
const i = whereParams.length + 1;
|
|
14220
|
-
text = `${text} ${keyword} ${String(column)} BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`;
|
|
14221
14384
|
whereParams.push(start, end);
|
|
14222
|
-
|
|
14385
|
+
pushWhere("AND", `${String(column)} BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`);
|
|
14386
|
+
return this;
|
|
14387
|
+
},
|
|
14388
|
+
orWhereBetween(column, start, end) {
|
|
14389
|
+
validateIdentifier(String(column), "orWhereBetween(column)");
|
|
14390
|
+
const i = whereParams.length + 1;
|
|
14391
|
+
whereParams.push(start, end);
|
|
14392
|
+
pushWhere("OR", `${String(column)} BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`);
|
|
14223
14393
|
return this;
|
|
14224
14394
|
},
|
|
14225
14395
|
whereExists(subquery) {
|
|
14226
|
-
|
|
14227
|
-
text = `${text} ${keyword} EXISTS (${subquery.toSQL()})`;
|
|
14228
|
-
built = null;
|
|
14396
|
+
pushWhere("AND", `EXISTS (${subquery.toSQL()})`);
|
|
14229
14397
|
return this;
|
|
14230
14398
|
},
|
|
14399
|
+
orWhereExists(subquery) {
|
|
14400
|
+
pushWhere("OR", `EXISTS (${subquery.toSQL()})`);
|
|
14401
|
+
return this;
|
|
14402
|
+
},
|
|
14403
|
+
whereGroup(cb) {
|
|
14404
|
+
addWhereGroup("AND", cb);
|
|
14405
|
+
return this;
|
|
14406
|
+
},
|
|
14407
|
+
orWhereGroup(cb) {
|
|
14408
|
+
addWhereGroup("OR", cb);
|
|
14409
|
+
return this;
|
|
14410
|
+
},
|
|
14411
|
+
__whereState() {
|
|
14412
|
+
return { body: renderWhereTerms(whereTerms), params: [...whereParams] };
|
|
14413
|
+
},
|
|
14231
14414
|
whereJsonContains(column, json) {
|
|
14232
14415
|
validateIdentifier(String(column), "whereJsonContains(column)");
|
|
14233
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14234
14416
|
const dialect = config5.dialect;
|
|
14235
14417
|
const idx = whereParams.length + 1;
|
|
14236
14418
|
if (dialect === "postgres") {
|
|
14237
14419
|
if (config5.sql?.jsonContainsMode === "function")
|
|
14238
|
-
|
|
14420
|
+
pushWhere("AND", `jsonb_contains(${column}, ${getPlaceholder(idx)})`);
|
|
14239
14421
|
else
|
|
14240
|
-
|
|
14422
|
+
pushWhere("AND", `${column} @> ${getPlaceholder(idx)}`);
|
|
14241
14423
|
whereParams.push(JSON.stringify(json));
|
|
14242
14424
|
} else if (isMysqlLike(dialect)) {
|
|
14243
|
-
|
|
14425
|
+
pushWhere("AND", `JSON_CONTAINS(${column}, ${getPlaceholder(idx)})`);
|
|
14244
14426
|
whereParams.push(JSON.stringify(json));
|
|
14245
14427
|
} else {
|
|
14246
14428
|
if (Array.isArray(json)) {
|
|
14247
14429
|
const conds = json.map((_, i) => `EXISTS (SELECT 1 FROM json_each(${column}) WHERE json_each.value = ${getPlaceholder(idx + i)})`);
|
|
14248
|
-
|
|
14430
|
+
pushWhere("AND", `(${conds.join(" AND ")})`);
|
|
14249
14431
|
for (const v of json)
|
|
14250
14432
|
whereParams.push(v);
|
|
14251
14433
|
} else if (json !== null && typeof json === "object") {
|
|
14252
14434
|
throw new Error("[query-builder] whereJsonContains: object containment is not supported on SQLite \u2014 pass a scalar or array, or use whereJsonPath.");
|
|
14253
14435
|
} else {
|
|
14254
|
-
|
|
14436
|
+
pushWhere("AND", `EXISTS (SELECT 1 FROM json_each(${column}) WHERE json_each.value = ${getPlaceholder(idx)})`);
|
|
14255
14437
|
whereParams.push(json);
|
|
14256
14438
|
}
|
|
14257
14439
|
}
|
|
14258
|
-
built = null;
|
|
14259
14440
|
return this;
|
|
14260
14441
|
},
|
|
14261
14442
|
whereJsonPath(path, op, value) {
|
|
@@ -14265,17 +14446,14 @@ function createQueryBuilder(state) {
|
|
|
14265
14446
|
if (!/^[A-Za-z0-9_.[\]$'\->* ,]+$/.test(path))
|
|
14266
14447
|
throw new TypeError(`[query-builder] whereJsonPath(path): refusing to use '${path}' \u2014 contains characters outside the allowed JSON-path set`);
|
|
14267
14448
|
const dialect = config5.dialect;
|
|
14268
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14269
14449
|
const idx = whereParams.length + 1;
|
|
14270
|
-
if (dialect === "postgres")
|
|
14271
|
-
|
|
14272
|
-
|
|
14273
|
-
|
|
14274
|
-
|
|
14275
|
-
|
|
14276
|
-
}
|
|
14450
|
+
if (dialect === "postgres")
|
|
14451
|
+
pushWhere("AND", `${path} ${op} ${getPlaceholder(idx)}`);
|
|
14452
|
+
else if (isMysqlLike(dialect))
|
|
14453
|
+
pushWhere("AND", `JSON_EXTRACT(${path}) ${op} ${getPlaceholder(idx)}`);
|
|
14454
|
+
else
|
|
14455
|
+
pushWhere("AND", `json_extract(${path}) ${op} ${getPlaceholder(idx)}`);
|
|
14277
14456
|
whereParams.push(value);
|
|
14278
|
-
built = null;
|
|
14279
14457
|
return this;
|
|
14280
14458
|
},
|
|
14281
14459
|
whereLike(column, pattern, caseSensitive = false) {
|
|
@@ -14348,51 +14526,41 @@ function createQueryBuilder(state) {
|
|
|
14348
14526
|
},
|
|
14349
14527
|
whereAny(cols, op, value) {
|
|
14350
14528
|
if (cols.length === 0) {
|
|
14351
|
-
|
|
14352
|
-
text += ` ${kw} (${FALSE_PREDICATE})`;
|
|
14353
|
-
built = null;
|
|
14529
|
+
pushWhere("AND", `(${FALSE_PREDICATE})`);
|
|
14354
14530
|
return this;
|
|
14355
14531
|
}
|
|
14356
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14357
14532
|
const idx = whereParams.length + 1;
|
|
14358
14533
|
const conds = cols.map((c, i) => `${c} ${op} ${getPlaceholder(idx + i)}`);
|
|
14359
|
-
text += ` ${keyword} (${conds.join(" OR ")})`;
|
|
14360
14534
|
for (let i = 0;i < cols.length; i++)
|
|
14361
14535
|
whereParams.push(value);
|
|
14362
|
-
|
|
14536
|
+
pushWhere("AND", `(${conds.join(" OR ")})`);
|
|
14363
14537
|
return this;
|
|
14364
14538
|
},
|
|
14365
14539
|
whereAll(cols, op, value) {
|
|
14366
14540
|
if (cols.length === 0)
|
|
14367
14541
|
return this;
|
|
14368
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14369
14542
|
const idx = whereParams.length + 1;
|
|
14370
14543
|
const conds = cols.map((c, i) => `${c} ${op} ${getPlaceholder(idx + i)}`);
|
|
14371
|
-
text += ` ${keyword} (${conds.join(" AND ")})`;
|
|
14372
14544
|
for (let i = 0;i < cols.length; i++)
|
|
14373
14545
|
whereParams.push(value);
|
|
14374
|
-
|
|
14546
|
+
pushWhere("AND", `(${conds.join(" AND ")})`);
|
|
14375
14547
|
return this;
|
|
14376
14548
|
},
|
|
14377
14549
|
whereNone(cols, op, value) {
|
|
14378
14550
|
if (cols.length === 0)
|
|
14379
14551
|
return this;
|
|
14380
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14381
14552
|
const idx = whereParams.length + 1;
|
|
14382
14553
|
const conds = cols.map((c, i) => `${c} ${op} ${getPlaceholder(idx + i)}`);
|
|
14383
|
-
text += ` ${keyword} NOT (${conds.join(" OR ")})`;
|
|
14384
14554
|
for (let i = 0;i < cols.length; i++)
|
|
14385
14555
|
whereParams.push(value);
|
|
14386
|
-
|
|
14556
|
+
pushWhere("AND", `NOT (${conds.join(" OR ")})`);
|
|
14387
14557
|
return this;
|
|
14388
14558
|
},
|
|
14389
14559
|
whereNotBetween(column, start, end) {
|
|
14390
14560
|
validateIdentifier(String(column), "whereNotBetween(column)");
|
|
14391
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14392
14561
|
const i = whereParams.length + 1;
|
|
14393
|
-
text += ` ${keyword} ${column} NOT BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`;
|
|
14394
14562
|
whereParams.push(start, end);
|
|
14395
|
-
|
|
14563
|
+
pushWhere("AND", `${column} NOT BETWEEN ${getPlaceholder(i)} AND ${getPlaceholder(i + 1)}`);
|
|
14396
14564
|
return this;
|
|
14397
14565
|
},
|
|
14398
14566
|
whereDate(column, op, date) {
|
|
@@ -14400,223 +14568,94 @@ function createQueryBuilder(state) {
|
|
|
14400
14568
|
const dateString = date instanceof Date ? date.toISOString() : typeof date === "string" ? date : (() => {
|
|
14401
14569
|
throw new TypeError(`[query-builder] whereDate(date): expected string or Date, got ${typeof date}`);
|
|
14402
14570
|
})();
|
|
14403
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14404
14571
|
const idx = whereParams.length + 1;
|
|
14405
|
-
text += ` ${keyword} ${column} ${op} ${getPlaceholder(idx)}`;
|
|
14406
14572
|
whereParams.push(dateString);
|
|
14407
|
-
|
|
14573
|
+
pushWhere("AND", `${column} ${op} ${getPlaceholder(idx)}`);
|
|
14408
14574
|
return this;
|
|
14409
14575
|
},
|
|
14410
14576
|
whereRaw(fragment) {
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14577
|
+
pushWhere("AND", renderRawFragment(fragment, "whereRaw(fragment)"));
|
|
14578
|
+
return this;
|
|
14579
|
+
},
|
|
14580
|
+
orWhereRaw(fragment) {
|
|
14581
|
+
pushWhere("OR", renderRawFragment(fragment, "orWhereRaw(fragment)"));
|
|
14415
14582
|
return this;
|
|
14416
14583
|
},
|
|
14417
14584
|
whereColumn(left, op, right) {
|
|
14418
14585
|
validateIdentifier(left, "whereColumn(left)");
|
|
14419
14586
|
validateIdentifier(right, "whereColumn(right)");
|
|
14420
|
-
|
|
14421
|
-
text += ` ${keyword} ${left} ${op} ${right}`;
|
|
14422
|
-
built = null;
|
|
14587
|
+
pushWhere("AND", `${left} ${op} ${right}`);
|
|
14423
14588
|
return this;
|
|
14424
14589
|
},
|
|
14425
14590
|
orWhereColumn(left, op, right) {
|
|
14426
14591
|
validateIdentifier(left, "orWhereColumn(left)");
|
|
14427
14592
|
validateIdentifier(right, "orWhereColumn(right)");
|
|
14428
|
-
|
|
14429
|
-
built = null;
|
|
14593
|
+
pushWhere("OR", `${left} ${op} ${right}`);
|
|
14430
14594
|
return this;
|
|
14431
14595
|
},
|
|
14432
14596
|
whereIn(column, values) {
|
|
14433
14597
|
validateIdentifier(String(column), "whereIn(column)");
|
|
14434
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14435
14598
|
if (Array.isArray(values)) {
|
|
14436
14599
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14437
|
-
|
|
14600
|
+
const clause = renderInPredicate(column, values, false, placeholders);
|
|
14438
14601
|
whereParams.push(...values);
|
|
14602
|
+
pushWhere("AND", clause);
|
|
14439
14603
|
} else {
|
|
14440
|
-
|
|
14604
|
+
pushWhere("AND", `${column} IN (${String(values.toSQL())})`);
|
|
14441
14605
|
}
|
|
14442
|
-
built = null;
|
|
14443
14606
|
return this;
|
|
14444
14607
|
},
|
|
14445
14608
|
orWhereIn(column, values) {
|
|
14446
14609
|
validateIdentifier(String(column), "orWhereIn(column)");
|
|
14447
14610
|
if (Array.isArray(values)) {
|
|
14448
14611
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14449
|
-
|
|
14612
|
+
const clause = renderInPredicate(column, values, false, placeholders);
|
|
14450
14613
|
whereParams.push(...values);
|
|
14614
|
+
pushWhere("OR", clause);
|
|
14451
14615
|
} else {
|
|
14452
|
-
|
|
14616
|
+
pushWhere("OR", `${column} IN (${String(values.toSQL())})`);
|
|
14453
14617
|
}
|
|
14454
|
-
built = null;
|
|
14455
14618
|
return this;
|
|
14456
14619
|
},
|
|
14457
14620
|
whereNotIn(column, values) {
|
|
14458
14621
|
validateIdentifier(String(column), "whereNotIn(column)");
|
|
14459
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14460
14622
|
if (Array.isArray(values)) {
|
|
14461
14623
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14462
|
-
|
|
14624
|
+
const clause = renderInPredicate(column, values, true, placeholders);
|
|
14463
14625
|
whereParams.push(...values);
|
|
14626
|
+
pushWhere("AND", clause);
|
|
14464
14627
|
} else {
|
|
14465
|
-
|
|
14628
|
+
pushWhere("AND", `${column} NOT IN (${String(values.toSQL())})`);
|
|
14466
14629
|
}
|
|
14467
|
-
built = null;
|
|
14468
14630
|
return this;
|
|
14469
14631
|
},
|
|
14470
14632
|
orWhereNotIn(column, values) {
|
|
14471
14633
|
validateIdentifier(String(column), "orWhereNotIn(column)");
|
|
14472
14634
|
if (Array.isArray(values)) {
|
|
14473
14635
|
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14474
|
-
|
|
14636
|
+
const clause = renderInPredicate(column, values, true, placeholders);
|
|
14475
14637
|
whereParams.push(...values);
|
|
14638
|
+
pushWhere("OR", clause);
|
|
14476
14639
|
} else {
|
|
14477
|
-
|
|
14640
|
+
pushWhere("OR", `${column} NOT IN (${String(values.toSQL())})`);
|
|
14478
14641
|
}
|
|
14479
|
-
built = null;
|
|
14480
14642
|
return this;
|
|
14481
14643
|
},
|
|
14482
14644
|
whereNested(fragment) {
|
|
14483
|
-
const keyword = SQL_PATTERNS.WHERE.test(text) ? "AND" : "WHERE";
|
|
14484
14645
|
const inner = fragment.toSQL ? String(fragment.toSQL()) : String(fragment);
|
|
14485
|
-
|
|
14486
|
-
built = null;
|
|
14646
|
+
pushWhere("AND", `(${inner})`);
|
|
14487
14647
|
return this;
|
|
14488
14648
|
},
|
|
14489
14649
|
orWhereNested(fragment) {
|
|
14490
14650
|
const inner = fragment.toSQL ? String(fragment.toSQL()) : String(fragment);
|
|
14491
|
-
|
|
14492
|
-
built = null;
|
|
14651
|
+
pushWhere("OR", `(${inner})`);
|
|
14493
14652
|
return this;
|
|
14494
14653
|
},
|
|
14495
14654
|
andWhere(expr, op, value) {
|
|
14496
|
-
|
|
14497
|
-
validateIdentifier(String(expr), "andWhere(column)");
|
|
14498
|
-
assertSafeWhereOperator(op, "andWhere(operator)");
|
|
14499
|
-
const paramIndex = whereParams.length + 1;
|
|
14500
|
-
whereConditions.push(`${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
|
|
14501
|
-
whereParams.push(value);
|
|
14502
|
-
text = `${text} AND ${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`;
|
|
14503
|
-
built = null;
|
|
14504
|
-
return this;
|
|
14505
|
-
}
|
|
14506
|
-
if (Array.isArray(expr)) {
|
|
14507
|
-
const [col, op2, val] = expr;
|
|
14508
|
-
const colName = String(col);
|
|
14509
|
-
validateIdentifier(colName, "andWhere(column)");
|
|
14510
|
-
const operator = assertSafeWhereOperator(op2, "andWhere(operator)");
|
|
14511
|
-
if (operator === "in" || operator === "not in") {
|
|
14512
|
-
const values = Array.isArray(val) ? val : [val];
|
|
14513
|
-
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14514
|
-
whereConditions.push(`${colName} ${operator.toUpperCase()} (${placeholders})`);
|
|
14515
|
-
whereParams.push(...values);
|
|
14516
|
-
text = `${text} AND ${colName} ${operator.toUpperCase()} (${placeholders})`;
|
|
14517
|
-
built = null;
|
|
14518
|
-
} else {
|
|
14519
|
-
const paramIndex = whereParams.length + 1;
|
|
14520
|
-
whereConditions.push(`${colName} ${operator} ${getPlaceholder(paramIndex)}`);
|
|
14521
|
-
whereParams.push(val);
|
|
14522
|
-
text = `${text} AND ${colName} ${operator} ${getPlaceholder(paramIndex)}`;
|
|
14523
|
-
built = null;
|
|
14524
|
-
}
|
|
14525
|
-
return this;
|
|
14526
|
-
}
|
|
14527
|
-
if (expr && typeof expr === "object" && !("raw" in expr)) {
|
|
14528
|
-
const keys = Object.keys(expr);
|
|
14529
|
-
const conditions = [];
|
|
14530
|
-
for (const key of keys) {
|
|
14531
|
-
const value2 = expr[key];
|
|
14532
|
-
if (Array.isArray(value2)) {
|
|
14533
|
-
const placeholders = getPlaceholders(value2.length, whereParams.length + 1);
|
|
14534
|
-
conditions.push(`${key} IN (${placeholders})`);
|
|
14535
|
-
whereConditions.push(`${key} IN (${placeholders})`);
|
|
14536
|
-
whereParams.push(...value2);
|
|
14537
|
-
} else {
|
|
14538
|
-
const paramIndex = whereParams.length + 1;
|
|
14539
|
-
conditions.push(`${key} = ${getPlaceholder(paramIndex)}`);
|
|
14540
|
-
whereConditions.push(`${key} = ${getPlaceholder(paramIndex)}`);
|
|
14541
|
-
whereParams.push(value2);
|
|
14542
|
-
}
|
|
14543
|
-
}
|
|
14544
|
-
if (conditions.length > 0) {
|
|
14545
|
-
text = `${text} AND ${conditions.join(" AND ")}`;
|
|
14546
|
-
built = null;
|
|
14547
|
-
}
|
|
14548
|
-
return this;
|
|
14549
|
-
}
|
|
14550
|
-
if (expr && typeof expr.raw !== "undefined") {
|
|
14551
|
-
whereConditions.push(expr.raw);
|
|
14552
|
-
text = `${text} AND ${expr.raw}`;
|
|
14553
|
-
built = null;
|
|
14554
|
-
return this;
|
|
14555
|
-
}
|
|
14556
|
-
return this;
|
|
14655
|
+
return addBooleanWhere(this, "AND", "andWhere", expr, op, value);
|
|
14557
14656
|
},
|
|
14558
14657
|
orWhere(expr, op, value) {
|
|
14559
|
-
|
|
14560
|
-
validateIdentifier(String(expr), "orWhere(column)");
|
|
14561
|
-
assertSafeWhereOperator(op, "orWhere(operator)");
|
|
14562
|
-
const paramIndex = whereParams.length + 1;
|
|
14563
|
-
whereConditions.push(`OR ${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`);
|
|
14564
|
-
whereParams.push(value);
|
|
14565
|
-
text = `${text} OR ${String(expr)} ${String(op)} ${getPlaceholder(paramIndex)}`;
|
|
14566
|
-
built = null;
|
|
14567
|
-
return this;
|
|
14568
|
-
}
|
|
14569
|
-
if (Array.isArray(expr)) {
|
|
14570
|
-
const [col, op2, val] = expr;
|
|
14571
|
-
const colName = String(col);
|
|
14572
|
-
validateIdentifier(colName, "orWhere(column)");
|
|
14573
|
-
const operator = assertSafeWhereOperator(op2, "orWhere(operator)");
|
|
14574
|
-
if (operator === "in" || operator === "not in") {
|
|
14575
|
-
const values = Array.isArray(val) ? val : [val];
|
|
14576
|
-
const placeholders = getPlaceholders(values.length, whereParams.length + 1);
|
|
14577
|
-
whereConditions.push(`OR ${colName} ${operator.toUpperCase()} (${placeholders})`);
|
|
14578
|
-
whereParams.push(...values);
|
|
14579
|
-
text = `${text} OR ${colName} ${operator.toUpperCase()} (${placeholders})`;
|
|
14580
|
-
built = null;
|
|
14581
|
-
} else {
|
|
14582
|
-
const paramIndex = whereParams.length + 1;
|
|
14583
|
-
whereConditions.push(`OR ${colName} ${operator} ${getPlaceholder(paramIndex)}`);
|
|
14584
|
-
whereParams.push(val);
|
|
14585
|
-
text = `${text} OR ${colName} ${operator} ${getPlaceholder(paramIndex)}`;
|
|
14586
|
-
built = null;
|
|
14587
|
-
}
|
|
14588
|
-
return this;
|
|
14589
|
-
}
|
|
14590
|
-
if (expr && typeof expr === "object" && !("raw" in expr)) {
|
|
14591
|
-
const keys = Object.keys(expr);
|
|
14592
|
-
const conditions = [];
|
|
14593
|
-
for (const key of keys) {
|
|
14594
|
-
const value2 = expr[key];
|
|
14595
|
-
if (Array.isArray(value2)) {
|
|
14596
|
-
const placeholders = getPlaceholders(value2.length, whereParams.length + 1);
|
|
14597
|
-
conditions.push(`${key} IN (${placeholders})`);
|
|
14598
|
-
whereConditions.push(`OR ${key} IN (${placeholders})`);
|
|
14599
|
-
whereParams.push(...value2);
|
|
14600
|
-
} else {
|
|
14601
|
-
const paramIndex = whereParams.length + 1;
|
|
14602
|
-
conditions.push(`${key} = ${getPlaceholder(paramIndex)}`);
|
|
14603
|
-
whereConditions.push(`OR ${key} = ${getPlaceholder(paramIndex)}`);
|
|
14604
|
-
whereParams.push(value2);
|
|
14605
|
-
}
|
|
14606
|
-
}
|
|
14607
|
-
if (conditions.length > 0) {
|
|
14608
|
-
text = `${text} OR ${conditions.join(" AND ")}`;
|
|
14609
|
-
built = null;
|
|
14610
|
-
}
|
|
14611
|
-
return this;
|
|
14612
|
-
}
|
|
14613
|
-
if (expr && typeof expr.raw !== "undefined") {
|
|
14614
|
-
whereConditions.push(`OR ${expr.raw}`);
|
|
14615
|
-
text = `${text} OR ${expr.raw}`;
|
|
14616
|
-
built = null;
|
|
14617
|
-
return this;
|
|
14618
|
-
}
|
|
14619
|
-
return this;
|
|
14658
|
+
return addBooleanWhere(this, "OR", "orWhere", expr, op, value);
|
|
14620
14659
|
},
|
|
14621
14660
|
orderBy(column, direction = "asc") {
|
|
14622
14661
|
const dir = direction === "asc" ? "ASC" : "DESC";
|
|
@@ -14853,7 +14892,7 @@ function createQueryBuilder(state) {
|
|
|
14853
14892
|
return this;
|
|
14854
14893
|
},
|
|
14855
14894
|
toSQL() {
|
|
14856
|
-
const sqlText = reorderSelectClauses(
|
|
14895
|
+
const sqlText = reorderSelectClauses(currentSql());
|
|
14857
14896
|
return {
|
|
14858
14897
|
sql: sqlText,
|
|
14859
14898
|
toString: () => sqlText,
|
|
@@ -14899,7 +14938,7 @@ function createQueryBuilder(state) {
|
|
|
14899
14938
|
if (!Number.isFinite(page) || page < 1 || !Number.isInteger(page))
|
|
14900
14939
|
throw new TypeError(`[query-builder] paginate(page): expected integer >= 1, got ${page}`);
|
|
14901
14940
|
if (opts.tx) {
|
|
14902
|
-
const baseSql = reorderSelectClauses(
|
|
14941
|
+
const baseSql = reorderSelectClauses(currentSql());
|
|
14903
14942
|
const baseParams = [...whereParams];
|
|
14904
14943
|
const cRows2 = await opts.tx.unsafe(`SELECT COUNT(*) as c FROM (${baseSql}) as sub`, baseParams);
|
|
14905
14944
|
const total2 = Number(cRows2?.[0]?.c ?? 0);
|
|
@@ -14927,25 +14966,33 @@ function createQueryBuilder(state) {
|
|
|
14927
14966
|
return { data: hasMore ? data.slice(0, perPage) : data, meta: { perPage, page: p, hasMore } };
|
|
14928
14967
|
},
|
|
14929
14968
|
async cursorPaginate(perPage, cursor, column = "id", direction = "asc") {
|
|
14930
|
-
|
|
14969
|
+
if (!Number.isInteger(perPage) || perPage <= 0)
|
|
14970
|
+
throw new TypeError(`[query-builder] cursorPaginate(perPage): expected positive integer, got ${perPage}`);
|
|
14971
|
+
const cols = (Array.isArray(column) ? column : [column]).map(String);
|
|
14972
|
+
for (const c of cols)
|
|
14973
|
+
validateIdentifier(c, "cursorPaginate(column)");
|
|
14974
|
+
const cmp = direction === "asc" ? ">" : "<";
|
|
14975
|
+
const dir = direction === "asc" ? "ASC" : "DESC";
|
|
14976
|
+
const params = [...whereParams];
|
|
14977
|
+
let predicate = "";
|
|
14931
14978
|
if (cursor !== undefined && cursor !== null) {
|
|
14932
14979
|
if (Array.isArray(column)) {
|
|
14933
|
-
const
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14980
|
+
const phs = cursor.map((v) => {
|
|
14981
|
+
params.push(v);
|
|
14982
|
+
return getPlaceholder(params.length);
|
|
14983
|
+
});
|
|
14984
|
+
predicate = `(${cols.join(", ")}) ${cmp} (${phs.join(", ")})`;
|
|
14938
14985
|
} else {
|
|
14939
|
-
|
|
14986
|
+
params.push(cursor);
|
|
14987
|
+
predicate = `${cols[0]} ${cmp} ${getPlaceholder(params.length)}`;
|
|
14940
14988
|
}
|
|
14941
14989
|
}
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
} else {
|
|
14947
|
-
q = sql`${q} ORDER BY ${sql(String(column))} ${direction === "asc" ? sql`ASC` : sql`DESC`} LIMIT ${perPage + 1}`;
|
|
14990
|
+
const base2 = reorderSelectClauses(predicate ? currentSql({ conn: "AND", sql: predicate }) : currentSql());
|
|
14991
|
+
const order = cols.map((c) => `${c} ${dir}`).join(", ");
|
|
14992
|
+
if (hasTopLevelOrderBy(base2)) {
|
|
14993
|
+
throw new TypeError(`[query-builder] cursorPaginate() cannot be combined with orderBy() \u2014 it orders by ` + `${order} itself, and a cursor is only meaningful in that order. ` + `Remove the orderBy(), or pass the column and direction to cursorPaginate().`);
|
|
14948
14994
|
}
|
|
14995
|
+
const q = params.length > 0 ? _sql.unsafe(`${base2} ORDER BY ${order} LIMIT ${perPage + 1}`, params) : _sql.unsafe(`${base2} ORDER BY ${order} LIMIT ${perPage + 1}`);
|
|
14949
14996
|
const rows = await runWithHooks(q, "select", { signal: abortSignal, timeoutMs });
|
|
14950
14997
|
const hasMore = rows.length > perPage;
|
|
14951
14998
|
const data = rows.slice(0, perPage);
|
|
@@ -15019,8 +15066,8 @@ function createQueryBuilder(state) {
|
|
|
15019
15066
|
};
|
|
15020
15067
|
const predicate = `${table}.${softDeleteColumn} IS NOT NULL`;
|
|
15021
15068
|
text = splice(text, predicate);
|
|
15022
|
-
const
|
|
15023
|
-
built = sql([splice(
|
|
15069
|
+
const currentSql2 = String(ensureBuilt());
|
|
15070
|
+
built = sql([splice(currentSql2, predicate)]);
|
|
15024
15071
|
return this;
|
|
15025
15072
|
},
|
|
15026
15073
|
scope(name, value) {
|
|
@@ -15063,7 +15110,7 @@ function createQueryBuilder(state) {
|
|
|
15063
15110
|
return ensureBuilt().simple();
|
|
15064
15111
|
},
|
|
15065
15112
|
toText() {
|
|
15066
|
-
return
|
|
15113
|
+
return currentSql();
|
|
15067
15114
|
},
|
|
15068
15115
|
async get() {
|
|
15069
15116
|
const hooks = activeHooks();
|
|
@@ -15071,11 +15118,12 @@ function createQueryBuilder(state) {
|
|
|
15071
15118
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !hasQueryHooks) {
|
|
15072
15119
|
const prepareFn = _sql._prepareStatement;
|
|
15073
15120
|
if (prepareFn) {
|
|
15074
|
-
const stmt = prepareFn(
|
|
15121
|
+
const stmt = prepareFn(currentSql());
|
|
15075
15122
|
return hydratePivotRows(whereParams.length > 0 ? stmt.all(...whereParams) : stmt.all());
|
|
15076
15123
|
}
|
|
15077
15124
|
}
|
|
15078
|
-
|
|
15125
|
+
const getText = currentSql();
|
|
15126
|
+
built = whereParams.length > 0 ? _sql.unsafe(getText, whereParams) : _sql.unsafe(getText);
|
|
15079
15127
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !hasQueryHooks) {
|
|
15080
15128
|
const stmt = ensureBuilt()._stmt;
|
|
15081
15129
|
const params = ensureBuilt()._params;
|
|
@@ -15092,9 +15140,9 @@ function createQueryBuilder(state) {
|
|
|
15092
15140
|
const col = config5.softDeletes.column;
|
|
15093
15141
|
const tbl = String(table);
|
|
15094
15142
|
const hasCol = schema ? Boolean(schema[tbl]?.columns?.[col]) : true;
|
|
15095
|
-
if (hasCol && !SQL_PATTERNS.DELETED_AT.test(
|
|
15096
|
-
finalQuery = sql`${ensureBuilt()} WHERE ${sql(String(col))} IS ${onlyTrashed ? sql`NOT NULL` : sql`NULL`}`;
|
|
15143
|
+
if (hasCol && !SQL_PATTERNS.DELETED_AT.test(currentSql())) {
|
|
15097
15144
|
addWhereText("WHERE", `${String(col)} IS ${onlyTrashed ? "NOT " : ""}NULL`);
|
|
15145
|
+
finalQuery = ensureBuilt();
|
|
15098
15146
|
}
|
|
15099
15147
|
}
|
|
15100
15148
|
const cacheKey = useCache ? `${String(finalQuery)}\x00${JSON.stringify(whereParams)}` : "";
|
|
@@ -15124,7 +15172,8 @@ function createQueryBuilder(state) {
|
|
|
15124
15172
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !fHasQueryHooks) {
|
|
15125
15173
|
const prepareFn = _sql._prepareStatement;
|
|
15126
15174
|
if (prepareFn) {
|
|
15127
|
-
const
|
|
15175
|
+
const base2 = currentSql();
|
|
15176
|
+
const firstText = base2.includes(" LIMIT ") ? base2 : `${base2} LIMIT 1`;
|
|
15128
15177
|
const stmt = prepareFn(firstText);
|
|
15129
15178
|
const rows2 = whereParams.length > 0 ? stmt.all(...whereParams) : stmt.all();
|
|
15130
15179
|
return hydratePivotRow(rows2[0]);
|
|
@@ -15191,13 +15240,14 @@ function createQueryBuilder(state) {
|
|
|
15191
15240
|
return fn(this);
|
|
15192
15241
|
},
|
|
15193
15242
|
async count() {
|
|
15194
|
-
const
|
|
15195
|
-
const
|
|
15243
|
+
const src = currentSql();
|
|
15244
|
+
const fromIdx = src.indexOf(" FROM ");
|
|
15245
|
+
const hasGroupBy = / GROUP BY /i.test(src);
|
|
15196
15246
|
let countText;
|
|
15197
15247
|
if (hasGroupBy) {
|
|
15198
|
-
countText = `SELECT COUNT(*) as c FROM (${
|
|
15248
|
+
countText = `SELECT COUNT(*) as c FROM (${src}) AS _bqb_count_sub`;
|
|
15199
15249
|
} else if (fromIdx !== -1) {
|
|
15200
|
-
countText = `SELECT COUNT(*) as c${
|
|
15250
|
+
countText = `SELECT COUNT(*) as c${src.substring(fromIdx)}`;
|
|
15201
15251
|
} else {
|
|
15202
15252
|
countText = `SELECT COUNT(*) as c FROM ${table}`;
|
|
15203
15253
|
}
|
|
@@ -15217,8 +15267,9 @@ function createQueryBuilder(state) {
|
|
|
15217
15267
|
return Number(row?.c ?? 0);
|
|
15218
15268
|
},
|
|
15219
15269
|
async avg(column) {
|
|
15220
|
-
const
|
|
15221
|
-
const
|
|
15270
|
+
const src = currentSql();
|
|
15271
|
+
const fromIdx = src.indexOf(" FROM ");
|
|
15272
|
+
const avgText = fromIdx !== -1 ? `SELECT AVG(${column}) as a${src.substring(fromIdx)}` : `SELECT AVG(${column}) as a FROM ${table}`;
|
|
15222
15273
|
const aHooks = activeHooks();
|
|
15223
15274
|
const aHasHooks = aHooks && (aHooks.onQueryStart || aHooks.onQueryEnd || aHooks.onQueryError || aHooks.startSpan || hasSlowQueryHook(aHooks));
|
|
15224
15275
|
if (!config5.softDeletes?.enabled && !useCache && !timeoutMs && !abortSignal && !aHasHooks) {
|
|
@@ -15235,24 +15286,27 @@ function createQueryBuilder(state) {
|
|
|
15235
15286
|
return Number(row?.a ?? 0);
|
|
15236
15287
|
},
|
|
15237
15288
|
async sum(column) {
|
|
15238
|
-
const
|
|
15239
|
-
const
|
|
15289
|
+
const src = currentSql();
|
|
15290
|
+
const fromIdx = src.indexOf(" FROM ");
|
|
15291
|
+
const sumText = fromIdx !== -1 ? `SELECT SUM(${column}) as s${src.substring(fromIdx)}` : `SELECT SUM(${column}) as s FROM ${table}`;
|
|
15240
15292
|
const q = whereParams.length > 0 ? _sql.unsafe(sumText, whereParams) : _sql.unsafe(sumText);
|
|
15241
15293
|
const rows = await runWithHooks(q, "select", { signal: abortSignal, timeoutMs });
|
|
15242
15294
|
const [row] = rows;
|
|
15243
15295
|
return Number(row?.s ?? 0);
|
|
15244
15296
|
},
|
|
15245
15297
|
async max(column) {
|
|
15246
|
-
const
|
|
15247
|
-
const
|
|
15298
|
+
const src = currentSql();
|
|
15299
|
+
const fromIdx = src.indexOf(" FROM ");
|
|
15300
|
+
const maxText = fromIdx !== -1 ? `SELECT MAX(${column}) as m${src.substring(fromIdx)}` : `SELECT MAX(${column}) as m FROM ${table}`;
|
|
15248
15301
|
const q = whereParams.length > 0 ? _sql.unsafe(maxText, whereParams) : _sql.unsafe(maxText);
|
|
15249
15302
|
const rows = await runWithHooks(q, "select", { signal: abortSignal, timeoutMs });
|
|
15250
15303
|
const [row] = rows;
|
|
15251
15304
|
return row?.m;
|
|
15252
15305
|
},
|
|
15253
15306
|
async min(column) {
|
|
15254
|
-
const
|
|
15255
|
-
const
|
|
15307
|
+
const src = currentSql();
|
|
15308
|
+
const fromIdx = src.indexOf(" FROM ");
|
|
15309
|
+
const minText = fromIdx !== -1 ? `SELECT MIN(${column}) as m${src.substring(fromIdx)}` : `SELECT MIN(${column}) as m FROM ${table}`;
|
|
15256
15310
|
const q = whereParams.length > 0 ? _sql.unsafe(minText, whereParams) : _sql.unsafe(minText);
|
|
15257
15311
|
const rows = await runWithHooks(q, "select", { signal: abortSignal, timeoutMs });
|
|
15258
15312
|
const [row] = rows;
|
|
@@ -15291,7 +15345,7 @@ function createQueryBuilder(state) {
|
|
|
15291
15345
|
return [...whereParams];
|
|
15292
15346
|
},
|
|
15293
15347
|
__rawState() {
|
|
15294
|
-
return { sql: reorderSelectClauses(
|
|
15348
|
+
return { sql: reorderSelectClauses(currentSql()), params: [...whereParams] };
|
|
15295
15349
|
},
|
|
15296
15350
|
raw() {
|
|
15297
15351
|
return ensureBuilt().raw();
|
|
@@ -15335,8 +15389,6 @@ function createQueryBuilder(state) {
|
|
|
15335
15389
|
return () => receiver;
|
|
15336
15390
|
const column = chosen;
|
|
15337
15391
|
return (value) => {
|
|
15338
|
-
const expr = Array.isArray(value) ? sql`${sql(column)} IN ${sql(value)}` : sql`${sql(column)} = ${value}`;
|
|
15339
|
-
built = isOr ? sql`${ensureBuilt()} OR ${expr}` : isAnd ? sql`${ensureBuilt()} AND ${expr}` : sql`${ensureBuilt()} WHERE ${expr}`;
|
|
15340
15392
|
if (Array.isArray(value)) {
|
|
15341
15393
|
const phs = getPlaceholders(value.length, whereParams.length + 1);
|
|
15342
15394
|
addWhereText(isOr ? "OR" : isAnd ? "AND" : "WHERE", `${column} IN (${phs})`);
|
|
@@ -15391,8 +15443,7 @@ function createQueryBuilder(state) {
|
|
|
15391
15443
|
const subText = rawState?.sql ?? (typeof subExec === "string" ? subExec : subExec?.sql ?? String(subExec));
|
|
15392
15444
|
const subParams = rawState?.params ?? (Array.isArray(subExec?.values) ? subExec.values : []);
|
|
15393
15445
|
const baseText = `SELECT * FROM (${subText}) AS ${String(alias)}`;
|
|
15394
|
-
const appendWhere = (
|
|
15395
|
-
const kw = !hasWhere ? "WHERE" : connector === "WHERE" ? "AND" : connector;
|
|
15446
|
+
const appendWhere = (params, expr, op, value) => {
|
|
15396
15447
|
const out = [...params];
|
|
15397
15448
|
const cmp = (col, operator, val) => {
|
|
15398
15449
|
validateIdentifier(col, "selectFromSub where(column)");
|
|
@@ -15408,61 +15459,91 @@ function createQueryBuilder(state) {
|
|
|
15408
15459
|
return `${col} ${o} ${ph}`;
|
|
15409
15460
|
};
|
|
15410
15461
|
let clause;
|
|
15411
|
-
if (typeof expr === "string" && op !== undefined)
|
|
15462
|
+
if (typeof expr === "string" && op !== undefined) {
|
|
15412
15463
|
clause = cmp(expr, op, value);
|
|
15413
|
-
else if (Array.isArray(expr) && expr.length === 3)
|
|
15464
|
+
} else if (Array.isArray(expr) && expr.length === 3) {
|
|
15414
15465
|
clause = cmp(expr[0], expr[1], expr[2]);
|
|
15415
|
-
else if (expr && typeof expr === "object")
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
15466
|
+
} else if (expr && typeof expr === "object") {
|
|
15467
|
+
const parts = Object.entries(expr).map(([k, v]) => cmp(k, "=", v));
|
|
15468
|
+
clause = parts.length > 1 ? `(${parts.join(" AND ")})` : parts[0];
|
|
15469
|
+
} else {
|
|
15470
|
+
return { clause: null, params };
|
|
15471
|
+
}
|
|
15472
|
+
return { clause, params: out };
|
|
15420
15473
|
};
|
|
15421
|
-
function makeSub(
|
|
15474
|
+
function makeSub(baseText2, terms, params, tail = "") {
|
|
15475
|
+
const body = renderWhereTerms(terms);
|
|
15476
|
+
const text = body ? `${baseText2} WHERE ${body}${tail}` : `${baseText2}${tail}`;
|
|
15422
15477
|
const build = () => params.length > 0 ? _sql.unsafe(text, params) : _sql.unsafe(text);
|
|
15478
|
+
const withTerm = (conn, expr, op, value) => {
|
|
15479
|
+
const r = appendWhere(params, expr, op, value);
|
|
15480
|
+
return r.clause === null ? makeSub(baseText2, terms, params, tail) : makeSub(baseText2, [...terms, { conn, sql: r.clause }], r.params, tail);
|
|
15481
|
+
};
|
|
15482
|
+
const withGroup = (conn, cb) => {
|
|
15483
|
+
const gTerms = [];
|
|
15484
|
+
let gParams = [...params];
|
|
15485
|
+
const add = (c) => (expr, op, value) => {
|
|
15486
|
+
const r = appendWhere(gParams, expr, op, value);
|
|
15487
|
+
if (r.clause !== null) {
|
|
15488
|
+
gTerms.push({ conn: c, sql: r.clause });
|
|
15489
|
+
gParams = r.params;
|
|
15490
|
+
}
|
|
15491
|
+
return collector;
|
|
15492
|
+
};
|
|
15493
|
+
const collector = { where: add("AND"), andWhere: add("AND"), orWhere: add("OR") };
|
|
15494
|
+
cb(collector);
|
|
15495
|
+
const body2 = renderWhereTerms(gTerms);
|
|
15496
|
+
if (!body2) {
|
|
15497
|
+
throw new TypeError("[query-builder] selectFromSub.whereGroup(callback): the callback added no conditions. " + "Add at least one where()/orWhere() to the builder it receives.");
|
|
15498
|
+
}
|
|
15499
|
+
return makeSub(baseText2, [...terms, { conn, sql: `(${body2})` }], gParams, tail);
|
|
15500
|
+
};
|
|
15423
15501
|
const base = {
|
|
15424
15502
|
distinct() {
|
|
15425
|
-
return makeSub(
|
|
15503
|
+
return makeSub(baseText2.replace(/^SELECT\s+/i, "SELECT DISTINCT "), terms, params, tail);
|
|
15426
15504
|
},
|
|
15427
15505
|
distinctOn(...columns) {
|
|
15428
15506
|
const cols = columns.map(String).join(", ");
|
|
15429
|
-
return makeSub(
|
|
15507
|
+
return makeSub(baseText2.replace(/^SELECT\s+/i, `SELECT DISTINCT ON (${cols}) `), terms, params, tail);
|
|
15430
15508
|
},
|
|
15431
15509
|
selectRaw(fragment) {
|
|
15432
15510
|
const frag = renderRawFragment(fragment, "selectFromSub.selectRaw(fragment)");
|
|
15433
|
-
const fromIdx =
|
|
15434
|
-
const
|
|
15435
|
-
return makeSub(
|
|
15511
|
+
const fromIdx = baseText2.indexOf(" FROM ");
|
|
15512
|
+
const newBase = fromIdx !== -1 ? `${baseText2.slice(0, fromIdx)}, ${frag}${baseText2.slice(fromIdx)}` : `${baseText2}, ${frag}`;
|
|
15513
|
+
return makeSub(newBase, terms, params, tail);
|
|
15436
15514
|
},
|
|
15437
15515
|
where(expr, op, value) {
|
|
15438
|
-
|
|
15439
|
-
return makeSub(r.text, r.params, true);
|
|
15516
|
+
return withTerm("AND", expr, op, value);
|
|
15440
15517
|
},
|
|
15441
15518
|
andWhere(expr, op, value) {
|
|
15442
|
-
|
|
15443
|
-
return makeSub(r.text, r.params, true);
|
|
15519
|
+
return withTerm("AND", expr, op, value);
|
|
15444
15520
|
},
|
|
15445
15521
|
orWhere(expr, op, value) {
|
|
15446
|
-
|
|
15447
|
-
|
|
15522
|
+
return withTerm("OR", expr, op, value);
|
|
15523
|
+
},
|
|
15524
|
+
whereGroup(cb) {
|
|
15525
|
+
return withGroup("AND", cb);
|
|
15526
|
+
},
|
|
15527
|
+
orWhereGroup(cb) {
|
|
15528
|
+
return withGroup("OR", cb);
|
|
15448
15529
|
},
|
|
15449
15530
|
orderBy(column, direction = "asc") {
|
|
15450
15531
|
validateIdentifier(String(column), "selectFromSub.orderBy(column)");
|
|
15451
15532
|
const dir = direction === "asc" ? "ASC" : "DESC";
|
|
15452
|
-
const
|
|
15453
|
-
return makeSub(
|
|
15533
|
+
const newTail = SQL_PATTERNS.ORDER_BY.test(tail) ? `${tail}, ${column} ${dir}` : `${tail} ORDER BY ${column} ${dir}`;
|
|
15534
|
+
return makeSub(baseText2, terms, params, newTail);
|
|
15454
15535
|
},
|
|
15455
15536
|
limit(n) {
|
|
15456
15537
|
if (!Number.isInteger(n) || n < 0)
|
|
15457
15538
|
throw new TypeError(`[query-builder] selectFromSub.limit(n): expected non-negative integer, got ${n}`);
|
|
15458
|
-
const
|
|
15459
|
-
return makeSub(
|
|
15539
|
+
const newTail = SQL_PATTERNS.LIMIT.test(tail) ? tail.replace(SQL_PATTERNS.LIMIT, ` LIMIT ${n}`) : `${tail} LIMIT ${n}`;
|
|
15540
|
+
return makeSub(baseText2, terms, params, newTail);
|
|
15460
15541
|
},
|
|
15461
15542
|
offset(n) {
|
|
15462
15543
|
if (!Number.isInteger(n) || n < 0)
|
|
15463
15544
|
throw new TypeError(`[query-builder] selectFromSub.offset(n): expected non-negative integer, got ${n}`);
|
|
15464
|
-
const
|
|
15465
|
-
return makeSub(
|
|
15545
|
+
const newTail = SQL_PATTERNS.OFFSET.test(tail) ? tail.replace(SQL_PATTERNS.OFFSET, ` OFFSET ${n}`) : `${tail} OFFSET ${n}`;
|
|
15546
|
+
return makeSub(baseText2, terms, params, newTail);
|
|
15466
15547
|
},
|
|
15467
15548
|
toSQL() {
|
|
15468
15549
|
return makeExecutableQuery(build(), text);
|
|
@@ -15545,8 +15626,13 @@ function createQueryBuilder(state) {
|
|
|
15545
15626
|
whereJsonContains: subqueryNotSupported("whereJsonContains"),
|
|
15546
15627
|
whereJsonPath: subqueryNotSupported("whereJsonPath"),
|
|
15547
15628
|
whereNull: subqueryNotSupported("whereNull"),
|
|
15629
|
+
orWhereNull: subqueryNotSupported("orWhereNull"),
|
|
15548
15630
|
whereNotNull: subqueryNotSupported("whereNotNull"),
|
|
15631
|
+
orWhereNotNull: subqueryNotSupported("orWhereNotNull"),
|
|
15549
15632
|
whereExists: subqueryNotSupported("whereExists"),
|
|
15633
|
+
orWhereExists: subqueryNotSupported("orWhereExists"),
|
|
15634
|
+
orWhereBetween: subqueryNotSupported("orWhereBetween"),
|
|
15635
|
+
orWhereRaw: subqueryNotSupported("orWhereRaw"),
|
|
15550
15636
|
whereJsonDoesntContain: subqueryNotSupported("whereJsonDoesntContain"),
|
|
15551
15637
|
whereJsonContainsKey: subqueryNotSupported("whereJsonContainsKey"),
|
|
15552
15638
|
whereJsonDoesntContainKey: subqueryNotSupported("whereJsonDoesntContainKey"),
|
|
@@ -15625,7 +15711,7 @@ function createQueryBuilder(state) {
|
|
|
15625
15711
|
};
|
|
15626
15712
|
return base;
|
|
15627
15713
|
}
|
|
15628
|
-
return makeSub(baseText, subParams);
|
|
15714
|
+
return makeSub(baseText, [], subParams);
|
|
15629
15715
|
},
|
|
15630
15716
|
insertInto(table) {
|
|
15631
15717
|
let built;
|
|
@@ -16730,7 +16816,7 @@ function clearQueryCache() {
|
|
|
16730
16816
|
function setQueryCacheMaxSize(size) {
|
|
16731
16817
|
queryCache.setMaxSize(size);
|
|
16732
16818
|
}
|
|
16733
|
-
var
|
|
16819
|
+
var SQL_PATTERNS, SAFE_WHERE_OPERATORS, warnedSqlFragmentContexts, queryCache, reorderCache, REORDER_CACHE_MAX = 500;
|
|
16734
16820
|
var init_client = __esm(() => {
|
|
16735
16821
|
init_config();
|
|
16736
16822
|
init_db();
|
|
@@ -19465,7 +19551,7 @@ var init_migrate = __esm(() => {
|
|
|
19465
19551
|
init_src2();
|
|
19466
19552
|
init_introspect_db();
|
|
19467
19553
|
init_workspace();
|
|
19468
|
-
NON_TRANSACTIONAL_SQL = /\bCONCURRENTLY\b|^\s*VACUUM\b/im;
|
|
19554
|
+
NON_TRANSACTIONAL_SQL = /\bCONCURRENTLY\b|^\s*VACUUM\b|^\s*BEGIN\s*(?:;|TRANSACTION\b)|^\s*PRAGMA\s+foreign_keys\b/im;
|
|
19469
19555
|
});
|
|
19470
19556
|
|
|
19471
19557
|
// src/actions/migrate-generate.ts
|
|
@@ -20524,6 +20610,135 @@ var init_actions = __esm(() => {
|
|
|
20524
20610
|
init_wait_ready();
|
|
20525
20611
|
});
|
|
20526
20612
|
|
|
20613
|
+
// src/faker-compat.ts
|
|
20614
|
+
function asStringOptions(value) {
|
|
20615
|
+
if (typeof value === "number")
|
|
20616
|
+
return { length: value };
|
|
20617
|
+
return value;
|
|
20618
|
+
}
|
|
20619
|
+
function asNumberOptions(value) {
|
|
20620
|
+
if (typeof value === "number")
|
|
20621
|
+
return { max: value };
|
|
20622
|
+
return value;
|
|
20623
|
+
}
|
|
20624
|
+
function callable(value) {
|
|
20625
|
+
return typeof value === "function";
|
|
20626
|
+
}
|
|
20627
|
+
function flattened(name) {
|
|
20628
|
+
return name.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
|
|
20629
|
+
}
|
|
20630
|
+
function withFractionDigits(value, options) {
|
|
20631
|
+
if (!options || typeof options.fractionDigits !== "number")
|
|
20632
|
+
return value;
|
|
20633
|
+
return Number(value.toFixed(options.fractionDigits));
|
|
20634
|
+
}
|
|
20635
|
+
function compatModule(underlying, overrides = {}) {
|
|
20636
|
+
if (!underlying)
|
|
20637
|
+
return overrides;
|
|
20638
|
+
return new Proxy(underlying, {
|
|
20639
|
+
get(target, property) {
|
|
20640
|
+
if (property in overrides)
|
|
20641
|
+
return overrides[property];
|
|
20642
|
+
const direct = target[property];
|
|
20643
|
+
if (direct !== undefined)
|
|
20644
|
+
return direct;
|
|
20645
|
+
const fallback = target[flattened(property)];
|
|
20646
|
+
if (callable(fallback))
|
|
20647
|
+
return fallback.bind(target);
|
|
20648
|
+
return;
|
|
20649
|
+
}
|
|
20650
|
+
});
|
|
20651
|
+
}
|
|
20652
|
+
function createFakerCompatLayer(underlying) {
|
|
20653
|
+
const pick = (items) => {
|
|
20654
|
+
const list = Array.isArray(items) ? items : [];
|
|
20655
|
+
const index = Math.floor(Math.random() * list.length);
|
|
20656
|
+
return list[index];
|
|
20657
|
+
};
|
|
20658
|
+
const strings = () => underlying.string;
|
|
20659
|
+
const numbers = () => underlying.number;
|
|
20660
|
+
const random = () => underlying.random;
|
|
20661
|
+
const compatString = compatModule(underlying.string, {
|
|
20662
|
+
alpha: (options) => strings()?.alpha?.(asStringOptions(options)),
|
|
20663
|
+
alphanumeric: (options) => strings()?.alphanumeric?.(asStringOptions(options)),
|
|
20664
|
+
numeric: (options) => strings()?.numeric?.(asStringOptions(options)),
|
|
20665
|
+
sample: (options) => strings()?.sample?.(asStringOptions(options)),
|
|
20666
|
+
hexadecimal: (options) => strings()?.hexadecimal?.(asStringOptions(options))
|
|
20667
|
+
});
|
|
20668
|
+
const compatNumber = compatModule(underlying.number, {
|
|
20669
|
+
int: (options) => numbers()?.int?.(asNumberOptions(options)),
|
|
20670
|
+
float: (options) => {
|
|
20671
|
+
const parsed = asNumberOptions(options);
|
|
20672
|
+
return withFractionDigits(Number(numbers()?.float?.(parsed) ?? 0), parsed);
|
|
20673
|
+
}
|
|
20674
|
+
});
|
|
20675
|
+
const compatHelpers = compatModule(underlying.helpers, {
|
|
20676
|
+
arrayElement: pick,
|
|
20677
|
+
arrayElements: (items, count) => {
|
|
20678
|
+
const list = [...Array.isArray(items) ? items : []];
|
|
20679
|
+
const wanted = typeof count === "number" ? count : Math.max(1, Math.floor(Math.random() * list.length));
|
|
20680
|
+
for (let at = list.length - 1;at > 0; at -= 1) {
|
|
20681
|
+
const swap = Math.floor(Math.random() * (at + 1));
|
|
20682
|
+
[list[at], list[swap]] = [list[swap], list[at]];
|
|
20683
|
+
}
|
|
20684
|
+
return list.slice(0, Math.min(wanted, list.length));
|
|
20685
|
+
},
|
|
20686
|
+
shuffle: (items) => {
|
|
20687
|
+
const list = [...Array.isArray(items) ? items : []];
|
|
20688
|
+
for (let at = list.length - 1;at > 0; at -= 1) {
|
|
20689
|
+
const swap = Math.floor(Math.random() * (at + 1));
|
|
20690
|
+
[list[at], list[swap]] = [list[swap], list[at]];
|
|
20691
|
+
}
|
|
20692
|
+
return list;
|
|
20693
|
+
},
|
|
20694
|
+
maybe: (produce, options) => {
|
|
20695
|
+
const probability = typeof options?.probability === "number" ? options.probability : 0.5;
|
|
20696
|
+
return Math.random() < probability ? produce() : undefined;
|
|
20697
|
+
},
|
|
20698
|
+
slugify: (text) => String(text ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
|
|
20699
|
+
});
|
|
20700
|
+
const compatDatatype = {
|
|
20701
|
+
boolean: (options) => {
|
|
20702
|
+
const probability = typeof options === "number" ? options : options?.probability;
|
|
20703
|
+
if (typeof probability === "number")
|
|
20704
|
+
return Math.random() < probability;
|
|
20705
|
+
return Boolean(random()?.boolean?.());
|
|
20706
|
+
},
|
|
20707
|
+
number: (options) => Number(numbers()?.int?.(asNumberOptions(options)) ?? 0),
|
|
20708
|
+
float: (options) => withFractionDigits(Number(numbers()?.float?.(options) ?? 0), options),
|
|
20709
|
+
uuid: () => crypto.randomUUID(),
|
|
20710
|
+
string: (length) => String(strings()?.alphanumeric?.({ length: length ?? 10 }) ?? ""),
|
|
20711
|
+
hexadecimal: (options) => String(strings()?.hexadecimal?.(asStringOptions(options)) ?? ""),
|
|
20712
|
+
array: (length) => Array.from({ length: length ?? 3 }, () => strings()?.alphanumeric?.({ length: 8 })),
|
|
20713
|
+
json: () => JSON.stringify({ value: strings()?.alphanumeric?.({ length: 8 }) })
|
|
20714
|
+
};
|
|
20715
|
+
const modules = {
|
|
20716
|
+
string: compatString,
|
|
20717
|
+
number: compatNumber,
|
|
20718
|
+
helpers: compatHelpers,
|
|
20719
|
+
datatype: compatDatatype,
|
|
20720
|
+
location: compatModule(underlying.address),
|
|
20721
|
+
address: compatModule(underlying.address),
|
|
20722
|
+
vehicle: compatModule(underlying.vehicle, {
|
|
20723
|
+
vrm: () => underlying.vehicle?.registration?.()
|
|
20724
|
+
}),
|
|
20725
|
+
company: compatModule(underlying.company, {
|
|
20726
|
+
catchPhrase: () => underlying.company?.catchphrase?.(),
|
|
20727
|
+
buzzPhrase: () => underlying.company?.bs?.() ?? underlying.company?.buzzword?.()
|
|
20728
|
+
})
|
|
20729
|
+
};
|
|
20730
|
+
return new Proxy(underlying, {
|
|
20731
|
+
get(target, property) {
|
|
20732
|
+
if (property in modules)
|
|
20733
|
+
return modules[property];
|
|
20734
|
+
const direct = target[property];
|
|
20735
|
+
if (direct && typeof direct === "object")
|
|
20736
|
+
return compatModule(direct);
|
|
20737
|
+
return direct;
|
|
20738
|
+
}
|
|
20739
|
+
});
|
|
20740
|
+
}
|
|
20741
|
+
|
|
20527
20742
|
// src/relation-utils.ts
|
|
20528
20743
|
function normalizeRelationEntry(entry) {
|
|
20529
20744
|
if (typeof entry === "string")
|
|
@@ -26231,9 +26446,8 @@ class ModelQueryBuilder {
|
|
|
26231
26446
|
return this._withRelations;
|
|
26232
26447
|
}
|
|
26233
26448
|
buildWhereClauses(params) {
|
|
26234
|
-
const
|
|
26235
|
-
for (
|
|
26236
|
-
const w = this._wheres[i2];
|
|
26449
|
+
const terms = [];
|
|
26450
|
+
for (const w of this._wheres) {
|
|
26237
26451
|
let clause;
|
|
26238
26452
|
if (w.raw) {
|
|
26239
26453
|
clause = w.raw;
|
|
@@ -26244,15 +26458,15 @@ class ModelQueryBuilder {
|
|
|
26244
26458
|
clause = w.operator === "=" ? `${col} IS NULL` : `${col} IS NOT NULL`;
|
|
26245
26459
|
} else if (w.operator === "in" || w.operator === "not in") {
|
|
26246
26460
|
const arr = w.value;
|
|
26247
|
-
clause =
|
|
26461
|
+
clause = renderInPredicate(sqlColumn(w.column), arr, w.operator === "not in", arr.map(() => "?").join(", "));
|
|
26248
26462
|
params.push(...arr);
|
|
26249
26463
|
} else {
|
|
26250
26464
|
clause = `${sqlColumn(w.column)} ${w.operator} ?`;
|
|
26251
26465
|
params.push(w.value);
|
|
26252
26466
|
}
|
|
26253
|
-
|
|
26467
|
+
terms.push({ conn: w.boolean === "or" ? "OR" : "AND", sql: clause });
|
|
26254
26468
|
}
|
|
26255
|
-
return
|
|
26469
|
+
return renderWhereTerms(terms);
|
|
26256
26470
|
}
|
|
26257
26471
|
softDeleteClause() {
|
|
26258
26472
|
if (this._trashed === "include" || !softDeletesEnabled(this._definition))
|
|
@@ -26844,27 +27058,6 @@ async function createTableFromModel(definition) {
|
|
|
26844
27058
|
}
|
|
26845
27059
|
await exec.run(`CREATE TABLE IF NOT EXISTS ${definition.table} (${columns.join(", ")})`, []);
|
|
26846
27060
|
}
|
|
26847
|
-
function createFakerCompatLayer(underlying) {
|
|
26848
|
-
return new Proxy(underlying, {
|
|
26849
|
-
get(target, prop) {
|
|
26850
|
-
if (prop === "location")
|
|
26851
|
-
return target.address;
|
|
26852
|
-
if (prop === "datatype") {
|
|
26853
|
-
const rng = target.random;
|
|
26854
|
-
const num = target.number;
|
|
26855
|
-
const str = target.string;
|
|
26856
|
-
return {
|
|
26857
|
-
boolean: () => rng?.boolean?.(),
|
|
26858
|
-
number: (opts) => num?.int?.(opts),
|
|
26859
|
-
float: (opts) => num?.float?.(opts),
|
|
26860
|
-
uuid: () => crypto.randomUUID(),
|
|
26861
|
-
string: (length) => str?.alphanumeric?.(length ?? 10)
|
|
26862
|
-
};
|
|
26863
|
-
}
|
|
26864
|
-
return target[prop];
|
|
26865
|
-
}
|
|
26866
|
-
});
|
|
26867
|
-
}
|
|
26868
27061
|
async function seedModel(definition, count, faker) {
|
|
26869
27062
|
const exec = getExecutor();
|
|
26870
27063
|
const seeder = definition.traits?.useSeeder;
|
|
@@ -29912,6 +30105,7 @@ export {
|
|
|
29912
30105
|
createQueryBuilder,
|
|
29913
30106
|
createModel,
|
|
29914
30107
|
createMigrationDriver,
|
|
30108
|
+
createFakerCompatLayer,
|
|
29915
30109
|
createDynamoDBToolingAdapter,
|
|
29916
30110
|
createDynamoDBQueryBuilder,
|
|
29917
30111
|
createDynamoDBItemBuilder,
|