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