prisma-sql 1.38.0 → 1.39.0
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/generator.cjs +1522 -1537
- package/dist/generator.cjs.map +1 -1
- package/dist/generator.js +1522 -1537
- package/dist/generator.js.map +1 -1
- package/dist/index.cjs +1848 -1577
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1848 -1577
- package/dist/index.js.map +1 -1
- package/package.json +4 -15
- package/readme.md +1 -1
package/dist/generator.cjs
CHANGED
|
@@ -56,7 +56,7 @@ var require_package = __commonJS({
|
|
|
56
56
|
"package.json"(exports$1, module) {
|
|
57
57
|
module.exports = {
|
|
58
58
|
name: "prisma-sql",
|
|
59
|
-
version: "1.
|
|
59
|
+
version: "1.39.0",
|
|
60
60
|
description: "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
|
|
61
61
|
main: "dist/index.cjs",
|
|
62
62
|
module: "dist/index.js",
|
|
@@ -97,17 +97,6 @@ var require_package = __commonJS({
|
|
|
97
97
|
"sonar-cli": "sonar-scanner -Dsonar.projectKey=prisma-sql -Dsonar.sources=./src -Dsonar.host.url=http://localhost:9000 -Dsonar.login=sqp_9fe07460d0aa83f711d0edf4f317f05019d0613b",
|
|
98
98
|
sonar: "yarn sonar-cli && npx tsx scripts/sonar.ts"
|
|
99
99
|
},
|
|
100
|
-
workspaces: {
|
|
101
|
-
packages: [
|
|
102
|
-
"demo"
|
|
103
|
-
],
|
|
104
|
-
nohoist: [
|
|
105
|
-
"**/prisma",
|
|
106
|
-
"**/prisma/**",
|
|
107
|
-
"**/@prisma/**",
|
|
108
|
-
"**/prisma-*"
|
|
109
|
-
]
|
|
110
|
-
},
|
|
111
100
|
keywords: [
|
|
112
101
|
"prisma",
|
|
113
102
|
"sql",
|
|
@@ -140,7 +129,6 @@ var require_package = __commonJS({
|
|
|
140
129
|
"@faker-js/faker": "^10.2.0",
|
|
141
130
|
"@prisma/adapter-better-sqlite3": "^7.2.0",
|
|
142
131
|
"@prisma/adapter-pg": "^7.2.0",
|
|
143
|
-
"@prisma/client": "7.2.0",
|
|
144
132
|
"@types/better-sqlite3": "^7.6.13",
|
|
145
133
|
"@types/node": "^25.0.10",
|
|
146
134
|
"@vitest/coverage-v8": "4.0.18",
|
|
@@ -148,11 +136,12 @@ var require_package = __commonJS({
|
|
|
148
136
|
"drizzle-kit": "^0.31.8",
|
|
149
137
|
"drizzle-orm": "^0.45.1",
|
|
150
138
|
postgres: "^3.4.8",
|
|
151
|
-
prisma: "7.2.0",
|
|
152
139
|
tsup: "^8.5.1",
|
|
153
140
|
tsx: "^4.21.0",
|
|
154
141
|
typescript: "^5.9.3",
|
|
155
|
-
vitest: "^4.0.18"
|
|
142
|
+
vitest: "^4.0.18",
|
|
143
|
+
"@prisma/client": "7.2.0",
|
|
144
|
+
prisma: "7.2.0"
|
|
156
145
|
},
|
|
157
146
|
engines: {
|
|
158
147
|
node: ">=16.0.0"
|
|
@@ -161,6 +150,148 @@ var require_package = __commonJS({
|
|
|
161
150
|
}
|
|
162
151
|
});
|
|
163
152
|
|
|
153
|
+
// src/builder/shared/constants.ts
|
|
154
|
+
var SQL_SEPARATORS = Object.freeze({
|
|
155
|
+
FIELD_LIST: ", ",
|
|
156
|
+
CONDITION_AND: " AND ",
|
|
157
|
+
CONDITION_OR: " OR ",
|
|
158
|
+
ORDER_BY: ", "
|
|
159
|
+
});
|
|
160
|
+
var SQL_RESERVED_WORDS = /* @__PURE__ */ new Set([
|
|
161
|
+
"select",
|
|
162
|
+
"from",
|
|
163
|
+
"where",
|
|
164
|
+
"and",
|
|
165
|
+
"or",
|
|
166
|
+
"not",
|
|
167
|
+
"in",
|
|
168
|
+
"like",
|
|
169
|
+
"between",
|
|
170
|
+
"order",
|
|
171
|
+
"by",
|
|
172
|
+
"group",
|
|
173
|
+
"having",
|
|
174
|
+
"limit",
|
|
175
|
+
"offset",
|
|
176
|
+
"join",
|
|
177
|
+
"inner",
|
|
178
|
+
"left",
|
|
179
|
+
"right",
|
|
180
|
+
"outer",
|
|
181
|
+
"on",
|
|
182
|
+
"as",
|
|
183
|
+
"table",
|
|
184
|
+
"column",
|
|
185
|
+
"index",
|
|
186
|
+
"user",
|
|
187
|
+
"users",
|
|
188
|
+
"values",
|
|
189
|
+
"update",
|
|
190
|
+
"insert",
|
|
191
|
+
"delete",
|
|
192
|
+
"create",
|
|
193
|
+
"drop",
|
|
194
|
+
"alter",
|
|
195
|
+
"truncate",
|
|
196
|
+
"grant",
|
|
197
|
+
"revoke",
|
|
198
|
+
"exec",
|
|
199
|
+
"execute",
|
|
200
|
+
"union",
|
|
201
|
+
"intersect",
|
|
202
|
+
"except",
|
|
203
|
+
"case",
|
|
204
|
+
"when",
|
|
205
|
+
"then",
|
|
206
|
+
"else",
|
|
207
|
+
"end",
|
|
208
|
+
"null",
|
|
209
|
+
"true",
|
|
210
|
+
"false",
|
|
211
|
+
"is",
|
|
212
|
+
"exists",
|
|
213
|
+
"all",
|
|
214
|
+
"any",
|
|
215
|
+
"some"
|
|
216
|
+
]);
|
|
217
|
+
var SQL_KEYWORDS = SQL_RESERVED_WORDS;
|
|
218
|
+
var DEFAULT_WHERE_CLAUSE = "1=1";
|
|
219
|
+
var SPECIAL_FIELDS = Object.freeze({
|
|
220
|
+
ID: "id"
|
|
221
|
+
});
|
|
222
|
+
var SQL_TEMPLATES = Object.freeze({
|
|
223
|
+
PUBLIC_SCHEMA: "public",
|
|
224
|
+
WHERE: "WHERE",
|
|
225
|
+
SELECT: "SELECT",
|
|
226
|
+
FROM: "FROM",
|
|
227
|
+
ORDER_BY: "ORDER BY",
|
|
228
|
+
GROUP_BY: "GROUP BY",
|
|
229
|
+
HAVING: "HAVING",
|
|
230
|
+
LIMIT: "LIMIT",
|
|
231
|
+
OFFSET: "OFFSET",
|
|
232
|
+
COUNT_ALL: "COUNT(*)",
|
|
233
|
+
AS: "AS",
|
|
234
|
+
DISTINCT_ON: "DISTINCT ON",
|
|
235
|
+
IS_NULL: "IS NULL",
|
|
236
|
+
IS_NOT_NULL: "IS NOT NULL",
|
|
237
|
+
LIKE: "LIKE",
|
|
238
|
+
AND: "AND",
|
|
239
|
+
OR: "OR",
|
|
240
|
+
NOT: "NOT"
|
|
241
|
+
});
|
|
242
|
+
var SCHEMA_PREFIXES = Object.freeze({
|
|
243
|
+
INTERNAL: "@",
|
|
244
|
+
COMMENT: "//"
|
|
245
|
+
});
|
|
246
|
+
var Ops = Object.freeze({
|
|
247
|
+
EQUALS: "equals",
|
|
248
|
+
NOT: "not",
|
|
249
|
+
GT: "gt",
|
|
250
|
+
GTE: "gte",
|
|
251
|
+
LT: "lt",
|
|
252
|
+
LTE: "lte",
|
|
253
|
+
IN: "in",
|
|
254
|
+
NOT_IN: "notIn",
|
|
255
|
+
CONTAINS: "contains",
|
|
256
|
+
STARTS_WITH: "startsWith",
|
|
257
|
+
ENDS_WITH: "endsWith",
|
|
258
|
+
HAS: "has",
|
|
259
|
+
HAS_SOME: "hasSome",
|
|
260
|
+
HAS_EVERY: "hasEvery",
|
|
261
|
+
IS_EMPTY: "isEmpty",
|
|
262
|
+
PATH: "path",
|
|
263
|
+
STRING_CONTAINS: "string_contains",
|
|
264
|
+
STRING_STARTS_WITH: "string_starts_with",
|
|
265
|
+
STRING_ENDS_WITH: "string_ends_with"
|
|
266
|
+
});
|
|
267
|
+
var LogicalOps = Object.freeze({
|
|
268
|
+
AND: "AND",
|
|
269
|
+
OR: "OR",
|
|
270
|
+
NOT: "NOT"
|
|
271
|
+
});
|
|
272
|
+
var RelationFilters = Object.freeze({
|
|
273
|
+
SOME: "some",
|
|
274
|
+
EVERY: "every",
|
|
275
|
+
NONE: "none"
|
|
276
|
+
});
|
|
277
|
+
var Modes = Object.freeze({
|
|
278
|
+
INSENSITIVE: "insensitive",
|
|
279
|
+
DEFAULT: "default"
|
|
280
|
+
});
|
|
281
|
+
var Wildcards = Object.freeze({
|
|
282
|
+
[Ops.CONTAINS]: (v) => `%${v}%`,
|
|
283
|
+
[Ops.STARTS_WITH]: (v) => `${v}%`,
|
|
284
|
+
[Ops.ENDS_WITH]: (v) => `%${v}`
|
|
285
|
+
});
|
|
286
|
+
var REGEX_CACHE = {
|
|
287
|
+
VALID_IDENTIFIER: /^[a-z_][a-z0-9_]*$/
|
|
288
|
+
};
|
|
289
|
+
var LIMITS = Object.freeze({
|
|
290
|
+
MAX_QUERY_DEPTH: 50,
|
|
291
|
+
MAX_ARRAY_SIZE: 1e4,
|
|
292
|
+
MAX_STRING_LENGTH: 1e4
|
|
293
|
+
});
|
|
294
|
+
|
|
164
295
|
// src/sql-builder-dialect.ts
|
|
165
296
|
var globalDialect = "postgres";
|
|
166
297
|
function setGlobalDialect(dialect) {
|
|
@@ -342,148 +473,6 @@ function prepareArrayParam(value, dialect) {
|
|
|
342
473
|
return JSON.stringify(value);
|
|
343
474
|
}
|
|
344
475
|
|
|
345
|
-
// src/builder/shared/constants.ts
|
|
346
|
-
var SQL_SEPARATORS = Object.freeze({
|
|
347
|
-
FIELD_LIST: ", ",
|
|
348
|
-
CONDITION_AND: " AND ",
|
|
349
|
-
CONDITION_OR: " OR ",
|
|
350
|
-
ORDER_BY: ", "
|
|
351
|
-
});
|
|
352
|
-
var SQL_RESERVED_WORDS = /* @__PURE__ */ new Set([
|
|
353
|
-
"select",
|
|
354
|
-
"from",
|
|
355
|
-
"where",
|
|
356
|
-
"and",
|
|
357
|
-
"or",
|
|
358
|
-
"not",
|
|
359
|
-
"in",
|
|
360
|
-
"like",
|
|
361
|
-
"between",
|
|
362
|
-
"order",
|
|
363
|
-
"by",
|
|
364
|
-
"group",
|
|
365
|
-
"having",
|
|
366
|
-
"limit",
|
|
367
|
-
"offset",
|
|
368
|
-
"join",
|
|
369
|
-
"inner",
|
|
370
|
-
"left",
|
|
371
|
-
"right",
|
|
372
|
-
"outer",
|
|
373
|
-
"on",
|
|
374
|
-
"as",
|
|
375
|
-
"table",
|
|
376
|
-
"column",
|
|
377
|
-
"index",
|
|
378
|
-
"user",
|
|
379
|
-
"users",
|
|
380
|
-
"values",
|
|
381
|
-
"update",
|
|
382
|
-
"insert",
|
|
383
|
-
"delete",
|
|
384
|
-
"create",
|
|
385
|
-
"drop",
|
|
386
|
-
"alter",
|
|
387
|
-
"truncate",
|
|
388
|
-
"grant",
|
|
389
|
-
"revoke",
|
|
390
|
-
"exec",
|
|
391
|
-
"execute",
|
|
392
|
-
"union",
|
|
393
|
-
"intersect",
|
|
394
|
-
"except",
|
|
395
|
-
"case",
|
|
396
|
-
"when",
|
|
397
|
-
"then",
|
|
398
|
-
"else",
|
|
399
|
-
"end",
|
|
400
|
-
"null",
|
|
401
|
-
"true",
|
|
402
|
-
"false",
|
|
403
|
-
"is",
|
|
404
|
-
"exists",
|
|
405
|
-
"all",
|
|
406
|
-
"any",
|
|
407
|
-
"some"
|
|
408
|
-
]);
|
|
409
|
-
var SQL_KEYWORDS = SQL_RESERVED_WORDS;
|
|
410
|
-
var DEFAULT_WHERE_CLAUSE = "1=1";
|
|
411
|
-
var SPECIAL_FIELDS = Object.freeze({
|
|
412
|
-
ID: "id"
|
|
413
|
-
});
|
|
414
|
-
var SQL_TEMPLATES = Object.freeze({
|
|
415
|
-
PUBLIC_SCHEMA: "public",
|
|
416
|
-
WHERE: "WHERE",
|
|
417
|
-
SELECT: "SELECT",
|
|
418
|
-
FROM: "FROM",
|
|
419
|
-
ORDER_BY: "ORDER BY",
|
|
420
|
-
GROUP_BY: "GROUP BY",
|
|
421
|
-
HAVING: "HAVING",
|
|
422
|
-
LIMIT: "LIMIT",
|
|
423
|
-
OFFSET: "OFFSET",
|
|
424
|
-
COUNT_ALL: "COUNT(*)",
|
|
425
|
-
AS: "AS",
|
|
426
|
-
DISTINCT_ON: "DISTINCT ON",
|
|
427
|
-
IS_NULL: "IS NULL",
|
|
428
|
-
IS_NOT_NULL: "IS NOT NULL",
|
|
429
|
-
LIKE: "LIKE",
|
|
430
|
-
AND: "AND",
|
|
431
|
-
OR: "OR",
|
|
432
|
-
NOT: "NOT"
|
|
433
|
-
});
|
|
434
|
-
var SCHEMA_PREFIXES = Object.freeze({
|
|
435
|
-
INTERNAL: "@",
|
|
436
|
-
COMMENT: "//"
|
|
437
|
-
});
|
|
438
|
-
var Ops = Object.freeze({
|
|
439
|
-
EQUALS: "equals",
|
|
440
|
-
NOT: "not",
|
|
441
|
-
GT: "gt",
|
|
442
|
-
GTE: "gte",
|
|
443
|
-
LT: "lt",
|
|
444
|
-
LTE: "lte",
|
|
445
|
-
IN: "in",
|
|
446
|
-
NOT_IN: "notIn",
|
|
447
|
-
CONTAINS: "contains",
|
|
448
|
-
STARTS_WITH: "startsWith",
|
|
449
|
-
ENDS_WITH: "endsWith",
|
|
450
|
-
HAS: "has",
|
|
451
|
-
HAS_SOME: "hasSome",
|
|
452
|
-
HAS_EVERY: "hasEvery",
|
|
453
|
-
IS_EMPTY: "isEmpty",
|
|
454
|
-
PATH: "path",
|
|
455
|
-
STRING_CONTAINS: "string_contains",
|
|
456
|
-
STRING_STARTS_WITH: "string_starts_with",
|
|
457
|
-
STRING_ENDS_WITH: "string_ends_with"
|
|
458
|
-
});
|
|
459
|
-
var LogicalOps = Object.freeze({
|
|
460
|
-
AND: "AND",
|
|
461
|
-
OR: "OR",
|
|
462
|
-
NOT: "NOT"
|
|
463
|
-
});
|
|
464
|
-
var RelationFilters = Object.freeze({
|
|
465
|
-
SOME: "some",
|
|
466
|
-
EVERY: "every",
|
|
467
|
-
NONE: "none"
|
|
468
|
-
});
|
|
469
|
-
var Modes = Object.freeze({
|
|
470
|
-
INSENSITIVE: "insensitive",
|
|
471
|
-
DEFAULT: "default"
|
|
472
|
-
});
|
|
473
|
-
var Wildcards = Object.freeze({
|
|
474
|
-
[Ops.CONTAINS]: (v) => `%${v}%`,
|
|
475
|
-
[Ops.STARTS_WITH]: (v) => `${v}%`,
|
|
476
|
-
[Ops.ENDS_WITH]: (v) => `%${v}`
|
|
477
|
-
});
|
|
478
|
-
var REGEX_CACHE = {
|
|
479
|
-
VALID_IDENTIFIER: /^[a-z_][a-z0-9_]*$/
|
|
480
|
-
};
|
|
481
|
-
var LIMITS = Object.freeze({
|
|
482
|
-
MAX_QUERY_DEPTH: 50,
|
|
483
|
-
MAX_ARRAY_SIZE: 1e4,
|
|
484
|
-
MAX_STRING_LENGTH: 1e4
|
|
485
|
-
});
|
|
486
|
-
|
|
487
476
|
// src/builder/shared/validators/type-guards.ts
|
|
488
477
|
function isNotNullish(value) {
|
|
489
478
|
return value !== null && value !== void 0;
|
|
@@ -569,6 +558,19 @@ function getRelationFieldSet(model) {
|
|
|
569
558
|
RELATION_SET_CACHE.set(model, s);
|
|
570
559
|
return s;
|
|
571
560
|
}
|
|
561
|
+
var COLUMN_MAP_CACHE = /* @__PURE__ */ new WeakMap();
|
|
562
|
+
function getColumnMap(model) {
|
|
563
|
+
const cached = COLUMN_MAP_CACHE.get(model);
|
|
564
|
+
if (cached) return cached;
|
|
565
|
+
const map = /* @__PURE__ */ new Map();
|
|
566
|
+
for (const f of model.fields) {
|
|
567
|
+
if (!f.isRelation) {
|
|
568
|
+
map.set(f.name, f.dbName || f.name);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
COLUMN_MAP_CACHE.set(model, map);
|
|
572
|
+
return map;
|
|
573
|
+
}
|
|
572
574
|
|
|
573
575
|
// src/builder/shared/validators/sql-validators.ts
|
|
574
576
|
function isValidWhereClause(clause) {
|
|
@@ -956,27 +958,10 @@ function quote(id) {
|
|
|
956
958
|
}
|
|
957
959
|
return id;
|
|
958
960
|
}
|
|
959
|
-
function pickDbFieldName(field) {
|
|
960
|
-
const candidates = [
|
|
961
|
-
field == null ? void 0 : field.dbName,
|
|
962
|
-
field == null ? void 0 : field.columnName,
|
|
963
|
-
field == null ? void 0 : field.databaseName,
|
|
964
|
-
field == null ? void 0 : field.mappedName
|
|
965
|
-
];
|
|
966
|
-
for (const c of candidates) {
|
|
967
|
-
if (typeof c === "string") {
|
|
968
|
-
const s = c.trim();
|
|
969
|
-
if (s.length > 0) return s;
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
return void 0;
|
|
973
|
-
}
|
|
974
961
|
function resolveColumnName(model, fieldName) {
|
|
975
|
-
var _a;
|
|
976
962
|
if (!model) return fieldName;
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
return (_a = pickDbFieldName(f)) != null ? _a : fieldName;
|
|
963
|
+
const columnMap = getColumnMap(model);
|
|
964
|
+
return columnMap.get(fieldName) || fieldName;
|
|
980
965
|
}
|
|
981
966
|
function quoteColumn(model, fieldName) {
|
|
982
967
|
return quote(resolveColumnName(model, fieldName));
|
|
@@ -1134,1570 +1119,1570 @@ function joinCondition(field, parentModel, childModel, parentAlias, childAlias)
|
|
|
1134
1119
|
function getModelByName(schemas, name) {
|
|
1135
1120
|
return schemas.find((m) => m.name === name);
|
|
1136
1121
|
}
|
|
1137
|
-
function
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
);
|
|
1141
|
-
if (
|
|
1142
|
-
|
|
1143
|
-
for (const [subOp, subVal] of entries) {
|
|
1144
|
-
const sub = buildOp(expr, subOp, subVal, params, dialect);
|
|
1145
|
-
if (sub && sub.trim().length > 0) clauses.push(`(${sub})`);
|
|
1146
|
-
}
|
|
1147
|
-
if (clauses.length === 0) return "";
|
|
1148
|
-
if (clauses.length === 1) return `${SQL_TEMPLATES.NOT} ${clauses[0]}`;
|
|
1149
|
-
return `${SQL_TEMPLATES.NOT} (${clauses.join(separator)})`;
|
|
1150
|
-
}
|
|
1151
|
-
function buildScalarOperator(expr, op, val, params, mode, fieldType, dialect) {
|
|
1152
|
-
if (val === void 0) return "";
|
|
1153
|
-
if (val === null) {
|
|
1154
|
-
return handleNullValue(expr, op);
|
|
1155
|
-
}
|
|
1156
|
-
if (op === Ops.NOT && isPlainObject(val)) {
|
|
1157
|
-
return handleNotOperator(expr, val, params, mode, fieldType, dialect);
|
|
1158
|
-
}
|
|
1159
|
-
if (op === Ops.NOT) {
|
|
1160
|
-
const placeholder = params.addAuto(val);
|
|
1161
|
-
return `${expr} <> ${placeholder}`;
|
|
1122
|
+
function normalizeIntLike(name, v, opts = {}) {
|
|
1123
|
+
var _a, _b;
|
|
1124
|
+
if (!isNotNullish(v)) return void 0;
|
|
1125
|
+
if (schemaParser.isDynamicParameter(v)) return v;
|
|
1126
|
+
if (typeof v !== "number" || !Number.isFinite(v) || !Number.isInteger(v)) {
|
|
1127
|
+
throw new Error(`${name} must be an integer`);
|
|
1162
1128
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1129
|
+
const min = (_a = opts.min) != null ? _a : 0;
|
|
1130
|
+
const allowZero = (_b = opts.allowZero) != null ? _b : true;
|
|
1131
|
+
if (!allowZero && v === 0) {
|
|
1132
|
+
throw new Error(`${name} must be > 0`);
|
|
1166
1133
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
Ops.STARTS_WITH,
|
|
1170
|
-
Ops.ENDS_WITH
|
|
1171
|
-
]);
|
|
1172
|
-
if (STRING_LIKE_OPS.has(op)) {
|
|
1173
|
-
if (!isNotNullish(dialect)) {
|
|
1174
|
-
throw createError(`Like operators require a SQL dialect`, {
|
|
1175
|
-
operator: op
|
|
1176
|
-
});
|
|
1177
|
-
}
|
|
1178
|
-
return handleLikeOperator(expr, op, val, params, mode, dialect);
|
|
1134
|
+
if (v < min) {
|
|
1135
|
+
throw new Error(`${name} must be >= ${min}`);
|
|
1179
1136
|
}
|
|
1180
|
-
if (
|
|
1181
|
-
|
|
1182
|
-
throw createError(`IN operators require a SQL dialect`, { operator: op });
|
|
1183
|
-
}
|
|
1184
|
-
return handleInOperator(expr, op, val, params, dialect);
|
|
1137
|
+
if (typeof opts.max === "number" && v > opts.max) {
|
|
1138
|
+
throw new Error(`${name} must be <= ${opts.max}`);
|
|
1185
1139
|
}
|
|
1186
|
-
return
|
|
1187
|
-
}
|
|
1188
|
-
function handleNullValue(expr, op) {
|
|
1189
|
-
if (op === Ops.EQUALS) return `${expr} ${SQL_TEMPLATES.IS_NULL}`;
|
|
1190
|
-
if (op === Ops.NOT) return `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1191
|
-
throw createError(`Operator '${op}' doesn't support null`, { operator: op });
|
|
1192
|
-
}
|
|
1193
|
-
function normalizeMode(v) {
|
|
1194
|
-
if (v === Modes.INSENSITIVE) return Modes.INSENSITIVE;
|
|
1195
|
-
if (v === Modes.DEFAULT) return Modes.DEFAULT;
|
|
1196
|
-
return void 0;
|
|
1140
|
+
return v;
|
|
1197
1141
|
}
|
|
1198
|
-
function
|
|
1199
|
-
const
|
|
1200
|
-
const
|
|
1201
|
-
return
|
|
1202
|
-
|
|
1203
|
-
val,
|
|
1204
|
-
params,
|
|
1205
|
-
dialect,
|
|
1206
|
-
(e, subOp, subVal, p, d) => buildScalarOperator(e, subOp, subVal, p, effectiveMode, fieldType, d),
|
|
1207
|
-
` ${SQL_TEMPLATES.AND} `
|
|
1208
|
-
);
|
|
1142
|
+
function scopeName(scope, dynamicName) {
|
|
1143
|
+
const s = String(scope).trim();
|
|
1144
|
+
const dn = String(dynamicName).trim();
|
|
1145
|
+
if (s.length === 0) return dn;
|
|
1146
|
+
return `${s}:${dn}`;
|
|
1209
1147
|
}
|
|
1210
|
-
function
|
|
1211
|
-
if (
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
return `('%' || ${placeholder} || '%')`;
|
|
1215
|
-
case Ops.STARTS_WITH:
|
|
1216
|
-
return `(${placeholder} || '%')`;
|
|
1217
|
-
case Ops.ENDS_WITH:
|
|
1218
|
-
return `('%' || ${placeholder})`;
|
|
1219
|
-
default:
|
|
1220
|
-
return placeholder;
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
switch (op) {
|
|
1224
|
-
case Ops.CONTAINS:
|
|
1225
|
-
return `('%' || ${placeholder} || '%')`;
|
|
1226
|
-
case Ops.STARTS_WITH:
|
|
1227
|
-
return `(${placeholder} || '%')`;
|
|
1228
|
-
case Ops.ENDS_WITH:
|
|
1229
|
-
return `('%' || ${placeholder})`;
|
|
1230
|
-
default:
|
|
1231
|
-
return placeholder;
|
|
1148
|
+
function addAutoScoped(params, value, scope) {
|
|
1149
|
+
if (schemaParser.isDynamicParameter(value)) {
|
|
1150
|
+
const dn = schemaParser.extractDynamicName(value);
|
|
1151
|
+
return params.add(void 0, scopeName(scope, dn));
|
|
1232
1152
|
}
|
|
1153
|
+
return params.add(value);
|
|
1233
1154
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1155
|
+
|
|
1156
|
+
// src/builder/shared/order-by-utils.ts
|
|
1157
|
+
var flipNulls = (v) => {
|
|
1158
|
+
const s = String(v).toLowerCase();
|
|
1159
|
+
if (s === "first") return "last";
|
|
1160
|
+
if (s === "last") return "first";
|
|
1161
|
+
return v;
|
|
1162
|
+
};
|
|
1163
|
+
var flipSortString = (v) => {
|
|
1164
|
+
if (typeof v !== "string") return v;
|
|
1165
|
+
const s = v.toLowerCase();
|
|
1166
|
+
if (s === "asc") return "desc";
|
|
1167
|
+
if (s === "desc") return "asc";
|
|
1168
|
+
return v;
|
|
1169
|
+
};
|
|
1170
|
+
var getNextSort = (sortRaw) => {
|
|
1171
|
+
if (typeof sortRaw !== "string") return sortRaw;
|
|
1172
|
+
const s = sortRaw.toLowerCase();
|
|
1173
|
+
if (s === "asc") return "desc";
|
|
1174
|
+
if (s === "desc") return "asc";
|
|
1175
|
+
return sortRaw;
|
|
1176
|
+
};
|
|
1177
|
+
var flipObjectSort = (obj) => {
|
|
1178
|
+
const sortRaw = obj.sort;
|
|
1179
|
+
const out = __spreadProps(__spreadValues({}, obj), { sort: getNextSort(sortRaw) });
|
|
1180
|
+
const nullsRaw = obj.nulls;
|
|
1181
|
+
if (typeof nullsRaw === "string") {
|
|
1182
|
+
out.nulls = flipNulls(nullsRaw);
|
|
1243
1183
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1184
|
+
return out;
|
|
1185
|
+
};
|
|
1186
|
+
var flipValue = (v) => {
|
|
1187
|
+
if (typeof v === "string") return flipSortString(v);
|
|
1188
|
+
if (isPlainObject(v)) return flipObjectSort(v);
|
|
1189
|
+
return v;
|
|
1190
|
+
};
|
|
1191
|
+
var assertSingleFieldObject = (item) => {
|
|
1192
|
+
if (!isPlainObject(item)) {
|
|
1193
|
+
throw new Error("orderBy array entries must be objects");
|
|
1247
1194
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
if (val === void 0) return "";
|
|
1252
|
-
if (schemaParser.isDynamicParameter(val)) {
|
|
1253
|
-
const placeholder2 = params.addAuto(val);
|
|
1254
|
-
return op === Ops.IN ? inArray(expr, placeholder2, dialect) : notInArray(expr, placeholder2, dialect);
|
|
1195
|
+
const entries = Object.entries(item);
|
|
1196
|
+
if (entries.length !== 1) {
|
|
1197
|
+
throw new Error("orderBy array entries must have exactly one field");
|
|
1255
1198
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1199
|
+
return entries[0];
|
|
1200
|
+
};
|
|
1201
|
+
var flipOrderByArray = (orderBy) => {
|
|
1202
|
+
return orderBy.map((item) => {
|
|
1203
|
+
const [k, v] = assertSingleFieldObject(item);
|
|
1204
|
+
return { [k]: flipValue(v) };
|
|
1205
|
+
});
|
|
1206
|
+
};
|
|
1207
|
+
var flipOrderByObject = (orderBy) => {
|
|
1208
|
+
const out = {};
|
|
1209
|
+
for (const [k, v] of Object.entries(orderBy)) {
|
|
1210
|
+
out[k] = flipValue(v);
|
|
1261
1211
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1212
|
+
return out;
|
|
1213
|
+
};
|
|
1214
|
+
function reverseOrderByInput(orderBy) {
|
|
1215
|
+
if (!isNotNullish(orderBy)) return orderBy;
|
|
1216
|
+
if (Array.isArray(orderBy)) {
|
|
1217
|
+
return flipOrderByArray(orderBy);
|
|
1264
1218
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1219
|
+
if (isPlainObject(orderBy)) {
|
|
1220
|
+
return flipOrderByObject(orderBy);
|
|
1221
|
+
}
|
|
1222
|
+
throw new Error("orderBy must be an object or array of objects");
|
|
1268
1223
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
if (
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
const placeholder = params.addAuto(val);
|
|
1283
|
-
return `${expr} ${sqlOp} ${placeholder}`;
|
|
1284
|
-
}
|
|
1285
|
-
function buildArrayParam(val, params, dialect) {
|
|
1286
|
-
if (schemaParser.isDynamicParameter(val)) {
|
|
1287
|
-
return params.addAuto(val);
|
|
1224
|
+
var normalizePairs = (pairs, parseValue) => {
|
|
1225
|
+
return pairs.map(([field, rawValue]) => {
|
|
1226
|
+
const parsed = parseValue(rawValue, field);
|
|
1227
|
+
return {
|
|
1228
|
+
[field]: parsed.nulls !== void 0 ? { sort: parsed.direction, nulls: parsed.nulls } : parsed.direction
|
|
1229
|
+
};
|
|
1230
|
+
});
|
|
1231
|
+
};
|
|
1232
|
+
function normalizeOrderByInput(orderBy, parseValue) {
|
|
1233
|
+
if (!isNotNullish(orderBy)) return [];
|
|
1234
|
+
if (Array.isArray(orderBy)) {
|
|
1235
|
+
const pairs = orderBy.map(assertSingleFieldObject);
|
|
1236
|
+
return normalizePairs(pairs, parseValue);
|
|
1288
1237
|
}
|
|
1289
|
-
if (
|
|
1290
|
-
|
|
1238
|
+
if (isPlainObject(orderBy)) {
|
|
1239
|
+
return normalizePairs(Object.entries(orderBy), parseValue);
|
|
1291
1240
|
}
|
|
1292
|
-
|
|
1293
|
-
return params.add(paramValue);
|
|
1241
|
+
throw new Error("orderBy must be an object or array of objects");
|
|
1294
1242
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
if (op === Ops.EQUALS) {
|
|
1303
|
-
return handleArrayEquals(expr, val, params, cast, dialect);
|
|
1304
|
-
}
|
|
1305
|
-
if (op === Ops.NOT) {
|
|
1306
|
-
return handleArrayNot(expr, val, params, cast, dialect);
|
|
1307
|
-
}
|
|
1308
|
-
switch (op) {
|
|
1309
|
-
case Ops.HAS:
|
|
1310
|
-
return handleArrayHas(expr, val, params, cast, dialect);
|
|
1311
|
-
case Ops.HAS_SOME:
|
|
1312
|
-
return handleArrayHasSome(expr, val, params, cast, dialect);
|
|
1313
|
-
case Ops.HAS_EVERY:
|
|
1314
|
-
return handleArrayHasEvery(expr, val, params, cast, dialect);
|
|
1315
|
-
case Ops.IS_EMPTY:
|
|
1316
|
-
return handleArrayIsEmpty(expr, val, dialect);
|
|
1317
|
-
default:
|
|
1318
|
-
throw createError(`Unknown array operator: ${op}`, { operator: op });
|
|
1319
|
-
}
|
|
1243
|
+
|
|
1244
|
+
// src/builder/pagination.ts
|
|
1245
|
+
var MAX_LIMIT_OFFSET = 2147483647;
|
|
1246
|
+
function parseDirectionRaw(raw, errorLabel) {
|
|
1247
|
+
const s = String(raw).toLowerCase();
|
|
1248
|
+
if (s === "asc" || s === "desc") return s;
|
|
1249
|
+
throw new Error(`Invalid ${errorLabel}: ${raw}`);
|
|
1320
1250
|
}
|
|
1321
|
-
function
|
|
1322
|
-
if (
|
|
1323
|
-
|
|
1324
|
-
|
|
1251
|
+
function parseNullsRaw(raw, errorLabel) {
|
|
1252
|
+
if (!isNotNullish(raw)) return void 0;
|
|
1253
|
+
const s = String(raw).toLowerCase();
|
|
1254
|
+
if (s === "first" || s === "last") return s;
|
|
1255
|
+
throw new Error(`Invalid ${errorLabel}: ${raw}`);
|
|
1256
|
+
}
|
|
1257
|
+
function requireOrderByObject(v, errorPrefix) {
|
|
1258
|
+
if (!isPlainObject(v) || !("sort" in v)) {
|
|
1259
|
+
throw new Error(`${errorPrefix} must be 'asc' | 'desc' or { sort, nulls? }`);
|
|
1325
1260
|
}
|
|
1326
|
-
|
|
1327
|
-
return arrayEquals(expr, placeholder, cast, dialect);
|
|
1261
|
+
return v;
|
|
1328
1262
|
}
|
|
1329
|
-
function
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
} else {
|
|
1337
|
-
throw createError(`Array NOT only supports { equals: ... } shape`, {
|
|
1338
|
-
operator: Ops.NOT,
|
|
1339
|
-
value: val
|
|
1340
|
-
});
|
|
1263
|
+
function assertAllowedOrderByKeys(obj, fieldName) {
|
|
1264
|
+
const allowed = /* @__PURE__ */ new Set(["sort", "nulls"]);
|
|
1265
|
+
for (const k of Object.keys(obj)) {
|
|
1266
|
+
if (!allowed.has(k)) {
|
|
1267
|
+
throw new Error(
|
|
1268
|
+
fieldName ? `Unsupported orderBy key '${k}' for field '${fieldName}'` : `Unsupported orderBy key '${k}'`
|
|
1269
|
+
);
|
|
1341
1270
|
}
|
|
1342
1271
|
}
|
|
1343
|
-
if (target === null) {
|
|
1344
|
-
return `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1345
|
-
}
|
|
1346
|
-
if (isEmptyArray(target)) {
|
|
1347
|
-
return arrayIsNotEmpty(expr, dialect);
|
|
1348
|
-
}
|
|
1349
|
-
const placeholder = buildArrayParam(target, params, dialect);
|
|
1350
|
-
return `${SQL_TEMPLATES.NOT} (${arrayEquals(expr, placeholder, cast, dialect)})`;
|
|
1351
1272
|
}
|
|
1352
|
-
function
|
|
1353
|
-
|
|
1354
|
-
if (
|
|
1355
|
-
|
|
1356
|
-
operator: Ops.HAS,
|
|
1357
|
-
value: val
|
|
1358
|
-
});
|
|
1359
|
-
}
|
|
1360
|
-
if (!schemaParser.isDynamicParameter(val) && Array.isArray(val)) {
|
|
1361
|
-
throw createError(`has requires scalar value (single element), not array`, {
|
|
1362
|
-
operator: Ops.HAS,
|
|
1363
|
-
value: val
|
|
1364
|
-
});
|
|
1365
|
-
}
|
|
1366
|
-
if (isPlainObject(val)) {
|
|
1367
|
-
throw createError(`has requires scalar value`, {
|
|
1368
|
-
operator: Ops.HAS,
|
|
1369
|
-
value: val
|
|
1370
|
-
});
|
|
1273
|
+
function parseOrderByValue(v, fieldName) {
|
|
1274
|
+
const errorPrefix = fieldName ? `orderBy for '${fieldName}'` : "orderBy value";
|
|
1275
|
+
if (typeof v === "string") {
|
|
1276
|
+
return { direction: parseDirectionRaw(v, `${errorPrefix} direction`) };
|
|
1371
1277
|
}
|
|
1372
|
-
const
|
|
1373
|
-
|
|
1278
|
+
const obj = requireOrderByObject(v, errorPrefix);
|
|
1279
|
+
const direction = parseDirectionRaw(obj.sort, `${errorPrefix}.sort`);
|
|
1280
|
+
const nulls = parseNullsRaw(obj.nulls, `${errorPrefix}.nulls`);
|
|
1281
|
+
assertAllowedOrderByKeys(obj, fieldName);
|
|
1282
|
+
return { direction, nulls };
|
|
1374
1283
|
}
|
|
1375
|
-
function
|
|
1376
|
-
if (
|
|
1377
|
-
|
|
1378
|
-
const placeholder2 = params.addAuto(val);
|
|
1379
|
-
return arrayOverlaps(expr, placeholder2, cast, dialect);
|
|
1284
|
+
function normalizeFiniteInteger(name, v) {
|
|
1285
|
+
if (typeof v !== "number" || !Number.isFinite(v) || !Number.isInteger(v)) {
|
|
1286
|
+
throw new Error(`${name} must be an integer`);
|
|
1380
1287
|
}
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1288
|
+
return v;
|
|
1289
|
+
}
|
|
1290
|
+
function normalizeNonNegativeInt(name, v) {
|
|
1291
|
+
if (schemaParser.isDynamicParameter(v)) return v;
|
|
1292
|
+
const n = normalizeFiniteInteger(name, v);
|
|
1293
|
+
if (n < 0) {
|
|
1294
|
+
throw new Error(`${name} must be >= 0`);
|
|
1386
1295
|
}
|
|
1387
|
-
if (
|
|
1388
|
-
throw
|
|
1389
|
-
`Array too large (${val.length} elements, max ${LIMITS.MAX_ARRAY_SIZE})`,
|
|
1390
|
-
{ operator: Ops.HAS_SOME, value: `[${val.length} items]` }
|
|
1391
|
-
);
|
|
1296
|
+
if (n > MAX_LIMIT_OFFSET) {
|
|
1297
|
+
throw new Error(`${name} must be <= ${MAX_LIMIT_OFFSET}`);
|
|
1392
1298
|
}
|
|
1393
|
-
|
|
1394
|
-
const paramValue = prepareArrayParam(val, dialect);
|
|
1395
|
-
const placeholder = params.add(paramValue);
|
|
1396
|
-
return arrayOverlaps(expr, placeholder, cast, dialect);
|
|
1299
|
+
return n;
|
|
1397
1300
|
}
|
|
1398
|
-
function
|
|
1399
|
-
|
|
1400
|
-
const placeholder = buildArrayParam(val, params, dialect);
|
|
1401
|
-
return arrayContainsAll(expr, placeholder, cast, dialect);
|
|
1301
|
+
function hasNonNullishProp(v, key) {
|
|
1302
|
+
return isPlainObject(v) && key in v && isNotNullish(v[key]);
|
|
1402
1303
|
}
|
|
1403
|
-
function
|
|
1404
|
-
if (
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1304
|
+
function normalizeIntegerOrDynamic(name, v) {
|
|
1305
|
+
if (schemaParser.isDynamicParameter(v)) return v;
|
|
1306
|
+
return normalizeFiniteInteger(name, v);
|
|
1307
|
+
}
|
|
1308
|
+
function readSkipTake(relArgs) {
|
|
1309
|
+
const hasSkip = hasNonNullishProp(relArgs, "skip");
|
|
1310
|
+
const hasTake = hasNonNullishProp(relArgs, "take");
|
|
1311
|
+
if (!hasSkip && !hasTake) {
|
|
1312
|
+
return {
|
|
1313
|
+
hasSkip: false,
|
|
1314
|
+
hasTake: false,
|
|
1315
|
+
skipVal: void 0,
|
|
1316
|
+
takeVal: void 0
|
|
1317
|
+
};
|
|
1409
1318
|
}
|
|
1410
|
-
|
|
1319
|
+
const obj = relArgs;
|
|
1320
|
+
const skipVal = hasSkip ? normalizeNonNegativeInt("skip", obj.skip) : void 0;
|
|
1321
|
+
const takeVal = hasTake ? normalizeIntegerOrDynamic("take", obj.take) : void 0;
|
|
1322
|
+
return { hasSkip, hasTake, skipVal, takeVal };
|
|
1411
1323
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1324
|
+
function buildOrderByFragment(entries, alias, dialect, model) {
|
|
1325
|
+
if (entries.length === 0) return "";
|
|
1326
|
+
const out = [];
|
|
1327
|
+
for (const e of entries) {
|
|
1328
|
+
const dir = e.direction.toUpperCase();
|
|
1329
|
+
const c = col(alias, e.field, model);
|
|
1330
|
+
if (dialect === "postgres") {
|
|
1331
|
+
const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
|
|
1332
|
+
out.push(`${c} ${dir}${nulls}`);
|
|
1333
|
+
continue;
|
|
1422
1334
|
}
|
|
1423
|
-
if (
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
);
|
|
1335
|
+
if (isNotNullish(e.nulls)) {
|
|
1336
|
+
const isNullExpr = `(${c} IS NULL)`;
|
|
1337
|
+
const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
|
|
1338
|
+
out.push(`${isNullExpr} ${nullRankDir}`);
|
|
1339
|
+
out.push(`${c} ${dir}`);
|
|
1340
|
+
continue;
|
|
1428
1341
|
}
|
|
1342
|
+
out.push(`${c} ${dir}`);
|
|
1429
1343
|
}
|
|
1344
|
+
return out.join(SQL_SEPARATORS.ORDER_BY);
|
|
1430
1345
|
}
|
|
1431
|
-
function
|
|
1432
|
-
if (
|
|
1433
|
-
|
|
1434
|
-
return handleJsonPath(expr, val, params, dialect);
|
|
1435
|
-
}
|
|
1436
|
-
const jsonWildcards = {
|
|
1437
|
-
[Ops.STRING_CONTAINS]: (v) => `%${v}%`,
|
|
1438
|
-
[Ops.STRING_STARTS_WITH]: (v) => `${v}%`,
|
|
1439
|
-
[Ops.STRING_ENDS_WITH]: (v) => `%${v}`
|
|
1440
|
-
};
|
|
1441
|
-
if (op in jsonWildcards) {
|
|
1442
|
-
return handleJsonWildcard(expr, op, val, params, jsonWildcards, dialect);
|
|
1346
|
+
function defaultNullsFor(dialect, direction) {
|
|
1347
|
+
if (dialect === "postgres") {
|
|
1348
|
+
return direction === "asc" ? "last" : "first";
|
|
1443
1349
|
}
|
|
1444
|
-
|
|
1350
|
+
return direction === "asc" ? "first" : "last";
|
|
1445
1351
|
}
|
|
1446
|
-
function
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1352
|
+
function ensureCursorFieldsInOrder(orderEntries, cursorEntries) {
|
|
1353
|
+
const existing = /* @__PURE__ */ new Map();
|
|
1354
|
+
for (const e of orderEntries) existing.set(e.field, e);
|
|
1355
|
+
const out = [...orderEntries];
|
|
1356
|
+
for (const [field] of cursorEntries) {
|
|
1357
|
+
if (!existing.has(field)) {
|
|
1358
|
+
out.push({ field, direction: "asc" });
|
|
1359
|
+
existing.set(field, out[out.length - 1]);
|
|
1360
|
+
}
|
|
1453
1361
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
["<", v.lt],
|
|
1461
|
-
["<=", v.lte]
|
|
1462
|
-
];
|
|
1463
|
-
const ops = rawOps.filter(
|
|
1464
|
-
([, value]) => value !== void 0
|
|
1465
|
-
);
|
|
1466
|
-
if (ops.length === 0) {
|
|
1467
|
-
throw createError("JSON path query missing comparison operator", {
|
|
1468
|
-
operator: Ops.PATH
|
|
1469
|
-
});
|
|
1362
|
+
return out;
|
|
1363
|
+
}
|
|
1364
|
+
function buildCursorFilterParts(cursor, cursorAlias, params, model) {
|
|
1365
|
+
const entries = Object.entries(cursor);
|
|
1366
|
+
if (entries.length === 0) {
|
|
1367
|
+
throw new Error("cursor must have at least one field");
|
|
1470
1368
|
}
|
|
1369
|
+
const placeholdersByField = /* @__PURE__ */ new Map();
|
|
1471
1370
|
const parts = [];
|
|
1472
|
-
for (const [
|
|
1371
|
+
for (const [field, value] of entries) {
|
|
1372
|
+
const c = `${cursorAlias}.${quote(field)}`;
|
|
1473
1373
|
if (value === null) {
|
|
1474
|
-
|
|
1475
|
-
parts.push(`${base2} ${SQL_TEMPLATES.IS_NULL}`);
|
|
1374
|
+
parts.push(`${c} IS NULL`);
|
|
1476
1375
|
continue;
|
|
1477
1376
|
}
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
parts.push(`${
|
|
1481
|
-
}
|
|
1482
|
-
return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
|
|
1483
|
-
}
|
|
1484
|
-
function handleJsonWildcard(expr, op, val, params, wildcards, dialect) {
|
|
1485
|
-
if (!isNotNullish(val)) {
|
|
1486
|
-
throw createError(`JSON string operator requires non-null value`, {
|
|
1487
|
-
operator: op,
|
|
1488
|
-
value: val
|
|
1489
|
-
});
|
|
1490
|
-
}
|
|
1491
|
-
if (isPlainObject(val) || Array.isArray(val)) {
|
|
1492
|
-
throw createError(`JSON string operator requires scalar value`, {
|
|
1493
|
-
operator: op,
|
|
1494
|
-
value: val
|
|
1495
|
-
});
|
|
1496
|
-
}
|
|
1497
|
-
const strVal = String(val);
|
|
1498
|
-
if (strVal.length > LIMITS.MAX_STRING_LENGTH) {
|
|
1499
|
-
throw createError(
|
|
1500
|
-
`String too long (${strVal.length} chars, max ${LIMITS.MAX_STRING_LENGTH})`,
|
|
1501
|
-
{ operator: op }
|
|
1502
|
-
);
|
|
1377
|
+
const ph = addAutoScoped(params, value, `cursor.filter.${field}`);
|
|
1378
|
+
placeholdersByField.set(field, ph);
|
|
1379
|
+
parts.push(`${c} = ${ph}`);
|
|
1503
1380
|
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1381
|
+
return {
|
|
1382
|
+
whereSql: parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`,
|
|
1383
|
+
placeholdersByField
|
|
1384
|
+
};
|
|
1507
1385
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
function isListRelation(fieldType) {
|
|
1512
|
-
return typeof fieldType === "string" && fieldType.endsWith("[]");
|
|
1386
|
+
function cursorValueExpr(tableName, cursorAlias, cursorWhereSql, field, model) {
|
|
1387
|
+
const colName = quote(field);
|
|
1388
|
+
return `(SELECT ${cursorAlias}.${colName} ${SQL_TEMPLATES.FROM} ${tableName} ${cursorAlias} ${SQL_TEMPLATES.WHERE} ${cursorWhereSql} ${SQL_TEMPLATES.LIMIT} 1)`;
|
|
1513
1389
|
}
|
|
1514
|
-
function
|
|
1515
|
-
|
|
1516
|
-
const fkFields = normalizeKeyList(field.foreignKey);
|
|
1517
|
-
if (isLocal) {
|
|
1518
|
-
if (fkFields.length === 0) {
|
|
1519
|
-
throw createError(`Relation '${field.name}' is missing foreignKey`, {
|
|
1520
|
-
field: field.name
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1523
|
-
const parts = fkFields.map((fk) => {
|
|
1524
|
-
const safe = fk.replace(/"/g, '""');
|
|
1525
|
-
const expr = `${parentAlias}."${safe}"`;
|
|
1526
|
-
return wantNull ? `${expr} ${SQL_TEMPLATES.IS_NULL}` : `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1527
|
-
});
|
|
1528
|
-
if (parts.length === 1) return parts[0];
|
|
1529
|
-
return wantNull ? `(${parts.join(" OR ")})` : `(${parts.join(" AND ")})`;
|
|
1530
|
-
}
|
|
1531
|
-
const existsSql = `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias} ${SQL_TEMPLATES.WHERE} ${join3})`;
|
|
1532
|
-
return wantNull ? `${SQL_TEMPLATES.NOT} ${existsSql}` : existsSql;
|
|
1390
|
+
function buildCursorRowExistsExpr(tableName, cursorAlias, cursorWhereSql) {
|
|
1391
|
+
return `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${tableName} ${cursorAlias} ${SQL_TEMPLATES.WHERE} ${cursorWhereSql} ${SQL_TEMPLATES.LIMIT} 1)`;
|
|
1533
1392
|
}
|
|
1534
|
-
function
|
|
1535
|
-
|
|
1536
|
-
return `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias}${joins} ${SQL_TEMPLATES.WHERE} ${join3} ${SQL_TEMPLATES.AND} ${sub.clause})`;
|
|
1393
|
+
function buildCursorEqualityExpr(columnExpr, valueExpr) {
|
|
1394
|
+
return `((${valueExpr} IS NULL AND ${columnExpr} IS NULL) OR (${valueExpr} IS NOT NULL AND ${columnExpr} = ${valueExpr}))`;
|
|
1537
1395
|
}
|
|
1538
|
-
function
|
|
1539
|
-
const
|
|
1540
|
-
|
|
1396
|
+
function buildCursorInequalityExpr(columnExpr, direction, nulls, valueExpr) {
|
|
1397
|
+
const op = direction === "asc" ? ">" : "<";
|
|
1398
|
+
if (nulls === "first") {
|
|
1399
|
+
return `(CASE WHEN ${valueExpr} IS NULL THEN (${columnExpr} IS NOT NULL) ELSE (${columnExpr} ${op} ${valueExpr}) END)`;
|
|
1400
|
+
}
|
|
1401
|
+
return `(CASE WHEN ${valueExpr} IS NULL THEN 0=1 ELSE ((${columnExpr} ${op} ${valueExpr}) OR (${columnExpr} IS NULL)) END)`;
|
|
1541
1402
|
}
|
|
1542
|
-
function
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
if (noneValue !== void 0 && noneValue !== null) {
|
|
1555
|
-
const sub = whereBuilder.build(noneValue, __spreadProps(__spreadValues({}, ctx), {
|
|
1556
|
-
alias: relAlias,
|
|
1557
|
-
model: relModel,
|
|
1558
|
-
path: [...ctx.path, fieldName, RelationFilters.NONE],
|
|
1559
|
-
isSubquery: true,
|
|
1560
|
-
depth: ctx.depth + 1
|
|
1561
|
-
}));
|
|
1562
|
-
const isEmptyFilter = isPlainObject(noneValue) && Object.keys(noneValue).length === 0;
|
|
1563
|
-
const canOptimize = !ctx.isSubquery && isEmptyFilter && sub.clause === DEFAULT_WHERE_CLAUSE && sub.joins.length === 0;
|
|
1564
|
-
if (canOptimize) {
|
|
1565
|
-
const checkField = relModel.fields.find(
|
|
1566
|
-
(f) => !f.isRelation && f.isRequired && f.name !== "id"
|
|
1567
|
-
) || relModel.fields.find((f) => !f.isRelation && f.name === "id");
|
|
1568
|
-
if (checkField) {
|
|
1569
|
-
const leftJoinSql = `LEFT JOIN ${relTable} ${relAlias} ON ${join3}`;
|
|
1570
|
-
const whereClause = `${relAlias}.${quote(checkField.name)} IS NULL`;
|
|
1571
|
-
return Object.freeze({
|
|
1572
|
-
clause: whereClause,
|
|
1573
|
-
joins: [leftJoinSql]
|
|
1574
|
-
});
|
|
1575
|
-
}
|
|
1403
|
+
function buildOuterCursorMatch(cursor, outerAlias, placeholdersByField, params, model) {
|
|
1404
|
+
const parts = [];
|
|
1405
|
+
for (const [field, value] of Object.entries(cursor)) {
|
|
1406
|
+
const c = col(outerAlias, field, model);
|
|
1407
|
+
if (value === null) {
|
|
1408
|
+
parts.push(`${c} IS NULL`);
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
const existing = placeholdersByField.get(field);
|
|
1412
|
+
if (typeof existing === "string" && existing.length > 0) {
|
|
1413
|
+
parts.push(`${c} = ${existing}`);
|
|
1414
|
+
continue;
|
|
1576
1415
|
}
|
|
1416
|
+
const ph = addAutoScoped(params, value, `cursor.outerMatch.${field}`);
|
|
1417
|
+
parts.push(`${c} = ${ph}`);
|
|
1577
1418
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1419
|
+
return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
|
|
1420
|
+
}
|
|
1421
|
+
function buildOrderEntries(orderBy) {
|
|
1422
|
+
const normalized = normalizeOrderByInput(orderBy, parseOrderByValue);
|
|
1423
|
+
const entries = [];
|
|
1424
|
+
for (const item of normalized) {
|
|
1425
|
+
for (const [field, value] of Object.entries(item)) {
|
|
1426
|
+
if (typeof value === "string") {
|
|
1427
|
+
entries.push({ field, direction: value });
|
|
1428
|
+
} else {
|
|
1429
|
+
entries.push({
|
|
1430
|
+
field,
|
|
1431
|
+
direction: value.sort,
|
|
1432
|
+
nulls: value.nulls
|
|
1433
|
+
});
|
|
1592
1434
|
}
|
|
1593
1435
|
}
|
|
1594
|
-
];
|
|
1595
|
-
const clauses = [];
|
|
1596
|
-
for (const { key, wrap } of filters) {
|
|
1597
|
-
const raw = value[key];
|
|
1598
|
-
if (raw === void 0 || raw === null) continue;
|
|
1599
|
-
const sub = whereBuilder.build(raw, __spreadProps(__spreadValues({}, ctx), {
|
|
1600
|
-
alias: relAlias,
|
|
1601
|
-
model: relModel,
|
|
1602
|
-
path: [...ctx.path, fieldName, key],
|
|
1603
|
-
isSubquery: true,
|
|
1604
|
-
depth: ctx.depth + 1
|
|
1605
|
-
}));
|
|
1606
|
-
const j = sub.joins.length > 0 ? ` ${sub.joins.join(" ")}` : "";
|
|
1607
|
-
clauses.push(wrap(sub.clause, j));
|
|
1608
|
-
}
|
|
1609
|
-
if (clauses.length === 0) {
|
|
1610
|
-
throw createError(
|
|
1611
|
-
`List relation '${fieldName}' requires one of { some, every, none }`,
|
|
1612
|
-
{ field: fieldName, path: ctx.path, modelName: ctx.model.name }
|
|
1613
|
-
);
|
|
1614
1436
|
}
|
|
1615
|
-
return
|
|
1616
|
-
clause: clauses.join(SQL_SEPARATORS.CONDITION_AND),
|
|
1617
|
-
joins: NO_JOINS
|
|
1618
|
-
});
|
|
1437
|
+
return entries;
|
|
1619
1438
|
}
|
|
1620
|
-
function
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
field,
|
|
1627
|
-
relModel,
|
|
1628
|
-
relTable,
|
|
1629
|
-
relAlias,
|
|
1630
|
-
join: join3
|
|
1631
|
-
} = args;
|
|
1632
|
-
const hasSomeEveryNone = isNotNullish(value[RelationFilters.SOME]) || isNotNullish(value[RelationFilters.EVERY]) || isNotNullish(value[RelationFilters.NONE]);
|
|
1633
|
-
if (hasSomeEveryNone) {
|
|
1634
|
-
throw createError(
|
|
1635
|
-
`To-one relation '${fieldName}' does not support { some, every, none }; use { is, isNot }`,
|
|
1636
|
-
{ field: fieldName, path: ctx.path, modelName: ctx.model.name }
|
|
1637
|
-
);
|
|
1638
|
-
}
|
|
1639
|
-
const hasIs = Object.prototype.hasOwnProperty.call(value, "is");
|
|
1640
|
-
const hasIsNot = Object.prototype.hasOwnProperty.call(value, "isNot");
|
|
1641
|
-
let filterKey;
|
|
1642
|
-
let filterVal;
|
|
1643
|
-
if (hasIs) {
|
|
1644
|
-
filterKey = "is";
|
|
1645
|
-
filterVal = value.is;
|
|
1646
|
-
} else if (hasIsNot) {
|
|
1647
|
-
filterKey = "isNot";
|
|
1648
|
-
filterVal = value.isNot;
|
|
1649
|
-
} else {
|
|
1650
|
-
filterKey = "is";
|
|
1651
|
-
filterVal = value;
|
|
1439
|
+
function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
|
|
1440
|
+
var _a;
|
|
1441
|
+
const d = dialect != null ? dialect : getGlobalDialect();
|
|
1442
|
+
const cursorEntries = Object.entries(cursor);
|
|
1443
|
+
if (cursorEntries.length === 0) {
|
|
1444
|
+
throw new Error("cursor must have at least one field");
|
|
1652
1445
|
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
}
|
|
1659
|
-
if (filterVal === null) {
|
|
1660
|
-
const wantNull = filterKey === "is";
|
|
1661
|
-
const clause2 = buildToOneNullCheck(
|
|
1446
|
+
const cursorAlias = "__tp_cursor_src";
|
|
1447
|
+
const { whereSql: cursorWhereSql, placeholdersByField } = buildCursorFilterParts(cursor, cursorAlias, params);
|
|
1448
|
+
let orderEntries = buildOrderEntries(orderBy);
|
|
1449
|
+
if (orderEntries.length === 0) {
|
|
1450
|
+
orderEntries = cursorEntries.map(([field]) => ({
|
|
1662
1451
|
field,
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
wantNull
|
|
1668
|
-
);
|
|
1669
|
-
return Object.freeze({
|
|
1670
|
-
clause: clause2,
|
|
1671
|
-
joins: NO_JOINS
|
|
1672
|
-
});
|
|
1452
|
+
direction: "asc"
|
|
1453
|
+
}));
|
|
1454
|
+
} else {
|
|
1455
|
+
orderEntries = ensureCursorFieldsInOrder(orderEntries, cursorEntries);
|
|
1673
1456
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1457
|
+
const existsExpr = buildCursorRowExistsExpr(
|
|
1458
|
+
tableName,
|
|
1459
|
+
cursorAlias,
|
|
1460
|
+
cursorWhereSql
|
|
1461
|
+
);
|
|
1462
|
+
const outerCursorMatch = buildOuterCursorMatch(
|
|
1463
|
+
cursor,
|
|
1464
|
+
alias,
|
|
1465
|
+
placeholdersByField,
|
|
1466
|
+
params,
|
|
1467
|
+
model
|
|
1468
|
+
);
|
|
1469
|
+
const orClauses = [];
|
|
1470
|
+
for (let level = 0; level < orderEntries.length; level++) {
|
|
1471
|
+
const andParts = [];
|
|
1472
|
+
for (let i = 0; i < level; i++) {
|
|
1473
|
+
const e2 = orderEntries[i];
|
|
1474
|
+
const c2 = col(alias, e2.field, model);
|
|
1475
|
+
const v2 = cursorValueExpr(
|
|
1476
|
+
tableName,
|
|
1477
|
+
cursorAlias,
|
|
1478
|
+
cursorWhereSql,
|
|
1479
|
+
e2.field);
|
|
1480
|
+
andParts.push(buildCursorEqualityExpr(c2, v2));
|
|
1481
|
+
}
|
|
1482
|
+
const e = orderEntries[level];
|
|
1483
|
+
const c = col(alias, e.field, model);
|
|
1484
|
+
const v = cursorValueExpr(
|
|
1485
|
+
tableName,
|
|
1486
|
+
cursorAlias,
|
|
1487
|
+
cursorWhereSql,
|
|
1488
|
+
e.field);
|
|
1489
|
+
const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
|
|
1490
|
+
andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, v));
|
|
1491
|
+
orClauses.push(`(${andParts.join(SQL_SEPARATORS.CONDITION_AND)})`);
|
|
1684
1492
|
}
|
|
1685
|
-
const
|
|
1686
|
-
|
|
1687
|
-
model: relModel,
|
|
1688
|
-
path: [...ctx.path, fieldName, filterKey],
|
|
1689
|
-
isSubquery: true,
|
|
1690
|
-
depth: ctx.depth + 1
|
|
1691
|
-
}));
|
|
1692
|
-
const clause = filterKey === "is" ? buildToOneExistsMatch(relTable, relAlias, join3, sub) : buildToOneNotExistsMatch(relTable, relAlias, join3, sub);
|
|
1693
|
-
return Object.freeze({
|
|
1694
|
-
clause,
|
|
1695
|
-
joins: NO_JOINS
|
|
1696
|
-
});
|
|
1493
|
+
const exclusive = orClauses.join(SQL_SEPARATORS.CONDITION_OR);
|
|
1494
|
+
return `(${existsExpr} ${SQL_SEPARATORS.CONDITION_AND} ((${exclusive})${SQL_SEPARATORS.CONDITION_OR}(${outerCursorMatch})))`;
|
|
1697
1495
|
}
|
|
1698
|
-
function
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
modelName: ctx.model.name,
|
|
1704
|
-
value
|
|
1705
|
-
});
|
|
1706
|
-
}
|
|
1496
|
+
function buildOrderBy(orderBy, alias, dialect, model) {
|
|
1497
|
+
const entries = buildOrderEntries(orderBy);
|
|
1498
|
+
if (entries.length === 0) return "";
|
|
1499
|
+
const d = dialect != null ? dialect : getGlobalDialect();
|
|
1500
|
+
return buildOrderByFragment(entries, alias, d, model);
|
|
1707
1501
|
}
|
|
1708
|
-
function
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
modelName: ctx.model.name
|
|
1715
|
-
});
|
|
1716
|
-
}
|
|
1717
|
-
const relModel = ctx.schemaModels.find((m) => m.name === field.relatedModel);
|
|
1718
|
-
if (!isNotNullish(relModel)) {
|
|
1719
|
-
throw createError(
|
|
1720
|
-
`Related model '${field.relatedModel}' not found in schema. Available models: ${ctx.schemaModels.map((m) => m.name).join(", ")}`,
|
|
1721
|
-
{
|
|
1722
|
-
field: fieldName,
|
|
1723
|
-
path: ctx.path,
|
|
1724
|
-
modelName: ctx.model.name
|
|
1725
|
-
}
|
|
1502
|
+
function buildOrderByClause(args, alias, dialect, model) {
|
|
1503
|
+
if (!isNotNullish(args.orderBy)) return "";
|
|
1504
|
+
const result = buildOrderBy(args.orderBy, alias, dialect, model);
|
|
1505
|
+
if (!isNonEmptyString(result)) {
|
|
1506
|
+
throw new Error(
|
|
1507
|
+
"buildOrderByClause: orderBy specified but produced empty result"
|
|
1726
1508
|
);
|
|
1727
1509
|
}
|
|
1728
|
-
|
|
1729
|
-
SQL_TEMPLATES.PUBLIC_SCHEMA,
|
|
1730
|
-
relModel.tableName,
|
|
1731
|
-
ctx.dialect
|
|
1732
|
-
);
|
|
1733
|
-
const relAlias = ctx.aliasGen.next(fieldName);
|
|
1734
|
-
const join3 = joinCondition(field, ctx.model, relModel, ctx.alias, relAlias);
|
|
1735
|
-
const args = {
|
|
1736
|
-
fieldName,
|
|
1737
|
-
value,
|
|
1738
|
-
ctx,
|
|
1739
|
-
whereBuilder,
|
|
1740
|
-
field,
|
|
1741
|
-
relModel,
|
|
1742
|
-
relTable,
|
|
1743
|
-
relAlias,
|
|
1744
|
-
join: join3
|
|
1745
|
-
};
|
|
1746
|
-
if (isListRelation(field.type)) return buildListRelationFilters(args);
|
|
1747
|
-
return buildToOneRelationFilters(args);
|
|
1510
|
+
return result;
|
|
1748
1511
|
}
|
|
1749
|
-
function
|
|
1750
|
-
|
|
1751
|
-
|
|
1512
|
+
function normalizeTakeLike(v) {
|
|
1513
|
+
const n = normalizeIntLike("take", v, {
|
|
1514
|
+
min: Number.MIN_SAFE_INTEGER,
|
|
1515
|
+
max: MAX_LIMIT_OFFSET,
|
|
1516
|
+
allowZero: true
|
|
1517
|
+
});
|
|
1518
|
+
if (typeof n === "number") {
|
|
1519
|
+
if (n === 0) return 0;
|
|
1520
|
+
}
|
|
1521
|
+
return n;
|
|
1752
1522
|
}
|
|
1753
|
-
function
|
|
1754
|
-
return
|
|
1523
|
+
function normalizeSkipLike(v) {
|
|
1524
|
+
return normalizeIntLike("skip", v, {
|
|
1525
|
+
min: 0,
|
|
1526
|
+
max: MAX_LIMIT_OFFSET,
|
|
1527
|
+
allowZero: true
|
|
1528
|
+
});
|
|
1755
1529
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
path,
|
|
1764
|
-
modelName: model.name,
|
|
1765
|
-
availableFields: model.fields.map((f) => f.name)
|
|
1766
|
-
});
|
|
1530
|
+
function getPaginationParams(method, args) {
|
|
1531
|
+
if (method === "findMany") {
|
|
1532
|
+
return {
|
|
1533
|
+
take: normalizeTakeLike(args.take),
|
|
1534
|
+
skip: normalizeSkipLike(args.skip),
|
|
1535
|
+
cursor: args.cursor
|
|
1536
|
+
};
|
|
1767
1537
|
}
|
|
1768
|
-
|
|
1538
|
+
if (method === "findFirst") {
|
|
1539
|
+
const skip = normalizeSkipLike(args.skip);
|
|
1540
|
+
return { take: 1, skip: skip != null ? skip : 0 };
|
|
1541
|
+
}
|
|
1542
|
+
if (method === "findUnique") {
|
|
1543
|
+
return { take: 1, skip: 0 };
|
|
1544
|
+
}
|
|
1545
|
+
return {};
|
|
1769
1546
|
}
|
|
1770
|
-
function
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1547
|
+
function buildNotComposite(expr, val, params, dialect, buildOp, separator) {
|
|
1548
|
+
const entries = Object.entries(val).filter(
|
|
1549
|
+
([k, v]) => k !== "mode" && v !== void 0
|
|
1550
|
+
);
|
|
1551
|
+
if (entries.length === 0) return "";
|
|
1552
|
+
const clauses = [];
|
|
1553
|
+
for (const [subOp, subVal] of entries) {
|
|
1554
|
+
const sub = buildOp(expr, subOp, subVal, params, dialect);
|
|
1555
|
+
if (sub && sub.trim().length > 0) clauses.push(`(${sub})`);
|
|
1556
|
+
}
|
|
1557
|
+
if (clauses.length === 0) return "";
|
|
1558
|
+
if (clauses.length === 1) return `${SQL_TEMPLATES.NOT} ${clauses[0]}`;
|
|
1559
|
+
return `${SQL_TEMPLATES.NOT} (${clauses.join(separator)})`;
|
|
1560
|
+
}
|
|
1561
|
+
function buildScalarOperator(expr, op, val, params, mode, fieldType, dialect) {
|
|
1562
|
+
if (val === void 0) return "";
|
|
1563
|
+
if (val === null) {
|
|
1564
|
+
return handleNullValue(expr, op);
|
|
1565
|
+
}
|
|
1566
|
+
if (op === Ops.NOT && isPlainObject(val)) {
|
|
1567
|
+
return handleNotOperator(expr, val, params, mode, fieldType, dialect);
|
|
1568
|
+
}
|
|
1569
|
+
if (op === Ops.NOT) {
|
|
1570
|
+
const placeholder = params.addAuto(val);
|
|
1571
|
+
return `${expr} <> ${placeholder}`;
|
|
1572
|
+
}
|
|
1573
|
+
if (op === Ops.EQUALS && mode === Modes.INSENSITIVE && isNotNullish(dialect)) {
|
|
1574
|
+
const placeholder = params.addAuto(val);
|
|
1575
|
+
return caseInsensitiveEquals(expr, placeholder);
|
|
1576
|
+
}
|
|
1577
|
+
const STRING_LIKE_OPS = /* @__PURE__ */ new Set([
|
|
1578
|
+
Ops.CONTAINS,
|
|
1579
|
+
Ops.STARTS_WITH,
|
|
1580
|
+
Ops.ENDS_WITH
|
|
1783
1581
|
]);
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
path,
|
|
1792
|
-
modelName
|
|
1793
|
-
});
|
|
1582
|
+
if (STRING_LIKE_OPS.has(op)) {
|
|
1583
|
+
if (!isNotNullish(dialect)) {
|
|
1584
|
+
throw createError(`Like operators require a SQL dialect`, {
|
|
1585
|
+
operator: op
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
return handleLikeOperator(expr, op, val, params, mode, dialect);
|
|
1794
1589
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
operator: op,
|
|
1801
|
-
field: fieldName,
|
|
1802
|
-
path,
|
|
1803
|
-
modelName
|
|
1804
|
-
});
|
|
1590
|
+
if (op === Ops.IN || op === Ops.NOT_IN) {
|
|
1591
|
+
if (!isNotNullish(dialect)) {
|
|
1592
|
+
throw createError(`IN operators require a SQL dialect`, { operator: op });
|
|
1593
|
+
}
|
|
1594
|
+
return handleInOperator(expr, op, val, params, dialect);
|
|
1805
1595
|
}
|
|
1596
|
+
return handleComparisonOperator(expr, op, val, params);
|
|
1806
1597
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1598
|
+
function handleNullValue(expr, op) {
|
|
1599
|
+
if (op === Ops.EQUALS) return `${expr} ${SQL_TEMPLATES.IS_NULL}`;
|
|
1600
|
+
if (op === Ops.NOT) return `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1601
|
+
throw createError(`Operator '${op}' doesn't support null`, { operator: op });
|
|
1602
|
+
}
|
|
1603
|
+
function normalizeMode(v) {
|
|
1604
|
+
if (v === Modes.INSENSITIVE) return Modes.INSENSITIVE;
|
|
1605
|
+
if (v === Modes.DEFAULT) return Modes.DEFAULT;
|
|
1606
|
+
return void 0;
|
|
1607
|
+
}
|
|
1608
|
+
function handleNotOperator(expr, val, params, outerMode, fieldType, dialect) {
|
|
1609
|
+
const innerMode = normalizeMode(val.mode);
|
|
1610
|
+
const effectiveMode = innerMode != null ? innerMode : outerMode;
|
|
1611
|
+
return buildNotComposite(
|
|
1612
|
+
expr,
|
|
1613
|
+
val,
|
|
1614
|
+
params,
|
|
1615
|
+
dialect,
|
|
1616
|
+
(e, subOp, subVal, p, d) => buildScalarOperator(e, subOp, subVal, p, effectiveMode, fieldType, d),
|
|
1617
|
+
` ${SQL_TEMPLATES.AND} `
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
function buildDynamicLikePattern(op, placeholder, dialect) {
|
|
1621
|
+
if (dialect === "postgres") {
|
|
1622
|
+
switch (op) {
|
|
1623
|
+
case Ops.CONTAINS:
|
|
1624
|
+
return `('%' || ${placeholder} || '%')`;
|
|
1625
|
+
case Ops.STARTS_WITH:
|
|
1626
|
+
return `(${placeholder} || '%')`;
|
|
1627
|
+
case Ops.ENDS_WITH:
|
|
1628
|
+
return `('%' || ${placeholder})`;
|
|
1629
|
+
default:
|
|
1630
|
+
return placeholder;
|
|
1816
1631
|
}
|
|
1817
|
-
return buildWhereInternal(where, ctx, this);
|
|
1818
1632
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1633
|
+
switch (op) {
|
|
1634
|
+
case Ops.CONTAINS:
|
|
1635
|
+
return `('%' || ${placeholder} || '%')`;
|
|
1636
|
+
case Ops.STARTS_WITH:
|
|
1637
|
+
return `(${placeholder} || '%')`;
|
|
1638
|
+
case Ops.ENDS_WITH:
|
|
1639
|
+
return `('%' || ${placeholder})`;
|
|
1640
|
+
default:
|
|
1641
|
+
return placeholder;
|
|
1642
|
+
}
|
|
1825
1643
|
}
|
|
1826
|
-
function
|
|
1827
|
-
if (
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
if (
|
|
1832
|
-
|
|
1833
|
-
out.push(s);
|
|
1644
|
+
function handleLikeOperator(expr, op, val, params, mode, dialect) {
|
|
1645
|
+
if (val === void 0) return "";
|
|
1646
|
+
if (schemaParser.isDynamicParameter(val)) {
|
|
1647
|
+
const placeholder2 = params.addAuto(val);
|
|
1648
|
+
const patternExpr = buildDynamicLikePattern(op, placeholder2, dialect);
|
|
1649
|
+
if (mode === Modes.INSENSITIVE) {
|
|
1650
|
+
return caseInsensitiveLike(expr, patternExpr, dialect);
|
|
1834
1651
|
}
|
|
1652
|
+
return `${expr} ${SQL_TEMPLATES.LIKE} ${patternExpr}`;
|
|
1835
1653
|
}
|
|
1836
|
-
|
|
1654
|
+
const placeholder = params.add(Wildcards[op](String(val)));
|
|
1655
|
+
if (mode === Modes.INSENSITIVE) {
|
|
1656
|
+
return caseInsensitiveLike(expr, placeholder, dialect);
|
|
1657
|
+
}
|
|
1658
|
+
return `${expr} ${SQL_TEMPLATES.LIKE} ${placeholder}`;
|
|
1837
1659
|
}
|
|
1838
|
-
function
|
|
1839
|
-
if (
|
|
1840
|
-
if (
|
|
1660
|
+
function handleInOperator(expr, op, val, params, dialect) {
|
|
1661
|
+
if (val === void 0) return "";
|
|
1662
|
+
if (schemaParser.isDynamicParameter(val)) {
|
|
1663
|
+
const placeholder2 = params.addAuto(val);
|
|
1664
|
+
return op === Ops.IN ? inArray(expr, placeholder2, dialect) : notInArray(expr, placeholder2, dialect);
|
|
1665
|
+
}
|
|
1666
|
+
if (!Array.isArray(val)) {
|
|
1667
|
+
throw createError(`IN operators require array value`, {
|
|
1668
|
+
operator: op,
|
|
1669
|
+
value: val
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
if (val.length === 0) {
|
|
1673
|
+
return op === Ops.IN ? "0=1" : "1=1";
|
|
1674
|
+
}
|
|
1675
|
+
const paramValue = prepareArrayParam(val, dialect);
|
|
1676
|
+
const placeholder = params.add(paramValue);
|
|
1677
|
+
return op === Ops.IN ? inArray(expr, placeholder, dialect) : notInArray(expr, placeholder, dialect);
|
|
1841
1678
|
}
|
|
1842
|
-
function
|
|
1843
|
-
if (
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1679
|
+
function handleComparisonOperator(expr, op, val, params) {
|
|
1680
|
+
if (val === void 0) return "";
|
|
1681
|
+
const COMPARISON_OPS2 = {
|
|
1682
|
+
[Ops.EQUALS]: "=",
|
|
1683
|
+
[Ops.GT]: ">",
|
|
1684
|
+
[Ops.GTE]: ">=",
|
|
1685
|
+
[Ops.LT]: "<",
|
|
1686
|
+
[Ops.LTE]: "<="
|
|
1687
|
+
};
|
|
1688
|
+
const sqlOp = COMPARISON_OPS2[op];
|
|
1689
|
+
if (!sqlOp) {
|
|
1690
|
+
throw createError(`Unsupported scalar operator: ${op}`, { operator: op });
|
|
1691
|
+
}
|
|
1692
|
+
const placeholder = params.addAuto(val);
|
|
1693
|
+
return `${expr} ${sqlOp} ${placeholder}`;
|
|
1847
1694
|
}
|
|
1848
|
-
function
|
|
1849
|
-
|
|
1695
|
+
function buildArrayParam(val, params, dialect) {
|
|
1696
|
+
if (schemaParser.isDynamicParameter(val)) {
|
|
1697
|
+
return params.addAuto(val);
|
|
1698
|
+
}
|
|
1699
|
+
if (!Array.isArray(val)) {
|
|
1700
|
+
throw createError(`Array operation requires array value`, { value: val });
|
|
1701
|
+
}
|
|
1702
|
+
const paramValue = prepareArrayParam(val, dialect);
|
|
1703
|
+
return params.add(paramValue);
|
|
1850
1704
|
}
|
|
1851
|
-
function
|
|
1852
|
-
|
|
1853
|
-
if (
|
|
1854
|
-
|
|
1705
|
+
function buildArrayOperator(expr, op, val, params, fieldType, dialect) {
|
|
1706
|
+
if (val === void 0) return "";
|
|
1707
|
+
if (val === null) {
|
|
1708
|
+
if (op === Ops.EQUALS) return `${expr} ${SQL_TEMPLATES.IS_NULL}`;
|
|
1709
|
+
if (op === Ops.NOT) return `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1710
|
+
}
|
|
1711
|
+
const cast = getArrayType(fieldType, dialect);
|
|
1712
|
+
if (op === Ops.EQUALS) {
|
|
1713
|
+
return handleArrayEquals(expr, val, params, cast, dialect);
|
|
1714
|
+
}
|
|
1715
|
+
if (op === Ops.NOT) {
|
|
1716
|
+
return handleArrayNot(expr, val, params, cast, dialect);
|
|
1717
|
+
}
|
|
1718
|
+
switch (op) {
|
|
1719
|
+
case Ops.HAS:
|
|
1720
|
+
return handleArrayHas(expr, val, params, cast, dialect);
|
|
1721
|
+
case Ops.HAS_SOME:
|
|
1722
|
+
return handleArrayHasSome(expr, val, params, cast, dialect);
|
|
1723
|
+
case Ops.HAS_EVERY:
|
|
1724
|
+
return handleArrayHasEvery(expr, val, params, cast, dialect);
|
|
1725
|
+
case Ops.IS_EMPTY:
|
|
1726
|
+
return handleArrayIsEmpty(expr, val, dialect);
|
|
1727
|
+
default:
|
|
1728
|
+
throw createError(`Unknown array operator: ${op}`, { operator: op });
|
|
1855
1729
|
}
|
|
1856
|
-
return buildTopLevelRelation(fieldName, value, ctx2, builder);
|
|
1857
1730
|
}
|
|
1858
|
-
function
|
|
1859
|
-
|
|
1860
|
-
if (
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1731
|
+
function handleArrayEquals(expr, val, params, cast, dialect) {
|
|
1732
|
+
if (val === void 0) return "";
|
|
1733
|
+
if (isEmptyArray(val)) {
|
|
1734
|
+
return arrayIsEmpty(expr, dialect);
|
|
1735
|
+
}
|
|
1736
|
+
const placeholder = buildArrayParam(val, params, dialect);
|
|
1737
|
+
return arrayEquals(expr, placeholder, cast, dialect);
|
|
1738
|
+
}
|
|
1739
|
+
function handleArrayNot(expr, val, params, cast, dialect) {
|
|
1740
|
+
if (val === void 0) return "";
|
|
1741
|
+
let target = val;
|
|
1742
|
+
if (isPlainObject(val)) {
|
|
1743
|
+
const entries = Object.entries(val).filter(([, v]) => v !== void 0);
|
|
1744
|
+
if (entries.length === 1 && entries[0][0] === Ops.EQUALS) {
|
|
1745
|
+
target = entries[0][1];
|
|
1746
|
+
} else {
|
|
1747
|
+
throw createError(`Array NOT only supports { equals: ... } shape`, {
|
|
1748
|
+
operator: Ops.NOT,
|
|
1749
|
+
value: val
|
|
1868
1750
|
});
|
|
1869
1751
|
}
|
|
1870
|
-
return buildRelationFilter(key, value, ctx, builder);
|
|
1871
|
-
}
|
|
1872
|
-
return buildScalarField(key, value, ctx);
|
|
1873
|
-
}
|
|
1874
|
-
function buildWhereInternal(where, ctx, builder) {
|
|
1875
|
-
if (ctx.depth > MAX_QUERY_DEPTH) {
|
|
1876
|
-
throw createError(
|
|
1877
|
-
`Query nesting too deep (max ${MAX_QUERY_DEPTH} levels). This usually indicates a circular reference.`,
|
|
1878
|
-
{ path: ctx.path, modelName: ctx.model.name }
|
|
1879
|
-
);
|
|
1880
1752
|
}
|
|
1881
|
-
if (
|
|
1882
|
-
return
|
|
1753
|
+
if (target === null) {
|
|
1754
|
+
return `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1883
1755
|
}
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
for (const [key, value] of Object.entries(where)) {
|
|
1887
|
-
if (value === void 0) continue;
|
|
1888
|
-
const result = buildWhereEntry(key, value, ctx, builder);
|
|
1889
|
-
appendResult(result, clauses, allJoins);
|
|
1756
|
+
if (isEmptyArray(target)) {
|
|
1757
|
+
return arrayIsNotEmpty(expr, dialect);
|
|
1890
1758
|
}
|
|
1891
|
-
const
|
|
1892
|
-
return
|
|
1759
|
+
const placeholder = buildArrayParam(target, params, dialect);
|
|
1760
|
+
return `${SQL_TEMPLATES.NOT} (${arrayEquals(expr, placeholder, cast, dialect)})`;
|
|
1893
1761
|
}
|
|
1894
|
-
function
|
|
1895
|
-
if (
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
throw createError(`${operator} entries must be objects`, {
|
|
1902
|
-
path: [...ctx.path, operator, String(i)],
|
|
1903
|
-
modelName: ctx.model.name,
|
|
1904
|
-
value: v
|
|
1905
|
-
});
|
|
1906
|
-
}
|
|
1907
|
-
out.push(v);
|
|
1908
|
-
}
|
|
1909
|
-
return out;
|
|
1910
|
-
}
|
|
1911
|
-
if (isPlainObject(value)) {
|
|
1912
|
-
return [value];
|
|
1762
|
+
function handleArrayHas(expr, val, params, cast, dialect) {
|
|
1763
|
+
if (val === void 0) return "";
|
|
1764
|
+
if (val === null) {
|
|
1765
|
+
throw createError(`has requires scalar value`, {
|
|
1766
|
+
operator: Ops.HAS,
|
|
1767
|
+
value: val
|
|
1768
|
+
});
|
|
1913
1769
|
}
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1920
|
-
function collectLogicalParts(operator, conditions, ctx, builder) {
|
|
1921
|
-
const allJoins = [];
|
|
1922
|
-
const clauses = [];
|
|
1923
|
-
for (let i = 0; i < conditions.length; i++) {
|
|
1924
|
-
const result = builder.build(conditions[i], __spreadProps(__spreadValues({}, ctx), {
|
|
1925
|
-
path: [...ctx.path, operator, String(i)],
|
|
1926
|
-
depth: ctx.depth + 1
|
|
1927
|
-
}));
|
|
1928
|
-
if (isNonEmptyArray(result.joins)) allJoins.push(...result.joins);
|
|
1929
|
-
if (result.clause && result.clause !== DEFAULT_WHERE_CLAUSE) {
|
|
1930
|
-
clauses.push(`(${result.clause})`);
|
|
1931
|
-
}
|
|
1770
|
+
if (!schemaParser.isDynamicParameter(val) && Array.isArray(val)) {
|
|
1771
|
+
throw createError(`has requires scalar value (single element), not array`, {
|
|
1772
|
+
operator: Ops.HAS,
|
|
1773
|
+
value: val
|
|
1774
|
+
});
|
|
1932
1775
|
}
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
}
|
|
1938
|
-
function buildLogicalClause(operator, clauses) {
|
|
1939
|
-
if (clauses.length === 0) return DEFAULT_WHERE_CLAUSE;
|
|
1940
|
-
if (operator === "NOT") {
|
|
1941
|
-
if (clauses.length === 1) return `${SQL_TEMPLATES.NOT} ${clauses[0]}`;
|
|
1942
|
-
return `${SQL_TEMPLATES.NOT} (${clauses.join(SQL_SEPARATORS.CONDITION_AND)})`;
|
|
1776
|
+
if (isPlainObject(val)) {
|
|
1777
|
+
throw createError(`has requires scalar value`, {
|
|
1778
|
+
operator: Ops.HAS,
|
|
1779
|
+
value: val
|
|
1780
|
+
});
|
|
1943
1781
|
}
|
|
1944
|
-
|
|
1782
|
+
const placeholder = params.addAuto(val);
|
|
1783
|
+
return arrayContains(expr, placeholder, cast, dialect);
|
|
1945
1784
|
}
|
|
1946
|
-
function
|
|
1947
|
-
|
|
1948
|
-
if (
|
|
1949
|
-
const
|
|
1950
|
-
return
|
|
1785
|
+
function handleArrayHasSome(expr, val, params, cast, dialect) {
|
|
1786
|
+
if (val === void 0) return "";
|
|
1787
|
+
if (schemaParser.isDynamicParameter(val)) {
|
|
1788
|
+
const placeholder2 = params.addAuto(val);
|
|
1789
|
+
return arrayOverlaps(expr, placeholder2, cast, dialect);
|
|
1951
1790
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
);
|
|
1958
|
-
const clause = buildLogicalClause(operator, clauses);
|
|
1959
|
-
return freezeResult(clause, joins);
|
|
1960
|
-
}
|
|
1961
|
-
function buildScalarField(fieldName, value, ctx) {
|
|
1962
|
-
const field = assertFieldExists(fieldName, ctx.model, ctx.path);
|
|
1963
|
-
const expr = col(ctx.alias, fieldName, ctx.model);
|
|
1964
|
-
if (value === null) {
|
|
1965
|
-
return freezeResult(`${expr} ${SQL_TEMPLATES.IS_NULL}`, EMPTY_JOINS);
|
|
1791
|
+
if (!Array.isArray(val)) {
|
|
1792
|
+
throw createError(`hasSome requires array value`, {
|
|
1793
|
+
operator: Ops.HAS_SOME,
|
|
1794
|
+
value: val
|
|
1795
|
+
});
|
|
1966
1796
|
}
|
|
1967
|
-
if (
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1797
|
+
if (val.length > LIMITS.MAX_ARRAY_SIZE) {
|
|
1798
|
+
throw createError(
|
|
1799
|
+
`Array too large (${val.length} elements, max ${LIMITS.MAX_ARRAY_SIZE})`,
|
|
1800
|
+
{ operator: Ops.HAS_SOME, value: `[${val.length} items]` }
|
|
1971
1801
|
);
|
|
1972
|
-
if (ops.length === 0) {
|
|
1973
|
-
return freezeResult(DEFAULT_WHERE_CLAUSE, EMPTY_JOINS);
|
|
1974
|
-
}
|
|
1975
|
-
const parts = [];
|
|
1976
|
-
for (const [op, val] of ops) {
|
|
1977
|
-
assertValidOperator(fieldName, op, field.type, ctx.path, ctx.model.name);
|
|
1978
|
-
const clause3 = buildOperator(expr, op, val, ctx, mode, field.type);
|
|
1979
|
-
if (isValidWhereClause(clause3)) parts.push(clause3);
|
|
1980
|
-
}
|
|
1981
|
-
const clause2 = parts.length > 0 ? parts.join(SQL_SEPARATORS.CONDITION_AND) : DEFAULT_WHERE_CLAUSE;
|
|
1982
|
-
return freezeResult(clause2, EMPTY_JOINS);
|
|
1983
1802
|
}
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
ctx,
|
|
1989
|
-
void 0,
|
|
1990
|
-
field.type
|
|
1991
|
-
);
|
|
1992
|
-
return freezeResult(clause || DEFAULT_WHERE_CLAUSE, EMPTY_JOINS);
|
|
1803
|
+
if (val.length === 0) return "0=1";
|
|
1804
|
+
const paramValue = prepareArrayParam(val, dialect);
|
|
1805
|
+
const placeholder = params.add(paramValue);
|
|
1806
|
+
return arrayOverlaps(expr, placeholder, cast, dialect);
|
|
1993
1807
|
}
|
|
1994
|
-
function
|
|
1995
|
-
if (
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
Ops.
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
if (JSON_OPS.has(op)) {
|
|
2006
|
-
return buildJsonOperator(expr, op, val, ctx.params, ctx.dialect);
|
|
2007
|
-
}
|
|
1808
|
+
function handleArrayHasEvery(expr, val, params, cast, dialect) {
|
|
1809
|
+
if (val === void 0) return "";
|
|
1810
|
+
const placeholder = buildArrayParam(val, params, dialect);
|
|
1811
|
+
return arrayContainsAll(expr, placeholder, cast, dialect);
|
|
1812
|
+
}
|
|
1813
|
+
function handleArrayIsEmpty(expr, val, dialect) {
|
|
1814
|
+
if (typeof val !== "boolean") {
|
|
1815
|
+
throw createError(`isEmpty requires boolean value`, {
|
|
1816
|
+
operator: Ops.IS_EMPTY,
|
|
1817
|
+
value: val
|
|
1818
|
+
});
|
|
2008
1819
|
}
|
|
2009
|
-
return
|
|
2010
|
-
expr,
|
|
2011
|
-
op,
|
|
2012
|
-
val,
|
|
2013
|
-
ctx.params,
|
|
2014
|
-
mode,
|
|
2015
|
-
fieldType,
|
|
2016
|
-
ctx.dialect
|
|
2017
|
-
);
|
|
1820
|
+
return val === true ? arrayIsEmpty(expr, dialect) : arrayIsNotEmpty(expr, dialect);
|
|
2018
1821
|
}
|
|
2019
1822
|
|
|
2020
|
-
// src/builder/
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
const
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
}
|
|
2030
|
-
function createAliasGenerator(maxAliases = 1e4) {
|
|
2031
|
-
let counter = 0;
|
|
2032
|
-
const usedAliases = /* @__PURE__ */ new Set();
|
|
2033
|
-
return {
|
|
2034
|
-
next(baseName) {
|
|
2035
|
-
if (usedAliases.size >= maxAliases) {
|
|
2036
|
-
throw new Error(
|
|
2037
|
-
`Alias generator exceeded maximum of ${maxAliases} aliases. This indicates a query complexity issue or potential infinite loop.`
|
|
2038
|
-
);
|
|
2039
|
-
}
|
|
2040
|
-
const base = toSafeSqlIdentifier(baseName);
|
|
2041
|
-
const suffix = `_${counter}`;
|
|
2042
|
-
const maxLen = 63;
|
|
2043
|
-
const baseMax = Math.max(1, maxLen - suffix.length);
|
|
2044
|
-
const trimmedBase = base.length > baseMax ? base.slice(0, baseMax) : base;
|
|
2045
|
-
const alias = `${trimmedBase}${suffix}`;
|
|
2046
|
-
counter += 1;
|
|
2047
|
-
if (usedAliases.has(alias)) {
|
|
2048
|
-
throw new Error(
|
|
2049
|
-
`CRITICAL: Duplicate alias '${alias}' at counter=${counter}. This indicates a bug in alias generation logic.`
|
|
2050
|
-
);
|
|
2051
|
-
}
|
|
2052
|
-
usedAliases.add(alias);
|
|
2053
|
-
return alias;
|
|
1823
|
+
// src/builder/where/operators-json.ts
|
|
1824
|
+
var SAFE_JSON_PATH_SEGMENT = /^[a-zA-Z_]\w*$/;
|
|
1825
|
+
function validateJsonPathSegments(segments) {
|
|
1826
|
+
for (const segment of segments) {
|
|
1827
|
+
if (typeof segment !== "string") {
|
|
1828
|
+
throw createError("JSON path segments must be strings", {
|
|
1829
|
+
operator: Ops.PATH,
|
|
1830
|
+
value: segment
|
|
1831
|
+
});
|
|
2054
1832
|
}
|
|
2055
|
-
|
|
1833
|
+
if (!SAFE_JSON_PATH_SEGMENT.test(segment)) {
|
|
1834
|
+
throw createError(
|
|
1835
|
+
`Invalid JSON path segment: '${segment}'. Must be alphanumeric with underscores, starting with letter or underscore.`,
|
|
1836
|
+
{ operator: Ops.PATH, value: segment }
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
2056
1840
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
if (
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
1841
|
+
function buildJsonOperator(expr, op, val, params, dialect) {
|
|
1842
|
+
if (val === void 0) return "";
|
|
1843
|
+
if (op === Ops.PATH && isPlainObject(val) && "path" in val) {
|
|
1844
|
+
return handleJsonPath(expr, val, params, dialect);
|
|
1845
|
+
}
|
|
1846
|
+
const jsonWildcards = {
|
|
1847
|
+
[Ops.STRING_CONTAINS]: (v) => `%${v}%`,
|
|
1848
|
+
[Ops.STRING_STARTS_WITH]: (v) => `${v}%`,
|
|
1849
|
+
[Ops.STRING_ENDS_WITH]: (v) => `%${v}`
|
|
1850
|
+
};
|
|
1851
|
+
if (op in jsonWildcards) {
|
|
1852
|
+
return handleJsonWildcard(expr, op, val, params, jsonWildcards, dialect);
|
|
2063
1853
|
}
|
|
1854
|
+
throw createError(`Unsupported JSON operator: ${op}`, { operator: op });
|
|
2064
1855
|
}
|
|
2065
|
-
function
|
|
2066
|
-
|
|
2067
|
-
|
|
1856
|
+
function handleJsonPath(expr, val, params, dialect) {
|
|
1857
|
+
const v = val;
|
|
1858
|
+
if (!Array.isArray(v.path)) {
|
|
1859
|
+
throw createError("JSON path must be an array", { operator: Ops.PATH });
|
|
2068
1860
|
}
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
const expected = mappingsLength + 1;
|
|
2072
|
-
if (nextIndex !== expected) {
|
|
2073
|
-
throw new Error(
|
|
2074
|
-
`CRITICAL: Next index mismatch - expected ${expected}, got ${nextIndex}`
|
|
2075
|
-
);
|
|
1861
|
+
if (v.path.length === 0) {
|
|
1862
|
+
throw createError("JSON path cannot be empty", { operator: Ops.PATH });
|
|
2076
1863
|
}
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
1864
|
+
validateJsonPathSegments(v.path);
|
|
1865
|
+
const pathExpr = dialect === "sqlite" ? params.add(`$.${v.path.join(".")}`) : params.add(v.path);
|
|
1866
|
+
const rawOps = [
|
|
1867
|
+
["=", v.equals],
|
|
1868
|
+
[">", v.gt],
|
|
1869
|
+
[">=", v.gte],
|
|
1870
|
+
["<", v.lt],
|
|
1871
|
+
["<=", v.lte]
|
|
1872
|
+
];
|
|
1873
|
+
const ops = rawOps.filter(
|
|
1874
|
+
([, value]) => value !== void 0
|
|
1875
|
+
);
|
|
1876
|
+
if (ops.length === 0) {
|
|
1877
|
+
throw createError("JSON path query missing comparison operator", {
|
|
1878
|
+
operator: Ops.PATH
|
|
1879
|
+
});
|
|
2083
1880
|
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
);
|
|
1881
|
+
const parts = [];
|
|
1882
|
+
for (const [sqlOp, value] of ops) {
|
|
1883
|
+
if (value === null) {
|
|
1884
|
+
const base2 = jsonExtractText(expr, pathExpr, dialect);
|
|
1885
|
+
parts.push(`${base2} ${SQL_TEMPLATES.IS_NULL}`);
|
|
1886
|
+
continue;
|
|
1887
|
+
}
|
|
1888
|
+
const valPh = params.add(value);
|
|
1889
|
+
const base = typeof value === "number" ? jsonExtractNumeric(expr, pathExpr, dialect) : jsonExtractText(expr, pathExpr, dialect);
|
|
1890
|
+
parts.push(`${base} ${sqlOp} ${valPh}`);
|
|
2092
1891
|
}
|
|
1892
|
+
return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
|
|
2093
1893
|
}
|
|
2094
|
-
function
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
1894
|
+
function handleJsonWildcard(expr, op, val, params, wildcards, dialect) {
|
|
1895
|
+
if (!isNotNullish(val)) {
|
|
1896
|
+
throw createError(`JSON string operator requires non-null value`, {
|
|
1897
|
+
operator: op,
|
|
1898
|
+
value: val
|
|
1899
|
+
});
|
|
2098
1900
|
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
1901
|
+
if (isPlainObject(val) || Array.isArray(val)) {
|
|
1902
|
+
throw createError(`JSON string operator requires scalar value`, {
|
|
1903
|
+
operator: op,
|
|
1904
|
+
value: val
|
|
1905
|
+
});
|
|
2104
1906
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
const dn = normalizeDynamicNameOrThrow(m.dynamicName, m.index);
|
|
2112
|
-
assertUniqueDynamicName(dn, seenDynamic);
|
|
1907
|
+
const strVal = String(val);
|
|
1908
|
+
if (strVal.length > LIMITS.MAX_STRING_LENGTH) {
|
|
1909
|
+
throw createError(
|
|
1910
|
+
`String too long (${strVal.length} chars, max ${LIMITS.MAX_STRING_LENGTH})`,
|
|
1911
|
+
{ operator: op }
|
|
1912
|
+
);
|
|
2113
1913
|
}
|
|
1914
|
+
const placeholder = params.add(wildcards[op](strVal));
|
|
1915
|
+
const jsonText = jsonToText(expr, dialect);
|
|
1916
|
+
return caseInsensitiveLike(jsonText, placeholder, dialect);
|
|
2114
1917
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
1918
|
+
|
|
1919
|
+
// src/builder/where/relations.ts
|
|
1920
|
+
var NO_JOINS = Object.freeze([]);
|
|
1921
|
+
function isListRelation(fieldType) {
|
|
1922
|
+
return typeof fieldType === "string" && fieldType.endsWith("[]");
|
|
1923
|
+
}
|
|
1924
|
+
function buildToOneNullCheck(field, parentAlias, relTable, relAlias, join3, wantNull) {
|
|
1925
|
+
const isLocal = field.isForeignKeyLocal === true;
|
|
1926
|
+
const fkFields = normalizeKeyList(field.foreignKey);
|
|
1927
|
+
if (isLocal) {
|
|
1928
|
+
if (fkFields.length === 0) {
|
|
1929
|
+
throw createError(`Relation '${field.name}' is missing foreignKey`, {
|
|
1930
|
+
field: field.name
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
const parts = fkFields.map((fk) => {
|
|
1934
|
+
const safe = fk.replace(/"/g, '""');
|
|
1935
|
+
const expr = `${parentAlias}."${safe}"`;
|
|
1936
|
+
return wantNull ? `${expr} ${SQL_TEMPLATES.IS_NULL}` : `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
|
|
1937
|
+
});
|
|
1938
|
+
if (parts.length === 1) return parts[0];
|
|
1939
|
+
return wantNull ? `(${parts.join(" OR ")})` : `(${parts.join(" AND ")})`;
|
|
2119
1940
|
}
|
|
1941
|
+
const existsSql = `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias} ${SQL_TEMPLATES.WHERE} ${join3})`;
|
|
1942
|
+
return wantNull ? `${SQL_TEMPLATES.NOT} ${existsSql}` : existsSql;
|
|
2120
1943
|
}
|
|
2121
|
-
function
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
if (mappings.length === 0) return;
|
|
2125
|
-
validateMappings(mappings);
|
|
2126
|
-
assertNextIndexMatches(mappings.length, index);
|
|
1944
|
+
function buildToOneExistsMatch(relTable, relAlias, join3, sub) {
|
|
1945
|
+
const joins = sub.joins.length > 0 ? ` ${sub.joins.join(" ")}` : "";
|
|
1946
|
+
return `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias}${joins} ${SQL_TEMPLATES.WHERE} ${join3} ${SQL_TEMPLATES.AND} ${sub.clause})`;
|
|
2127
1947
|
}
|
|
2128
|
-
function
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}
|
|
2132
|
-
return value;
|
|
1948
|
+
function buildToOneNotExistsMatch(relTable, relAlias, join3, sub) {
|
|
1949
|
+
const joins = sub.joins.length > 0 ? ` ${sub.joins.join(" ")}` : "";
|
|
1950
|
+
return `${SQL_TEMPLATES.NOT} EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias}${joins} ${SQL_TEMPLATES.WHERE} ${join3} ${SQL_TEMPLATES.AND} ${sub.clause})`;
|
|
2133
1951
|
}
|
|
2134
|
-
function
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
1952
|
+
function buildListRelationFilters(args) {
|
|
1953
|
+
const {
|
|
1954
|
+
fieldName,
|
|
1955
|
+
value,
|
|
1956
|
+
ctx,
|
|
1957
|
+
whereBuilder,
|
|
1958
|
+
relModel,
|
|
1959
|
+
relTable,
|
|
1960
|
+
relAlias,
|
|
1961
|
+
join: join3
|
|
1962
|
+
} = args;
|
|
1963
|
+
const noneValue = value[RelationFilters.NONE];
|
|
1964
|
+
if (noneValue !== void 0 && noneValue !== null) {
|
|
1965
|
+
const sub = whereBuilder.build(noneValue, __spreadProps(__spreadValues({}, ctx), {
|
|
1966
|
+
alias: relAlias,
|
|
1967
|
+
model: relModel,
|
|
1968
|
+
path: [...ctx.path, fieldName, RelationFilters.NONE],
|
|
1969
|
+
isSubquery: true,
|
|
1970
|
+
depth: ctx.depth + 1
|
|
1971
|
+
}));
|
|
1972
|
+
const isEmptyFilter = isPlainObject(noneValue) && Object.keys(noneValue).length === 0;
|
|
1973
|
+
const canOptimize = !ctx.isSubquery && isEmptyFilter && sub.clause === DEFAULT_WHERE_CLAUSE && sub.joins.length === 0;
|
|
1974
|
+
if (canOptimize) {
|
|
1975
|
+
const checkField = relModel.fields.find(
|
|
1976
|
+
(f) => !f.isRelation && f.isRequired && f.name !== "id"
|
|
1977
|
+
) || relModel.fields.find((f) => !f.isRelation && f.name === "id");
|
|
1978
|
+
if (checkField) {
|
|
1979
|
+
const leftJoinSql = `LEFT JOIN ${relTable} ${relAlias} ON ${join3}`;
|
|
1980
|
+
const whereClause = `${relAlias}.${quote(checkField.name)} IS NULL`;
|
|
1981
|
+
return Object.freeze({
|
|
1982
|
+
clause: whereClause,
|
|
1983
|
+
joins: [leftJoinSql]
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
2142
1986
|
}
|
|
2143
1987
|
}
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
1988
|
+
const filters = [
|
|
1989
|
+
{
|
|
1990
|
+
key: RelationFilters.SOME,
|
|
1991
|
+
wrap: (c, j) => `EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias}${j} ${SQL_TEMPLATES.WHERE} ${join3} ${SQL_TEMPLATES.AND} ${c})`
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
key: RelationFilters.EVERY,
|
|
1995
|
+
wrap: (c, j) => `${SQL_TEMPLATES.NOT} EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias}${j} ${SQL_TEMPLATES.WHERE} ${join3} ${SQL_TEMPLATES.AND} ${SQL_TEMPLATES.NOT} (${c}))`
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
key: RelationFilters.NONE,
|
|
1999
|
+
wrap: (c, j) => {
|
|
2000
|
+
const condition = c === DEFAULT_WHERE_CLAUSE ? "" : ` ${SQL_TEMPLATES.AND} ${c}`;
|
|
2001
|
+
return `${SQL_TEMPLATES.NOT} EXISTS (${SQL_TEMPLATES.SELECT} 1 ${SQL_TEMPLATES.FROM} ${relTable} ${relAlias}${j} ${SQL_TEMPLATES.WHERE} ${join3}${condition})`;
|
|
2002
|
+
}
|
|
2149
2003
|
}
|
|
2004
|
+
];
|
|
2005
|
+
const clauses = [];
|
|
2006
|
+
for (const { key, wrap } of filters) {
|
|
2007
|
+
const raw = value[key];
|
|
2008
|
+
if (raw === void 0 || raw === null) continue;
|
|
2009
|
+
const sub = whereBuilder.build(raw, __spreadProps(__spreadValues({}, ctx), {
|
|
2010
|
+
alias: relAlias,
|
|
2011
|
+
model: relModel,
|
|
2012
|
+
path: [...ctx.path, fieldName, key],
|
|
2013
|
+
isSubquery: true,
|
|
2014
|
+
depth: ctx.depth + 1
|
|
2015
|
+
}));
|
|
2016
|
+
const j = sub.joins.length > 0 ? ` ${sub.joins.join(" ")}` : "";
|
|
2017
|
+
clauses.push(wrap(sub.clause, j));
|
|
2150
2018
|
}
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
return dn;
|
|
2019
|
+
if (clauses.length === 0) {
|
|
2020
|
+
throw createError(
|
|
2021
|
+
`List relation '${fieldName}' requires one of { some, every, none }`,
|
|
2022
|
+
{ field: fieldName, path: ctx.path, modelName: ctx.model.name }
|
|
2023
|
+
);
|
|
2157
2024
|
}
|
|
2158
|
-
|
|
2159
|
-
|
|
2025
|
+
return Object.freeze({
|
|
2026
|
+
clause: clauses.join(SQL_SEPARATORS.CONDITION_AND),
|
|
2027
|
+
joins: NO_JOINS
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
function buildToOneRelationFilters(args) {
|
|
2031
|
+
const {
|
|
2032
|
+
fieldName,
|
|
2033
|
+
value,
|
|
2034
|
+
ctx,
|
|
2035
|
+
whereBuilder,
|
|
2036
|
+
field,
|
|
2037
|
+
relModel,
|
|
2038
|
+
relTable,
|
|
2039
|
+
relAlias,
|
|
2040
|
+
join: join3
|
|
2041
|
+
} = args;
|
|
2042
|
+
const hasSomeEveryNone = isNotNullish(value[RelationFilters.SOME]) || isNotNullish(value[RelationFilters.EVERY]) || isNotNullish(value[RelationFilters.NONE]);
|
|
2043
|
+
if (hasSomeEveryNone) {
|
|
2044
|
+
throw createError(
|
|
2045
|
+
`To-one relation '${fieldName}' does not support { some, every, none }; use { is, isNot }`,
|
|
2046
|
+
{ field: fieldName, path: ctx.path, modelName: ctx.model.name }
|
|
2047
|
+
);
|
|
2160
2048
|
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2049
|
+
const hasIs = Object.prototype.hasOwnProperty.call(value, "is");
|
|
2050
|
+
const hasIsNot = Object.prototype.hasOwnProperty.call(value, "isNot");
|
|
2051
|
+
let filterKey;
|
|
2052
|
+
let filterVal;
|
|
2053
|
+
if (hasIs) {
|
|
2054
|
+
filterKey = "is";
|
|
2055
|
+
filterVal = value.is;
|
|
2056
|
+
} else if (hasIsNot) {
|
|
2057
|
+
filterKey = "isNot";
|
|
2058
|
+
filterVal = value.isNot;
|
|
2059
|
+
} else {
|
|
2060
|
+
filterKey = "is";
|
|
2061
|
+
filterVal = value;
|
|
2173
2062
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
index++;
|
|
2180
|
-
return format(position);
|
|
2063
|
+
if (filterVal === void 0) {
|
|
2064
|
+
return Object.freeze({
|
|
2065
|
+
clause: DEFAULT_WHERE_CLAUSE,
|
|
2066
|
+
joins: NO_JOINS
|
|
2067
|
+
});
|
|
2181
2068
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2069
|
+
if (filterVal === null) {
|
|
2070
|
+
const wantNull = filterKey === "is";
|
|
2071
|
+
const clause2 = buildToOneNullCheck(
|
|
2072
|
+
field,
|
|
2073
|
+
ctx.alias,
|
|
2074
|
+
relTable,
|
|
2075
|
+
relAlias,
|
|
2076
|
+
join3,
|
|
2077
|
+
wantNull
|
|
2078
|
+
);
|
|
2079
|
+
return Object.freeze({
|
|
2080
|
+
clause: clause2,
|
|
2081
|
+
joins: NO_JOINS
|
|
2082
|
+
});
|
|
2185
2083
|
}
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2084
|
+
if (!isPlainObject(filterVal)) {
|
|
2085
|
+
throw createError(
|
|
2086
|
+
`Relation '${fieldName}' filter must be an object or null`,
|
|
2087
|
+
{
|
|
2088
|
+
field: fieldName,
|
|
2089
|
+
path: ctx.path,
|
|
2090
|
+
modelName: ctx.model.name,
|
|
2091
|
+
value: filterVal
|
|
2092
|
+
}
|
|
2093
|
+
);
|
|
2192
2094
|
}
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2095
|
+
const sub = whereBuilder.build(filterVal, __spreadProps(__spreadValues({}, ctx), {
|
|
2096
|
+
alias: relAlias,
|
|
2097
|
+
model: relModel,
|
|
2098
|
+
path: [...ctx.path, fieldName, filterKey],
|
|
2099
|
+
isSubquery: true,
|
|
2100
|
+
depth: ctx.depth + 1
|
|
2101
|
+
}));
|
|
2102
|
+
const clause = filterKey === "is" ? buildToOneExistsMatch(relTable, relAlias, join3, sub) : buildToOneNotExistsMatch(relTable, relAlias, join3, sub);
|
|
2103
|
+
return Object.freeze({
|
|
2104
|
+
clause,
|
|
2105
|
+
joins: NO_JOINS
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
function ensureRelationFilterObject(fieldName, value, ctx) {
|
|
2109
|
+
if (!isPlainObject(value)) {
|
|
2110
|
+
throw createError(`Relation filter '${fieldName}' must be an object`, {
|
|
2111
|
+
path: [...ctx.path, fieldName],
|
|
2112
|
+
field: fieldName,
|
|
2113
|
+
modelName: ctx.model.name,
|
|
2114
|
+
value
|
|
2198
2115
|
});
|
|
2199
2116
|
}
|
|
2200
|
-
return {
|
|
2201
|
-
add,
|
|
2202
|
-
addAuto,
|
|
2203
|
-
snapshot,
|
|
2204
|
-
get index() {
|
|
2205
|
-
return index;
|
|
2206
|
-
}
|
|
2207
|
-
};
|
|
2208
2117
|
}
|
|
2209
|
-
function
|
|
2210
|
-
|
|
2211
|
-
|
|
2118
|
+
function buildRelation(fieldName, value, ctx, whereBuilder) {
|
|
2119
|
+
const field = ctx.model.fields.find((f) => f.name === fieldName);
|
|
2120
|
+
if (!isValidRelationField(field)) {
|
|
2121
|
+
throw createError(`Invalid relation '${fieldName}'`, {
|
|
2122
|
+
field: fieldName,
|
|
2123
|
+
path: ctx.path,
|
|
2124
|
+
modelName: ctx.model.name
|
|
2125
|
+
});
|
|
2212
2126
|
}
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2127
|
+
const relModel = ctx.schemaModels.find((m) => m.name === field.relatedModel);
|
|
2128
|
+
if (!isNotNullish(relModel)) {
|
|
2129
|
+
throw createError(
|
|
2130
|
+
`Related model '${field.relatedModel}' not found in schema. Available models: ${ctx.schemaModels.map((m) => m.name).join(", ")}`,
|
|
2131
|
+
{
|
|
2132
|
+
field: fieldName,
|
|
2133
|
+
path: ctx.path,
|
|
2134
|
+
modelName: ctx.model.name
|
|
2135
|
+
}
|
|
2216
2136
|
);
|
|
2217
2137
|
}
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
return createStoreInternal(
|
|
2223
|
-
nextIndex,
|
|
2224
|
-
[...existingParams],
|
|
2225
|
-
[...existingMappings]
|
|
2138
|
+
const relTable = buildTableReference(
|
|
2139
|
+
SQL_TEMPLATES.PUBLIC_SCHEMA,
|
|
2140
|
+
relModel.tableName,
|
|
2141
|
+
ctx.dialect
|
|
2226
2142
|
);
|
|
2143
|
+
const relAlias = ctx.aliasGen.next(fieldName);
|
|
2144
|
+
const join3 = joinCondition(field, ctx.model, relModel, ctx.alias, relAlias);
|
|
2145
|
+
const args = {
|
|
2146
|
+
fieldName,
|
|
2147
|
+
value,
|
|
2148
|
+
ctx,
|
|
2149
|
+
whereBuilder,
|
|
2150
|
+
field,
|
|
2151
|
+
relModel,
|
|
2152
|
+
relTable,
|
|
2153
|
+
relAlias,
|
|
2154
|
+
join: join3
|
|
2155
|
+
};
|
|
2156
|
+
if (isListRelation(field.type)) return buildListRelationFilters(args);
|
|
2157
|
+
return buildToOneRelationFilters(args);
|
|
2158
|
+
}
|
|
2159
|
+
function buildTopLevelRelation(fieldName, value, ctx, whereBuilder) {
|
|
2160
|
+
ensureRelationFilterObject(fieldName, value, ctx);
|
|
2161
|
+
return buildRelation(fieldName, value, ctx, whereBuilder);
|
|
2162
|
+
}
|
|
2163
|
+
function buildNestedRelation(fieldName, value, ctx, whereBuilder) {
|
|
2164
|
+
return buildTopLevelRelation(fieldName, value, ctx, whereBuilder);
|
|
2227
2165
|
}
|
|
2228
2166
|
|
|
2229
|
-
// src/builder/shared/
|
|
2230
|
-
function
|
|
2231
|
-
const
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2167
|
+
// src/builder/shared/validators/field-validators.ts
|
|
2168
|
+
function assertFieldExists(name, model, path) {
|
|
2169
|
+
const field = model.fields.find((f) => f.name === name);
|
|
2170
|
+
if (!isNotNullish(field)) {
|
|
2171
|
+
throw createError(`Field '${name}' does not exist on '${model.name}'`, {
|
|
2172
|
+
field: name,
|
|
2173
|
+
path,
|
|
2174
|
+
modelName: model.name,
|
|
2175
|
+
availableFields: model.fields.map((f) => f.name)
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
return field;
|
|
2179
|
+
}
|
|
2180
|
+
function assertValidOperator(fieldName, op, fieldType, path, modelName) {
|
|
2181
|
+
if (!isNotNullish(fieldType)) return;
|
|
2182
|
+
const ARRAY_OPS = /* @__PURE__ */ new Set([
|
|
2183
|
+
Ops.HAS,
|
|
2184
|
+
Ops.HAS_SOME,
|
|
2185
|
+
Ops.HAS_EVERY,
|
|
2186
|
+
Ops.IS_EMPTY
|
|
2187
|
+
]);
|
|
2188
|
+
const JSON_OPS = /* @__PURE__ */ new Set([
|
|
2189
|
+
Ops.PATH,
|
|
2190
|
+
Ops.STRING_CONTAINS,
|
|
2191
|
+
Ops.STRING_STARTS_WITH,
|
|
2192
|
+
Ops.STRING_ENDS_WITH
|
|
2193
|
+
]);
|
|
2194
|
+
const isArrayOp = ARRAY_OPS.has(op);
|
|
2195
|
+
const isFieldArray = isArrayType(fieldType);
|
|
2196
|
+
const arrayOpMismatch = isArrayOp && !isFieldArray;
|
|
2197
|
+
if (arrayOpMismatch) {
|
|
2198
|
+
throw createError(`'${op}' requires array field, got '${fieldType}'`, {
|
|
2199
|
+
operator: op,
|
|
2200
|
+
field: fieldName,
|
|
2201
|
+
path,
|
|
2202
|
+
modelName
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
const isJsonOp = JSON_OPS.has(op);
|
|
2206
|
+
const isFieldJson = isJsonType(fieldType);
|
|
2207
|
+
const jsonOpMismatch = isJsonOp && !isFieldJson;
|
|
2208
|
+
if (jsonOpMismatch) {
|
|
2209
|
+
throw createError(`'${op}' requires JSON field, got '${fieldType}'`, {
|
|
2210
|
+
operator: op,
|
|
2211
|
+
field: fieldName,
|
|
2212
|
+
path,
|
|
2213
|
+
modelName
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2239
2216
|
}
|
|
2240
2217
|
|
|
2241
|
-
// src/builder/where.ts
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
schemaModels: (_b = options.schemaModels) != null ? _b : [],
|
|
2250
|
-
path: (_c = options.path) != null ? _c : [],
|
|
2251
|
-
isSubquery: (_d = options.isSubquery) != null ? _d : false,
|
|
2252
|
-
aliasGen: (_e = options.aliasGen) != null ? _e : createAliasGenerator(),
|
|
2253
|
-
dialect,
|
|
2254
|
-
params,
|
|
2255
|
-
depth: 0
|
|
2256
|
-
};
|
|
2257
|
-
const result = whereBuilderInstance.build(where, ctx);
|
|
2258
|
-
const publicResult = toPublicResult(result.clause, result.joins, params);
|
|
2259
|
-
if (!options.isSubquery) {
|
|
2260
|
-
const nums = [...publicResult.clause.matchAll(/\$(\d+)/g)].map(
|
|
2261
|
-
(m) => parseInt(m[1], 10)
|
|
2262
|
-
);
|
|
2263
|
-
if (nums.length > 0) {
|
|
2264
|
-
const min = Math.min(...nums);
|
|
2265
|
-
if (min === 1) {
|
|
2266
|
-
validateParamConsistency(publicResult.clause, publicResult.params);
|
|
2267
|
-
} else {
|
|
2268
|
-
validateParamConsistencyFragment(
|
|
2269
|
-
publicResult.clause,
|
|
2270
|
-
publicResult.params
|
|
2271
|
-
);
|
|
2272
|
-
}
|
|
2218
|
+
// src/builder/where/builder.ts
|
|
2219
|
+
var WhereBuilder = class {
|
|
2220
|
+
build(where, ctx) {
|
|
2221
|
+
if (!isPlainObject(where)) {
|
|
2222
|
+
throw createError("where must be an object", {
|
|
2223
|
+
path: ctx.path,
|
|
2224
|
+
modelName: ctx.model.name
|
|
2225
|
+
});
|
|
2273
2226
|
}
|
|
2227
|
+
return buildWhereInternal(where, ctx, this);
|
|
2274
2228
|
}
|
|
2275
|
-
|
|
2229
|
+
};
|
|
2230
|
+
var MAX_QUERY_DEPTH = 50;
|
|
2231
|
+
var EMPTY_JOINS = Object.freeze([]);
|
|
2232
|
+
var whereBuilderInstance = new WhereBuilder();
|
|
2233
|
+
function freezeResult(clause, joins = EMPTY_JOINS) {
|
|
2234
|
+
return Object.freeze({ clause, joins });
|
|
2276
2235
|
}
|
|
2277
|
-
function
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
if (!allowZero && v === 0) {
|
|
2287
|
-
throw new Error(`${name} must be > 0`);
|
|
2288
|
-
}
|
|
2289
|
-
if (v < min) {
|
|
2290
|
-
throw new Error(`${name} must be >= ${min}`);
|
|
2291
|
-
}
|
|
2292
|
-
if (typeof opts.max === "number" && v > opts.max) {
|
|
2293
|
-
throw new Error(`${name} must be <= ${opts.max}`);
|
|
2236
|
+
function dedupePreserveOrder(items) {
|
|
2237
|
+
if (items.length <= 1) return Object.freeze([...items]);
|
|
2238
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2239
|
+
const out = [];
|
|
2240
|
+
for (const s of items) {
|
|
2241
|
+
if (!seen.has(s)) {
|
|
2242
|
+
seen.add(s);
|
|
2243
|
+
out.push(s);
|
|
2244
|
+
}
|
|
2294
2245
|
}
|
|
2295
|
-
return
|
|
2246
|
+
return Object.freeze(out);
|
|
2296
2247
|
}
|
|
2297
|
-
function
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
if (s.length === 0) return dn;
|
|
2301
|
-
return `${s}:${dn}`;
|
|
2248
|
+
function appendResult(result, clauses, allJoins) {
|
|
2249
|
+
if (isValidWhereClause(result.clause)) clauses.push(result.clause);
|
|
2250
|
+
if (isNonEmptyArray(result.joins)) allJoins.push(...result.joins);
|
|
2302
2251
|
}
|
|
2303
|
-
function
|
|
2304
|
-
if (
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
return params.add(value);
|
|
2252
|
+
function asLogicalOperator(key) {
|
|
2253
|
+
if (key === LogicalOps.AND) return "AND";
|
|
2254
|
+
if (key === LogicalOps.OR) return "OR";
|
|
2255
|
+
if (key === LogicalOps.NOT) return "NOT";
|
|
2256
|
+
return null;
|
|
2309
2257
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
if (
|
|
2316
|
-
|
|
2317
|
-
};
|
|
2318
|
-
var flipSortString = (v) => {
|
|
2319
|
-
if (typeof v !== "string") return v;
|
|
2320
|
-
const s = v.toLowerCase();
|
|
2321
|
-
if (s === "asc") return "desc";
|
|
2322
|
-
if (s === "desc") return "asc";
|
|
2323
|
-
return v;
|
|
2324
|
-
};
|
|
2325
|
-
var getNextSort = (sortRaw) => {
|
|
2326
|
-
if (typeof sortRaw !== "string") return sortRaw;
|
|
2327
|
-
const s = sortRaw.toLowerCase();
|
|
2328
|
-
if (s === "asc") return "desc";
|
|
2329
|
-
if (s === "desc") return "asc";
|
|
2330
|
-
return sortRaw;
|
|
2331
|
-
};
|
|
2332
|
-
var flipObjectSort = (obj) => {
|
|
2333
|
-
const sortRaw = obj.sort;
|
|
2334
|
-
const out = __spreadProps(__spreadValues({}, obj), { sort: getNextSort(sortRaw) });
|
|
2335
|
-
const nullsRaw = obj.nulls;
|
|
2336
|
-
if (typeof nullsRaw === "string") {
|
|
2337
|
-
out.nulls = flipNulls(nullsRaw);
|
|
2338
|
-
}
|
|
2339
|
-
return out;
|
|
2340
|
-
};
|
|
2341
|
-
var flipValue = (v) => {
|
|
2342
|
-
if (typeof v === "string") return flipSortString(v);
|
|
2343
|
-
if (isPlainObject(v)) return flipObjectSort(v);
|
|
2344
|
-
return v;
|
|
2345
|
-
};
|
|
2346
|
-
var assertSingleFieldObject = (item) => {
|
|
2347
|
-
if (!isPlainObject(item)) {
|
|
2348
|
-
throw new Error("orderBy array entries must be objects");
|
|
2258
|
+
function nextContext(ctx) {
|
|
2259
|
+
return __spreadProps(__spreadValues({}, ctx), { depth: ctx.depth + 1 });
|
|
2260
|
+
}
|
|
2261
|
+
function buildRelationFilter(fieldName, value, ctx, builder) {
|
|
2262
|
+
const ctx2 = nextContext(ctx);
|
|
2263
|
+
if (ctx.isSubquery) {
|
|
2264
|
+
return buildNestedRelation(fieldName, value, ctx2, builder);
|
|
2349
2265
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2266
|
+
return buildTopLevelRelation(fieldName, value, ctx2, builder);
|
|
2267
|
+
}
|
|
2268
|
+
function buildWhereEntry(key, value, ctx, builder) {
|
|
2269
|
+
const op = asLogicalOperator(key);
|
|
2270
|
+
if (op) return buildLogical(op, value, ctx, builder);
|
|
2271
|
+
if (isRelationField(key, ctx.model)) {
|
|
2272
|
+
if (!isPlainObject(value)) {
|
|
2273
|
+
throw createError(`Relation filter '${key}' must be an object`, {
|
|
2274
|
+
path: [...ctx.path, key],
|
|
2275
|
+
field: key,
|
|
2276
|
+
modelName: ctx.model.name,
|
|
2277
|
+
value
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
return buildRelationFilter(key, value, ctx, builder);
|
|
2353
2281
|
}
|
|
2354
|
-
return
|
|
2355
|
-
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
var flipOrderByObject = (orderBy) => {
|
|
2363
|
-
const out = {};
|
|
2364
|
-
for (const [k, v] of Object.entries(orderBy)) {
|
|
2365
|
-
out[k] = flipValue(v);
|
|
2282
|
+
return buildScalarField(key, value, ctx);
|
|
2283
|
+
}
|
|
2284
|
+
function buildWhereInternal(where, ctx, builder) {
|
|
2285
|
+
if (ctx.depth > MAX_QUERY_DEPTH) {
|
|
2286
|
+
throw createError(
|
|
2287
|
+
`Query nesting too deep (max ${MAX_QUERY_DEPTH} levels). This usually indicates a circular reference.`,
|
|
2288
|
+
{ path: ctx.path, modelName: ctx.model.name }
|
|
2289
|
+
);
|
|
2366
2290
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
function reverseOrderByInput(orderBy) {
|
|
2370
|
-
if (!isNotNullish(orderBy)) return orderBy;
|
|
2371
|
-
if (Array.isArray(orderBy)) {
|
|
2372
|
-
return flipOrderByArray(orderBy);
|
|
2291
|
+
if (isEmptyWhere(where)) {
|
|
2292
|
+
return freezeResult(DEFAULT_WHERE_CLAUSE, EMPTY_JOINS);
|
|
2373
2293
|
}
|
|
2374
|
-
|
|
2375
|
-
|
|
2294
|
+
const allJoins = [];
|
|
2295
|
+
const clauses = [];
|
|
2296
|
+
for (const [key, value] of Object.entries(where)) {
|
|
2297
|
+
if (value === void 0) continue;
|
|
2298
|
+
const result = buildWhereEntry(key, value, ctx, builder);
|
|
2299
|
+
appendResult(result, clauses, allJoins);
|
|
2376
2300
|
}
|
|
2377
|
-
|
|
2301
|
+
const finalClause = clauses.length > 0 ? clauses.join(SQL_SEPARATORS.CONDITION_AND) : DEFAULT_WHERE_CLAUSE;
|
|
2302
|
+
return freezeResult(finalClause, dedupePreserveOrder(allJoins));
|
|
2378
2303
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
const
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
}
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2304
|
+
function normalizeLogicalValue(operator, value, ctx) {
|
|
2305
|
+
if (Array.isArray(value)) {
|
|
2306
|
+
const out = [];
|
|
2307
|
+
for (let i = 0; i < value.length; i++) {
|
|
2308
|
+
const v = value[i];
|
|
2309
|
+
if (v === void 0) continue;
|
|
2310
|
+
if (!isPlainObject(v)) {
|
|
2311
|
+
throw createError(`${operator} entries must be objects`, {
|
|
2312
|
+
path: [...ctx.path, operator, String(i)],
|
|
2313
|
+
modelName: ctx.model.name,
|
|
2314
|
+
value: v
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
out.push(v);
|
|
2318
|
+
}
|
|
2319
|
+
return out;
|
|
2392
2320
|
}
|
|
2393
|
-
if (isPlainObject(
|
|
2394
|
-
return
|
|
2321
|
+
if (isPlainObject(value)) {
|
|
2322
|
+
return [value];
|
|
2395
2323
|
}
|
|
2396
|
-
throw
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
function parseDirectionRaw(raw, errorLabel) {
|
|
2402
|
-
const s = String(raw).toLowerCase();
|
|
2403
|
-
if (s === "asc" || s === "desc") return s;
|
|
2404
|
-
throw new Error(`Invalid ${errorLabel}: ${raw}`);
|
|
2324
|
+
throw createError(`${operator} must be an object or array of objects`, {
|
|
2325
|
+
path: [...ctx.path, operator],
|
|
2326
|
+
modelName: ctx.model.name,
|
|
2327
|
+
value
|
|
2328
|
+
});
|
|
2405
2329
|
}
|
|
2406
|
-
function
|
|
2407
|
-
|
|
2408
|
-
const
|
|
2409
|
-
|
|
2410
|
-
|
|
2330
|
+
function collectLogicalParts(operator, conditions, ctx, builder) {
|
|
2331
|
+
const allJoins = [];
|
|
2332
|
+
const clauses = [];
|
|
2333
|
+
for (let i = 0; i < conditions.length; i++) {
|
|
2334
|
+
const result = builder.build(conditions[i], __spreadProps(__spreadValues({}, ctx), {
|
|
2335
|
+
path: [...ctx.path, operator, String(i)],
|
|
2336
|
+
depth: ctx.depth + 1
|
|
2337
|
+
}));
|
|
2338
|
+
if (isNonEmptyArray(result.joins)) allJoins.push(...result.joins);
|
|
2339
|
+
if (result.clause && result.clause !== DEFAULT_WHERE_CLAUSE) {
|
|
2340
|
+
clauses.push(`(${result.clause})`);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
return {
|
|
2344
|
+
joins: dedupePreserveOrder(allJoins),
|
|
2345
|
+
clauses: Object.freeze(clauses)
|
|
2346
|
+
};
|
|
2411
2347
|
}
|
|
2412
|
-
function
|
|
2413
|
-
if (
|
|
2414
|
-
|
|
2348
|
+
function buildLogicalClause(operator, clauses) {
|
|
2349
|
+
if (clauses.length === 0) return DEFAULT_WHERE_CLAUSE;
|
|
2350
|
+
if (operator === "NOT") {
|
|
2351
|
+
if (clauses.length === 1) return `${SQL_TEMPLATES.NOT} ${clauses[0]}`;
|
|
2352
|
+
return `${SQL_TEMPLATES.NOT} (${clauses.join(SQL_SEPARATORS.CONDITION_AND)})`;
|
|
2415
2353
|
}
|
|
2416
|
-
return
|
|
2354
|
+
return clauses.join(` ${operator} `);
|
|
2417
2355
|
}
|
|
2418
|
-
function
|
|
2419
|
-
const
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
fieldName ? `Unsupported orderBy key '${k}' for field '${fieldName}'` : `Unsupported orderBy key '${k}'`
|
|
2424
|
-
);
|
|
2425
|
-
}
|
|
2356
|
+
function buildLogical(operator, value, ctx, builder) {
|
|
2357
|
+
const conditions = normalizeLogicalValue(operator, value, ctx);
|
|
2358
|
+
if (conditions.length === 0) {
|
|
2359
|
+
const clause2 = operator === "OR" ? "0=1" : DEFAULT_WHERE_CLAUSE;
|
|
2360
|
+
return freezeResult(clause2, EMPTY_JOINS);
|
|
2426
2361
|
}
|
|
2362
|
+
const { joins, clauses } = collectLogicalParts(
|
|
2363
|
+
operator,
|
|
2364
|
+
conditions,
|
|
2365
|
+
ctx,
|
|
2366
|
+
builder
|
|
2367
|
+
);
|
|
2368
|
+
const clause = buildLogicalClause(operator, clauses);
|
|
2369
|
+
return freezeResult(clause, joins);
|
|
2427
2370
|
}
|
|
2428
|
-
function
|
|
2429
|
-
const
|
|
2430
|
-
|
|
2431
|
-
|
|
2371
|
+
function buildScalarField(fieldName, value, ctx) {
|
|
2372
|
+
const field = assertFieldExists(fieldName, ctx.model, ctx.path);
|
|
2373
|
+
const expr = col(ctx.alias, fieldName, ctx.model);
|
|
2374
|
+
if (value === null) {
|
|
2375
|
+
return freezeResult(`${expr} ${SQL_TEMPLATES.IS_NULL}`, EMPTY_JOINS);
|
|
2432
2376
|
}
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2377
|
+
if (isPlainObject(value)) {
|
|
2378
|
+
const mode = value.mode;
|
|
2379
|
+
const ops = Object.entries(value).filter(
|
|
2380
|
+
([k, v]) => k !== "mode" && v !== void 0
|
|
2381
|
+
);
|
|
2382
|
+
if (ops.length === 0) {
|
|
2383
|
+
return freezeResult(DEFAULT_WHERE_CLAUSE, EMPTY_JOINS);
|
|
2384
|
+
}
|
|
2385
|
+
const parts = [];
|
|
2386
|
+
for (const [op, val] of ops) {
|
|
2387
|
+
assertValidOperator(fieldName, op, field.type, ctx.path, ctx.model.name);
|
|
2388
|
+
const clause3 = buildOperator(expr, op, val, ctx, mode, field.type);
|
|
2389
|
+
if (isValidWhereClause(clause3)) parts.push(clause3);
|
|
2390
|
+
}
|
|
2391
|
+
const clause2 = parts.length > 0 ? parts.join(SQL_SEPARATORS.CONDITION_AND) : DEFAULT_WHERE_CLAUSE;
|
|
2392
|
+
return freezeResult(clause2, EMPTY_JOINS);
|
|
2442
2393
|
}
|
|
2443
|
-
|
|
2394
|
+
const clause = buildOperator(
|
|
2395
|
+
expr,
|
|
2396
|
+
Ops.EQUALS,
|
|
2397
|
+
value,
|
|
2398
|
+
ctx,
|
|
2399
|
+
void 0,
|
|
2400
|
+
field.type
|
|
2401
|
+
);
|
|
2402
|
+
return freezeResult(clause || DEFAULT_WHERE_CLAUSE, EMPTY_JOINS);
|
|
2444
2403
|
}
|
|
2445
|
-
function
|
|
2446
|
-
if (
|
|
2447
|
-
|
|
2448
|
-
if (n < 0) {
|
|
2449
|
-
throw new Error(`${name} must be >= 0`);
|
|
2404
|
+
function buildOperator(expr, op, val, ctx, mode, fieldType) {
|
|
2405
|
+
if (fieldType && isArrayType(fieldType)) {
|
|
2406
|
+
return buildArrayOperator(expr, op, val, ctx.params, fieldType, ctx.dialect);
|
|
2450
2407
|
}
|
|
2451
|
-
if (
|
|
2452
|
-
|
|
2408
|
+
if (fieldType && isJsonType(fieldType)) {
|
|
2409
|
+
const JSON_OPS = /* @__PURE__ */ new Set([
|
|
2410
|
+
Ops.PATH,
|
|
2411
|
+
Ops.STRING_CONTAINS,
|
|
2412
|
+
Ops.STRING_STARTS_WITH,
|
|
2413
|
+
Ops.STRING_ENDS_WITH
|
|
2414
|
+
]);
|
|
2415
|
+
if (JSON_OPS.has(op)) {
|
|
2416
|
+
return buildJsonOperator(expr, op, val, ctx.params, ctx.dialect);
|
|
2417
|
+
}
|
|
2453
2418
|
}
|
|
2454
|
-
return
|
|
2419
|
+
return buildScalarOperator(
|
|
2420
|
+
expr,
|
|
2421
|
+
op,
|
|
2422
|
+
val,
|
|
2423
|
+
ctx.params,
|
|
2424
|
+
mode,
|
|
2425
|
+
fieldType,
|
|
2426
|
+
ctx.dialect
|
|
2427
|
+
);
|
|
2455
2428
|
}
|
|
2456
|
-
|
|
2457
|
-
|
|
2429
|
+
|
|
2430
|
+
// src/builder/shared/alias-generator.ts
|
|
2431
|
+
function toSafeSqlIdentifier(input) {
|
|
2432
|
+
const raw = String(input);
|
|
2433
|
+
const cleaned = raw.replace(/\W/g, "_");
|
|
2434
|
+
const startsOk = /^[a-zA-Z_]/.test(cleaned);
|
|
2435
|
+
const base = startsOk ? cleaned : `_${cleaned}`;
|
|
2436
|
+
const fallback = base.length > 0 ? base : "_t";
|
|
2437
|
+
const lowered = fallback.toLowerCase();
|
|
2438
|
+
return SQL_KEYWORDS.has(lowered) ? `_${lowered}` : lowered;
|
|
2458
2439
|
}
|
|
2459
|
-
function
|
|
2460
|
-
|
|
2461
|
-
|
|
2440
|
+
function createAliasGenerator(maxAliases = 1e4) {
|
|
2441
|
+
let counter = 0;
|
|
2442
|
+
const usedAliases = /* @__PURE__ */ new Set();
|
|
2443
|
+
return {
|
|
2444
|
+
next(baseName) {
|
|
2445
|
+
if (usedAliases.size >= maxAliases) {
|
|
2446
|
+
throw new Error(
|
|
2447
|
+
`Alias generator exceeded maximum of ${maxAliases} aliases. This indicates a query complexity issue or potential infinite loop.`
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
const base = toSafeSqlIdentifier(baseName);
|
|
2451
|
+
const suffix = `_${counter}`;
|
|
2452
|
+
const maxLen = 63;
|
|
2453
|
+
const baseMax = Math.max(1, maxLen - suffix.length);
|
|
2454
|
+
const trimmedBase = base.length > baseMax ? base.slice(0, baseMax) : base;
|
|
2455
|
+
const alias = `${trimmedBase}${suffix}`;
|
|
2456
|
+
counter += 1;
|
|
2457
|
+
if (usedAliases.has(alias)) {
|
|
2458
|
+
throw new Error(
|
|
2459
|
+
`CRITICAL: Duplicate alias '${alias}' at counter=${counter}. This indicates a bug in alias generation logic.`
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
usedAliases.add(alias);
|
|
2463
|
+
return alias;
|
|
2464
|
+
}
|
|
2465
|
+
};
|
|
2462
2466
|
}
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
hasTake: false,
|
|
2470
|
-
skipVal: void 0,
|
|
2471
|
-
takeVal: void 0
|
|
2472
|
-
};
|
|
2467
|
+
var MAX_PARAM_INDEX = Number.MAX_SAFE_INTEGER - 1e3;
|
|
2468
|
+
function assertSameLength(params, mappings) {
|
|
2469
|
+
if (params.length !== mappings.length) {
|
|
2470
|
+
throw new Error(
|
|
2471
|
+
`CRITICAL: State corruption - params=${params.length}, mappings=${mappings.length}`
|
|
2472
|
+
);
|
|
2473
2473
|
}
|
|
2474
|
-
const obj = relArgs;
|
|
2475
|
-
const skipVal = hasSkip ? normalizeNonNegativeInt("skip", obj.skip) : void 0;
|
|
2476
|
-
const takeVal = hasTake ? normalizeIntegerOrDynamic("take", obj.take) : void 0;
|
|
2477
|
-
return { hasSkip, hasTake, skipVal, takeVal };
|
|
2478
2474
|
}
|
|
2479
|
-
function
|
|
2480
|
-
if (
|
|
2481
|
-
|
|
2482
|
-
for (const e of entries) {
|
|
2483
|
-
const dir = e.direction.toUpperCase();
|
|
2484
|
-
const c = col(alias, e.field, model);
|
|
2485
|
-
if (dialect === "postgres") {
|
|
2486
|
-
const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
|
|
2487
|
-
out.push(`${c} ${dir}${nulls}`);
|
|
2488
|
-
continue;
|
|
2489
|
-
}
|
|
2490
|
-
if (isNotNullish(e.nulls)) {
|
|
2491
|
-
const isNullExpr = `(${c} IS NULL)`;
|
|
2492
|
-
const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
|
|
2493
|
-
out.push(`${isNullExpr} ${nullRankDir}`);
|
|
2494
|
-
out.push(`${c} ${dir}`);
|
|
2495
|
-
continue;
|
|
2496
|
-
}
|
|
2497
|
-
out.push(`${c} ${dir}`);
|
|
2475
|
+
function assertValidNextIndex(index) {
|
|
2476
|
+
if (!Number.isInteger(index) || index < 1) {
|
|
2477
|
+
throw new Error(`CRITICAL: Index must be integer >= 1, got ${index}`);
|
|
2498
2478
|
}
|
|
2499
|
-
return out.join(SQL_SEPARATORS.ORDER_BY);
|
|
2500
2479
|
}
|
|
2501
|
-
function
|
|
2502
|
-
|
|
2503
|
-
|
|
2480
|
+
function assertNextIndexMatches(mappingsLength, nextIndex) {
|
|
2481
|
+
const expected = mappingsLength + 1;
|
|
2482
|
+
if (nextIndex !== expected) {
|
|
2483
|
+
throw new Error(
|
|
2484
|
+
`CRITICAL: Next index mismatch - expected ${expected}, got ${nextIndex}`
|
|
2485
|
+
);
|
|
2504
2486
|
}
|
|
2505
|
-
return direction === "asc" ? "first" : "last";
|
|
2506
2487
|
}
|
|
2507
|
-
function
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
if (!existing.has(field)) {
|
|
2513
|
-
out.push({ field, direction: "asc" });
|
|
2514
|
-
existing.set(field, out[out.length - 1]);
|
|
2515
|
-
}
|
|
2488
|
+
function assertSequentialIndex(actual, expected) {
|
|
2489
|
+
if (actual !== expected) {
|
|
2490
|
+
throw new Error(
|
|
2491
|
+
`CRITICAL: Indices must be sequential from 1..N. Expected ${expected}, got ${actual}`
|
|
2492
|
+
);
|
|
2516
2493
|
}
|
|
2517
|
-
return out;
|
|
2518
2494
|
}
|
|
2519
|
-
function
|
|
2520
|
-
const
|
|
2521
|
-
|
|
2522
|
-
|
|
2495
|
+
function assertExactlyOneOfDynamicOrValue(m) {
|
|
2496
|
+
const hasDynamic = typeof m.dynamicName === "string";
|
|
2497
|
+
const hasStatic = m.value !== void 0;
|
|
2498
|
+
if (hasDynamic === hasStatic) {
|
|
2499
|
+
throw new Error(
|
|
2500
|
+
`CRITICAL: ParamMap ${m.index} must have exactly one of dynamicName or value`
|
|
2501
|
+
);
|
|
2523
2502
|
}
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
parts.push(`${c} IS NULL`);
|
|
2530
|
-
continue;
|
|
2531
|
-
}
|
|
2532
|
-
const ph = addAutoScoped(params, value, `cursor.filter.${field}`);
|
|
2533
|
-
placeholdersByField.set(field, ph);
|
|
2534
|
-
parts.push(`${c} = ${ph}`);
|
|
2503
|
+
}
|
|
2504
|
+
function normalizeDynamicNameOrThrow(dynamicName, index) {
|
|
2505
|
+
const dn = dynamicName.trim();
|
|
2506
|
+
if (dn.length === 0) {
|
|
2507
|
+
throw new Error(`CRITICAL: dynamicName cannot be empty (index=${index})`);
|
|
2535
2508
|
}
|
|
2536
|
-
return
|
|
2537
|
-
whereSql: parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`,
|
|
2538
|
-
placeholdersByField
|
|
2539
|
-
};
|
|
2509
|
+
return dn;
|
|
2540
2510
|
}
|
|
2541
|
-
function
|
|
2542
|
-
|
|
2543
|
-
|
|
2511
|
+
function assertUniqueDynamicName(dn, seen) {
|
|
2512
|
+
if (seen.has(dn)) {
|
|
2513
|
+
throw new Error(`CRITICAL: Duplicate dynamic param name in mappings: ${dn}`);
|
|
2514
|
+
}
|
|
2515
|
+
seen.add(dn);
|
|
2544
2516
|
}
|
|
2545
|
-
function
|
|
2546
|
-
|
|
2517
|
+
function validateMappingEntry(m, expectedIndex, seenDynamic) {
|
|
2518
|
+
assertSequentialIndex(m.index, expectedIndex);
|
|
2519
|
+
assertExactlyOneOfDynamicOrValue(m);
|
|
2520
|
+
if (typeof m.dynamicName === "string") {
|
|
2521
|
+
const dn = normalizeDynamicNameOrThrow(m.dynamicName, m.index);
|
|
2522
|
+
assertUniqueDynamicName(dn, seenDynamic);
|
|
2523
|
+
}
|
|
2547
2524
|
}
|
|
2548
|
-
function
|
|
2549
|
-
|
|
2525
|
+
function validateMappings(mappings) {
|
|
2526
|
+
const seenDynamic = /* @__PURE__ */ new Set();
|
|
2527
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
2528
|
+
validateMappingEntry(mappings[i], i + 1, seenDynamic);
|
|
2529
|
+
}
|
|
2550
2530
|
}
|
|
2551
|
-
function
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2531
|
+
function validateState(params, mappings, index) {
|
|
2532
|
+
assertSameLength(params, mappings);
|
|
2533
|
+
assertValidNextIndex(index);
|
|
2534
|
+
if (mappings.length === 0) return;
|
|
2535
|
+
validateMappings(mappings);
|
|
2536
|
+
assertNextIndexMatches(mappings.length, index);
|
|
2537
|
+
}
|
|
2538
|
+
function normalizeValue(value) {
|
|
2539
|
+
if (value instanceof Date) {
|
|
2540
|
+
return value.toISOString();
|
|
2555
2541
|
}
|
|
2556
|
-
return
|
|
2542
|
+
return value;
|
|
2557
2543
|
}
|
|
2558
|
-
function
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2544
|
+
function createStoreInternal(startIndex, initialParams = [], initialMappings = []) {
|
|
2545
|
+
let index = startIndex;
|
|
2546
|
+
const params = [...initialParams];
|
|
2547
|
+
const mappings = [...initialMappings];
|
|
2548
|
+
const dynamicNameToIndex = /* @__PURE__ */ new Map();
|
|
2549
|
+
for (const m of initialMappings) {
|
|
2550
|
+
if (typeof m.dynamicName === "string") {
|
|
2551
|
+
dynamicNameToIndex.set(m.dynamicName.trim(), m.index);
|
|
2565
2552
|
}
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2553
|
+
}
|
|
2554
|
+
function assertCanAdd() {
|
|
2555
|
+
if (index > MAX_PARAM_INDEX) {
|
|
2556
|
+
throw new Error(
|
|
2557
|
+
`CRITICAL: Cannot add param - would overflow MAX_SAFE_INTEGER. Current index: ${index}`
|
|
2558
|
+
);
|
|
2570
2559
|
}
|
|
2571
|
-
const ph = addAutoScoped(params, value, `cursor.outerMatch.${field}`);
|
|
2572
|
-
parts.push(`${c} = ${ph}`);
|
|
2573
2560
|
}
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
const entries = [];
|
|
2579
|
-
for (const item of normalized) {
|
|
2580
|
-
for (const [field, value] of Object.entries(item)) {
|
|
2581
|
-
if (typeof value === "string") {
|
|
2582
|
-
entries.push({ field, direction: value });
|
|
2583
|
-
} else {
|
|
2584
|
-
entries.push({
|
|
2585
|
-
field,
|
|
2586
|
-
direction: value.sort,
|
|
2587
|
-
nulls: value.nulls
|
|
2588
|
-
});
|
|
2589
|
-
}
|
|
2561
|
+
function normalizeDynamicName(dynamicName) {
|
|
2562
|
+
const dn = dynamicName.trim();
|
|
2563
|
+
if (dn.length === 0) {
|
|
2564
|
+
throw new Error("CRITICAL: dynamicName cannot be empty");
|
|
2590
2565
|
}
|
|
2566
|
+
return dn;
|
|
2591
2567
|
}
|
|
2592
|
-
|
|
2593
|
-
}
|
|
2594
|
-
function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
|
|
2595
|
-
var _a;
|
|
2596
|
-
const d = dialect != null ? dialect : getGlobalDialect();
|
|
2597
|
-
const cursorEntries = Object.entries(cursor);
|
|
2598
|
-
if (cursorEntries.length === 0) {
|
|
2599
|
-
throw new Error("cursor must have at least one field");
|
|
2568
|
+
function format(position) {
|
|
2569
|
+
return `$${position}`;
|
|
2600
2570
|
}
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2571
|
+
function addDynamic(dynamicName) {
|
|
2572
|
+
const dn = normalizeDynamicName(dynamicName);
|
|
2573
|
+
const existing = dynamicNameToIndex.get(dn);
|
|
2574
|
+
if (existing !== void 0) {
|
|
2575
|
+
return format(existing);
|
|
2576
|
+
}
|
|
2577
|
+
const position = index;
|
|
2578
|
+
dynamicNameToIndex.set(dn, position);
|
|
2579
|
+
params.push(void 0);
|
|
2580
|
+
mappings.push({ index: position, dynamicName: dn });
|
|
2581
|
+
index++;
|
|
2582
|
+
return format(position);
|
|
2611
2583
|
}
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
const e2 = orderEntries[i];
|
|
2629
|
-
const c2 = col(alias, e2.field, model);
|
|
2630
|
-
const v2 = cursorValueExpr(
|
|
2631
|
-
tableName,
|
|
2632
|
-
cursorAlias,
|
|
2633
|
-
cursorWhereSql,
|
|
2634
|
-
e2.field);
|
|
2635
|
-
andParts.push(buildCursorEqualityExpr(c2, v2));
|
|
2584
|
+
function addStatic(value) {
|
|
2585
|
+
const position = index;
|
|
2586
|
+
const normalizedValue = normalizeValue(value);
|
|
2587
|
+
params.push(normalizedValue);
|
|
2588
|
+
mappings.push({ index: position, value: normalizedValue });
|
|
2589
|
+
index++;
|
|
2590
|
+
return format(position);
|
|
2591
|
+
}
|
|
2592
|
+
function add(value, dynamicName) {
|
|
2593
|
+
assertCanAdd();
|
|
2594
|
+
return dynamicName === void 0 ? addStatic(value) : addDynamic(dynamicName);
|
|
2595
|
+
}
|
|
2596
|
+
function addAuto(value) {
|
|
2597
|
+
if (schemaParser.isDynamicParameter(value)) {
|
|
2598
|
+
const dynamicName = schemaParser.extractDynamicName(value);
|
|
2599
|
+
return add(void 0, dynamicName);
|
|
2636
2600
|
}
|
|
2637
|
-
|
|
2638
|
-
const c = col(alias, e.field, model);
|
|
2639
|
-
const v = cursorValueExpr(
|
|
2640
|
-
tableName,
|
|
2641
|
-
cursorAlias,
|
|
2642
|
-
cursorWhereSql,
|
|
2643
|
-
e.field);
|
|
2644
|
-
const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
|
|
2645
|
-
andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, v));
|
|
2646
|
-
orClauses.push(`(${andParts.join(SQL_SEPARATORS.CONDITION_AND)})`);
|
|
2601
|
+
return add(value);
|
|
2647
2602
|
}
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
return
|
|
2603
|
+
function snapshot() {
|
|
2604
|
+
return Object.freeze({
|
|
2605
|
+
index,
|
|
2606
|
+
params: Object.freeze([...params]),
|
|
2607
|
+
mappings: Object.freeze([...mappings])
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
return {
|
|
2611
|
+
add,
|
|
2612
|
+
addAuto,
|
|
2613
|
+
snapshot,
|
|
2614
|
+
get index() {
|
|
2615
|
+
return index;
|
|
2616
|
+
}
|
|
2617
|
+
};
|
|
2656
2618
|
}
|
|
2657
|
-
function
|
|
2658
|
-
if (!
|
|
2659
|
-
|
|
2660
|
-
|
|
2619
|
+
function createParamStore(startIndex = 1) {
|
|
2620
|
+
if (!Number.isInteger(startIndex) || startIndex < 1) {
|
|
2621
|
+
throw new Error(`Start index must be integer >= 1, got ${startIndex}`);
|
|
2622
|
+
}
|
|
2623
|
+
if (startIndex > MAX_PARAM_INDEX) {
|
|
2661
2624
|
throw new Error(
|
|
2662
|
-
|
|
2625
|
+
`Start index too high (${startIndex}), risk of overflow at MAX_SAFE_INTEGER`
|
|
2663
2626
|
);
|
|
2664
2627
|
}
|
|
2665
|
-
return
|
|
2628
|
+
return createStoreInternal(startIndex);
|
|
2666
2629
|
}
|
|
2667
|
-
function
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
if (n === 0) return 0;
|
|
2675
|
-
}
|
|
2676
|
-
return n;
|
|
2630
|
+
function createParamStoreFrom(existingParams, existingMappings, nextIndex) {
|
|
2631
|
+
validateState([...existingParams], [...existingMappings], nextIndex);
|
|
2632
|
+
return createStoreInternal(
|
|
2633
|
+
nextIndex,
|
|
2634
|
+
[...existingParams],
|
|
2635
|
+
[...existingMappings]
|
|
2636
|
+
);
|
|
2677
2637
|
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2638
|
+
|
|
2639
|
+
// src/builder/shared/state.ts
|
|
2640
|
+
function toPublicResult(clause, joins, params) {
|
|
2641
|
+
const snapshot = params.snapshot();
|
|
2642
|
+
return Object.freeze({
|
|
2643
|
+
clause: clause || DEFAULT_WHERE_CLAUSE,
|
|
2644
|
+
joins: Object.freeze([...joins]),
|
|
2645
|
+
params: snapshot.params,
|
|
2646
|
+
paramMappings: snapshot.mappings,
|
|
2647
|
+
nextParamIndex: snapshot.index
|
|
2683
2648
|
});
|
|
2684
2649
|
}
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2650
|
+
|
|
2651
|
+
// src/builder/where.ts
|
|
2652
|
+
function buildWhereClause(where, options) {
|
|
2653
|
+
var _a, _b, _c, _d, _e;
|
|
2654
|
+
const dialect = options.dialect || getGlobalDialect();
|
|
2655
|
+
const params = (_a = options.params) != null ? _a : createParamStore();
|
|
2656
|
+
const ctx = {
|
|
2657
|
+
alias: options.alias,
|
|
2658
|
+
model: options.model,
|
|
2659
|
+
schemaModels: (_b = options.schemaModels) != null ? _b : [],
|
|
2660
|
+
path: (_c = options.path) != null ? _c : [],
|
|
2661
|
+
isSubquery: (_d = options.isSubquery) != null ? _d : false,
|
|
2662
|
+
aliasGen: (_e = options.aliasGen) != null ? _e : createAliasGenerator(),
|
|
2663
|
+
dialect,
|
|
2664
|
+
params,
|
|
2665
|
+
depth: 0
|
|
2666
|
+
};
|
|
2667
|
+
const result = whereBuilderInstance.build(where, ctx);
|
|
2668
|
+
const publicResult = toPublicResult(result.clause, result.joins, params);
|
|
2669
|
+
if (!options.isSubquery) {
|
|
2670
|
+
const nums = [...publicResult.clause.matchAll(/\$(\d+)/g)].map(
|
|
2671
|
+
(m) => parseInt(m[1], 10)
|
|
2672
|
+
);
|
|
2673
|
+
if (nums.length > 0) {
|
|
2674
|
+
const min = Math.min(...nums);
|
|
2675
|
+
if (min === 1) {
|
|
2676
|
+
validateParamConsistency(publicResult.clause, publicResult.params);
|
|
2677
|
+
} else {
|
|
2678
|
+
validateParamConsistencyFragment(
|
|
2679
|
+
publicResult.clause,
|
|
2680
|
+
publicResult.params
|
|
2681
|
+
);
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2699
2684
|
}
|
|
2700
|
-
return
|
|
2685
|
+
return publicResult;
|
|
2701
2686
|
}
|
|
2702
2687
|
|
|
2703
2688
|
// src/builder/select/fields.ts
|