prisma-guard 1.24.0 → 1.26.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/README.md +126 -39
- package/dist/generator/index.js +46 -16
- package/dist/generator/index.js.map +1 -1
- package/dist/runtime/index.cjs +783 -403
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +60 -21
- package/dist/runtime/index.d.ts +60 -21
- package/dist/runtime/index.js +783 -403
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
package/dist/runtime/index.cjs
CHANGED
|
@@ -373,12 +373,24 @@ var JSON_ARRAY_OPERATORS = /* @__PURE__ */ new Set([
|
|
|
373
373
|
"array_starts_with",
|
|
374
374
|
"array_ends_with"
|
|
375
375
|
]);
|
|
376
|
-
function getSupportedOperators(
|
|
377
|
-
|
|
376
|
+
function getSupportedOperators(input, isList = false, isEnum = false) {
|
|
377
|
+
let fieldType;
|
|
378
|
+
let list;
|
|
379
|
+
let enumField;
|
|
380
|
+
if (typeof input === "string") {
|
|
381
|
+
fieldType = input;
|
|
382
|
+
list = isList;
|
|
383
|
+
enumField = isEnum;
|
|
384
|
+
} else {
|
|
385
|
+
fieldType = input.type;
|
|
386
|
+
list = input.isList;
|
|
387
|
+
enumField = input.isEnum === true;
|
|
388
|
+
}
|
|
389
|
+
if (list)
|
|
378
390
|
return [...SCALAR_LIST_OPERATORS];
|
|
379
|
-
if (
|
|
391
|
+
if (enumField)
|
|
380
392
|
return [...ENUM_OPERATORS];
|
|
381
|
-
const ops = SCALAR_OPERATORS[
|
|
393
|
+
const ops = SCALAR_OPERATORS[fieldType];
|
|
382
394
|
if (!ops)
|
|
383
395
|
return [];
|
|
384
396
|
return [...ops];
|
|
@@ -439,15 +451,14 @@ function createJsonOperatorSchema(fieldMeta, operator) {
|
|
|
439
451
|
if (JSON_ARRAY_OPERATORS.has(operator)) {
|
|
440
452
|
return jsonValue;
|
|
441
453
|
}
|
|
442
|
-
throw new ShapeError(
|
|
443
|
-
`Operator "${operator}" not supported for Json fields`
|
|
444
|
-
);
|
|
454
|
+
throw new ShapeError(`Operator "${operator}" not supported for Json fields`);
|
|
445
455
|
}
|
|
446
456
|
function buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase) {
|
|
447
457
|
const allOps = getSupportedOperators(fieldMeta);
|
|
448
|
-
const nestedOps = allOps.filter((
|
|
449
|
-
if (nestedOps.length === 0)
|
|
458
|
+
const nestedOps = allOps.filter((op) => op !== "not");
|
|
459
|
+
if (nestedOps.length === 0) {
|
|
450
460
|
return scalarSchema;
|
|
461
|
+
}
|
|
451
462
|
const nestedSchemas = {};
|
|
452
463
|
for (const op of nestedOps) {
|
|
453
464
|
nestedSchemas[op] = createOperatorSchema(
|
|
@@ -459,14 +470,35 @@ function buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase) {
|
|
|
459
470
|
}
|
|
460
471
|
const nestedKeys = Object.keys(nestedSchemas);
|
|
461
472
|
const nestedObj = import_zod2.z.object(nestedSchemas).strict().refine(
|
|
462
|
-
(
|
|
463
|
-
(
|
|
473
|
+
(value) => nestedKeys.some(
|
|
474
|
+
(key) => value[key] !== void 0
|
|
464
475
|
),
|
|
465
476
|
{ message: "not filter must specify at least one operator" }
|
|
466
477
|
);
|
|
467
478
|
return import_zod2.z.union([scalarSchema, nestedObj]);
|
|
468
479
|
}
|
|
469
480
|
function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
|
|
481
|
+
const allowedOps = getSupportedOperators(fieldMeta);
|
|
482
|
+
if (!allowedOps.includes(operator)) {
|
|
483
|
+
if (fieldMeta.isList) {
|
|
484
|
+
throw new ShapeError(
|
|
485
|
+
`Operator "${operator}" not supported for scalar list fields`
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
if (fieldMeta.isEnum) {
|
|
489
|
+
throw new ShapeError(
|
|
490
|
+
`Operator "${operator}" not supported for enum fields`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
if (fieldMeta.type === "Bytes" && allowedOps.length === 0) {
|
|
494
|
+
throw new ShapeError(
|
|
495
|
+
`Type "${fieldMeta.type}" does not support filter operators`
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
throw new ShapeError(
|
|
499
|
+
`Operator "${operator}" not supported for type "${fieldMeta.type}"`
|
|
500
|
+
);
|
|
501
|
+
}
|
|
470
502
|
if (fieldMeta.isList) {
|
|
471
503
|
return createScalarListOperatorSchema(
|
|
472
504
|
fieldMeta,
|
|
@@ -480,50 +512,35 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
|
|
|
480
512
|
if (!values || values.length === 0) {
|
|
481
513
|
throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
|
|
482
514
|
}
|
|
483
|
-
if (!ENUM_OPERATORS.has(operator)) {
|
|
484
|
-
throw new ShapeError(
|
|
485
|
-
`Operator "${operator}" not supported for enum fields`
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
515
|
const enumSchema = import_zod2.z.enum(values);
|
|
489
516
|
if (operator === "equals") {
|
|
490
517
|
return !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
|
|
491
518
|
}
|
|
492
519
|
if (operator === "not") {
|
|
493
520
|
const scalarSchema = !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
|
|
494
|
-
return buildNotFilterSchema(
|
|
521
|
+
return buildNotFilterSchema(
|
|
522
|
+
fieldMeta,
|
|
523
|
+
scalarSchema,
|
|
524
|
+
enumMap,
|
|
525
|
+
scalarBase
|
|
526
|
+
);
|
|
495
527
|
}
|
|
496
528
|
const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
|
|
497
529
|
return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemSchema));
|
|
498
530
|
}
|
|
499
531
|
if (fieldMeta.type === "Json") {
|
|
500
|
-
const supportedOps2 = SCALAR_OPERATORS["Json"];
|
|
501
|
-
if (!supportedOps2 || !supportedOps2.has(operator)) {
|
|
502
|
-
throw new ShapeError(
|
|
503
|
-
`Operator "${operator}" not supported for type "Json"`
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
532
|
if (operator === "not") {
|
|
507
533
|
const jsonValue = import_zod2.z.unknown();
|
|
508
534
|
const scalarSchema = !fieldMeta.isRequired ? import_zod2.z.union([jsonValue, import_zod2.z.null()]) : jsonValue;
|
|
509
|
-
return buildNotFilterSchema(
|
|
535
|
+
return buildNotFilterSchema(
|
|
536
|
+
fieldMeta,
|
|
537
|
+
scalarSchema,
|
|
538
|
+
enumMap,
|
|
539
|
+
scalarBase
|
|
540
|
+
);
|
|
510
541
|
}
|
|
511
542
|
return createJsonOperatorSchema(fieldMeta, operator);
|
|
512
543
|
}
|
|
513
|
-
const supportedOps = SCALAR_OPERATORS[fieldMeta.type];
|
|
514
|
-
if (!supportedOps) {
|
|
515
|
-
throw new ShapeError(`Unknown scalar type for operator: ${fieldMeta.type}`);
|
|
516
|
-
}
|
|
517
|
-
if (supportedOps.size === 0) {
|
|
518
|
-
throw new ShapeError(
|
|
519
|
-
`Type "${fieldMeta.type}" does not support filter operators`
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
|
-
if (!supportedOps.has(operator)) {
|
|
523
|
-
throw new ShapeError(
|
|
524
|
-
`Operator "${operator}" not supported for type "${fieldMeta.type}"`
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
544
|
const factory = scalarBase[fieldMeta.type];
|
|
528
545
|
if (!factory) {
|
|
529
546
|
throw new ShapeError(`Unknown scalar type: ${fieldMeta.type}`);
|
|
@@ -999,33 +1016,67 @@ function mergeWhereForced(where, forced) {
|
|
|
999
1016
|
}
|
|
1000
1017
|
return result;
|
|
1001
1018
|
}
|
|
1019
|
+
function uniqueValuesEqual(a, b) {
|
|
1020
|
+
if (a === b)
|
|
1021
|
+
return true;
|
|
1022
|
+
if (a === null || b === null)
|
|
1023
|
+
return false;
|
|
1024
|
+
if (typeof a !== typeof b)
|
|
1025
|
+
return false;
|
|
1026
|
+
if (a instanceof Date && b instanceof Date) {
|
|
1027
|
+
return a.getTime() === b.getTime();
|
|
1028
|
+
}
|
|
1029
|
+
if (Array.isArray(a)) {
|
|
1030
|
+
if (!Array.isArray(b))
|
|
1031
|
+
return false;
|
|
1032
|
+
if (a.length !== b.length)
|
|
1033
|
+
return false;
|
|
1034
|
+
return a.every((v, i) => uniqueValuesEqual(v, b[i]));
|
|
1035
|
+
}
|
|
1036
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1037
|
+
const aKeys = Object.keys(a);
|
|
1038
|
+
const bKeys = Object.keys(b);
|
|
1039
|
+
if (aKeys.length !== bKeys.length)
|
|
1040
|
+
return false;
|
|
1041
|
+
return aKeys.every((key) => key in b && uniqueValuesEqual(a[key], b[key]));
|
|
1042
|
+
}
|
|
1043
|
+
return false;
|
|
1044
|
+
}
|
|
1045
|
+
function mergeUniqueValue(target, key, value) {
|
|
1046
|
+
const cloned = deepClone(value);
|
|
1047
|
+
if (!(key in target)) {
|
|
1048
|
+
target[key] = cloned;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
const existing = target[key];
|
|
1052
|
+
if (isPlainObject(existing) && isPlainObject(cloned)) {
|
|
1053
|
+
const merged = { ...existing };
|
|
1054
|
+
for (const [nestedKey, nestedValue] of Object.entries(cloned)) {
|
|
1055
|
+
if (nestedKey in merged && !uniqueValuesEqual(merged[nestedKey], nestedValue)) {
|
|
1056
|
+
throw new ShapeError(
|
|
1057
|
+
`Conflicting unique where value for "${key}.${nestedKey}"`
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
merged[nestedKey] = nestedValue;
|
|
1061
|
+
}
|
|
1062
|
+
target[key] = merged;
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (!uniqueValuesEqual(existing, cloned)) {
|
|
1066
|
+
throw new ShapeError(`Conflicting unique where value for "${key}"`);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1002
1069
|
function mergeUniqueWhereForced(where, forced) {
|
|
1003
1070
|
if (!hasWhereForced(forced))
|
|
1004
1071
|
return where ?? {};
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
const relObj = result[relName];
|
|
1011
|
-
for (const [op, nestedForced] of Object.entries(opMap)) {
|
|
1012
|
-
relObj[op] = mergeWhereForced(
|
|
1013
|
-
relObj[op],
|
|
1014
|
-
nestedForced
|
|
1015
|
-
);
|
|
1016
|
-
}
|
|
1072
|
+
if (Object.keys(forced.relations).length > 0) {
|
|
1073
|
+
throw new ShapeError(
|
|
1074
|
+
"Unique where forced conditions cannot contain relation filters"
|
|
1075
|
+
);
|
|
1017
1076
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
if (existing) {
|
|
1022
|
-
if (Array.isArray(existing)) {
|
|
1023
|
-
conditions.unshift(...existing);
|
|
1024
|
-
} else {
|
|
1025
|
-
conditions.unshift(existing);
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
result.AND = conditions;
|
|
1077
|
+
const result = where ? deepClone(where) : {};
|
|
1078
|
+
for (const [key, value] of Object.entries(forced.conditions)) {
|
|
1079
|
+
mergeUniqueValue(result, key, value);
|
|
1029
1080
|
}
|
|
1030
1081
|
return result;
|
|
1031
1082
|
}
|
|
@@ -1041,6 +1092,17 @@ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
|
|
|
1041
1092
|
if (!hasWhereInSchema) {
|
|
1042
1093
|
const { where: _, ...rest } = bodyObj;
|
|
1043
1094
|
parseable = rest;
|
|
1095
|
+
} else if (isUniqueMethod && hasWhereForced(built.forcedWhere) && isPlainObject(bodyObj.where)) {
|
|
1096
|
+
const where = stripUniqueWhereForcedInput(
|
|
1097
|
+
bodyObj.where,
|
|
1098
|
+
built.forcedWhere
|
|
1099
|
+
);
|
|
1100
|
+
if (Object.keys(where).length === 0) {
|
|
1101
|
+
const { where: _, ...rest } = bodyObj;
|
|
1102
|
+
parseable = rest;
|
|
1103
|
+
} else {
|
|
1104
|
+
parseable = { ...bodyObj, where };
|
|
1105
|
+
}
|
|
1044
1106
|
} else if (built.forcedOnlyWhereKeys.size > 0 && isPlainObject(bodyObj.where)) {
|
|
1045
1107
|
const where = { ...bodyObj.where };
|
|
1046
1108
|
for (const key of built.forcedOnlyWhereKeys) {
|
|
@@ -1148,13 +1210,15 @@ function applyForcedTree(validated, key, tree) {
|
|
|
1148
1210
|
);
|
|
1149
1211
|
}
|
|
1150
1212
|
if (forced.include) {
|
|
1151
|
-
if (!relObj.include)
|
|
1213
|
+
if (!relObj.include) {
|
|
1152
1214
|
relObj.include = buildForcedOnlyContainer(forced.include);
|
|
1215
|
+
}
|
|
1153
1216
|
applyForcedTree(relObj, "include", forced.include);
|
|
1154
1217
|
}
|
|
1155
1218
|
if (forced.select) {
|
|
1156
|
-
if (!relObj.select)
|
|
1219
|
+
if (!relObj.select) {
|
|
1157
1220
|
relObj.select = buildForcedOnlyContainer(forced.select);
|
|
1221
|
+
}
|
|
1158
1222
|
applyForcedTree(relObj, "select", forced.select);
|
|
1159
1223
|
}
|
|
1160
1224
|
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
@@ -1179,10 +1243,12 @@ function buildForcedOnlyContainer(tree) {
|
|
|
1179
1243
|
if (forced.where && hasWhereForced(forced.where)) {
|
|
1180
1244
|
nested.where = mergeWhereForced(void 0, forced.where);
|
|
1181
1245
|
}
|
|
1182
|
-
if (forced.include)
|
|
1246
|
+
if (forced.include) {
|
|
1183
1247
|
nested.include = buildForcedOnlyContainer(forced.include);
|
|
1184
|
-
|
|
1248
|
+
}
|
|
1249
|
+
if (forced.select) {
|
|
1185
1250
|
nested.select = buildForcedOnlyContainer(forced.select);
|
|
1251
|
+
}
|
|
1186
1252
|
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1187
1253
|
const placement = forced._countWherePlacement ?? "include";
|
|
1188
1254
|
if (!nested[placement])
|
|
@@ -1218,77 +1284,131 @@ function applyForcedCountWhere(container, forcedCountWhere) {
|
|
|
1218
1284
|
}
|
|
1219
1285
|
}
|
|
1220
1286
|
}
|
|
1221
|
-
function
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
} else if (key !== "OR" && key !== "NOT") {
|
|
1233
|
-
keys.add(key);
|
|
1234
|
-
}
|
|
1287
|
+
function formatUniqueConstraint(constraint) {
|
|
1288
|
+
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
1289
|
+
}
|
|
1290
|
+
function formatUniqueConstraints(constraints) {
|
|
1291
|
+
return constraints.map(formatUniqueConstraint).join(" | ");
|
|
1292
|
+
}
|
|
1293
|
+
function resolvedWhereCoversConstraint(where, constraint) {
|
|
1294
|
+
if (constraint.fields.length === 1) {
|
|
1295
|
+
return constraint.fields[0] in where;
|
|
1235
1296
|
}
|
|
1236
|
-
|
|
1297
|
+
const value = where[constraint.selector];
|
|
1298
|
+
if (!isPlainObject(value))
|
|
1299
|
+
return false;
|
|
1300
|
+
return constraint.fields.every((field) => field in value);
|
|
1237
1301
|
}
|
|
1238
1302
|
function validateResolvedUniqueWhere(model, where, method, uniqueMap) {
|
|
1239
1303
|
const constraints = uniqueMap[model];
|
|
1240
1304
|
if (!constraints || constraints.length === 0)
|
|
1241
1305
|
return;
|
|
1242
|
-
const fieldKeys = collectWhereFieldKeys(where);
|
|
1243
1306
|
const covered = constraints.some(
|
|
1244
|
-
(constraint) =>
|
|
1307
|
+
(constraint) => resolvedWhereCoversConstraint(where, constraint)
|
|
1245
1308
|
);
|
|
1246
1309
|
if (!covered) {
|
|
1247
|
-
const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
|
|
1248
1310
|
throw new ShapeError(
|
|
1249
|
-
`${method} on model "${model}" requires resolved where to cover a unique constraint: ${
|
|
1311
|
+
`${method} on model "${model}" requires resolved where to cover a unique constraint: ${formatUniqueConstraints(constraints)}`
|
|
1250
1312
|
);
|
|
1251
1313
|
}
|
|
1252
1314
|
}
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if (isPlainObject(value)) {
|
|
1259
|
-
for (const f of collectEqualityFields(value, model, typeMap)) {
|
|
1260
|
-
fields.add(f);
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
continue;
|
|
1315
|
+
function assertDirectUniqueShapeValue(model, field, value, typeMap) {
|
|
1316
|
+
if (typeMap && model) {
|
|
1317
|
+
const fieldMeta = typeMap[model]?.[field];
|
|
1318
|
+
if (!fieldMeta) {
|
|
1319
|
+
throw new ShapeError(`Unknown unique where field "${model}.${field}"`);
|
|
1264
1320
|
}
|
|
1265
|
-
if (
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1321
|
+
if (fieldMeta.isRelation) {
|
|
1322
|
+
throw new ShapeError(
|
|
1323
|
+
`Relation field "${model}.${field}" cannot be used in unique where`
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
if (isForcedValue(value))
|
|
1328
|
+
return;
|
|
1329
|
+
if (isPlainObject(value)) {
|
|
1330
|
+
const keys = Object.keys(value);
|
|
1331
|
+
throw new ShapeError(
|
|
1332
|
+
`Invalid unique where shape for "${model ?? "unknown"}.${field}". Prisma WhereUniqueInput does not accept filter operator objects${keys.length ? `: ${keys.join(", ")}` : ""}. Use { ${field}: true } in guard shape and { ${field}: value } in request args.`
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
if (value === null || value === void 0) {
|
|
1336
|
+
throw new ShapeError(
|
|
1337
|
+
`Invalid unique where shape for "${model ?? "unknown"}.${field}". Unique fields must use true or a forced value.`
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
function shapeCoversConstraint(where, constraint, model, typeMap) {
|
|
1342
|
+
if (constraint.fields.length === 1) {
|
|
1343
|
+
const field = constraint.fields[0];
|
|
1344
|
+
if (!(field in where))
|
|
1345
|
+
return false;
|
|
1346
|
+
assertDirectUniqueShapeValue(model, field, where[field], typeMap);
|
|
1347
|
+
return true;
|
|
1348
|
+
}
|
|
1349
|
+
if (!(constraint.selector in where))
|
|
1350
|
+
return false;
|
|
1351
|
+
const selectorValue = where[constraint.selector];
|
|
1352
|
+
if (isForcedValue(selectorValue))
|
|
1353
|
+
return true;
|
|
1354
|
+
if (!isPlainObject(selectorValue)) {
|
|
1355
|
+
throw new ShapeError(
|
|
1356
|
+
`Compound unique selector "${model}.${constraint.selector}" must be an object with fields: ${constraint.fields.join(", ")}`
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
const allowed = new Set(constraint.fields);
|
|
1360
|
+
for (const key of Object.keys(selectorValue)) {
|
|
1361
|
+
if (!allowed.has(key)) {
|
|
1362
|
+
throw new ShapeError(
|
|
1363
|
+
`Unknown field "${key}" in compound unique selector "${model}.${constraint.selector}". Allowed fields: ${constraint.fields.join(", ")}`
|
|
1364
|
+
);
|
|
1273
1365
|
}
|
|
1274
1366
|
}
|
|
1275
|
-
|
|
1367
|
+
for (const field of constraint.fields) {
|
|
1368
|
+
if (!(field in selectorValue)) {
|
|
1369
|
+
throw new ShapeError(
|
|
1370
|
+
`Missing field "${field}" in compound unique selector "${model}.${constraint.selector}"`
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
assertDirectUniqueShapeValue(model, field, selectorValue[field], typeMap);
|
|
1374
|
+
}
|
|
1375
|
+
return true;
|
|
1276
1376
|
}
|
|
1277
1377
|
function validateUniqueEquality(model, where, method, uniqueMap, typeMap) {
|
|
1278
1378
|
const constraints = uniqueMap[model];
|
|
1279
1379
|
if (!constraints || constraints.length === 0)
|
|
1280
1380
|
return;
|
|
1281
|
-
const equalityFields = collectEqualityFields(where, model, typeMap);
|
|
1282
1381
|
const valid = constraints.some(
|
|
1283
|
-
(constraint) =>
|
|
1382
|
+
(constraint) => shapeCoversConstraint(where, constraint, model, typeMap)
|
|
1284
1383
|
);
|
|
1285
1384
|
if (!valid) {
|
|
1286
|
-
const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
|
|
1287
1385
|
throw new ShapeError(
|
|
1288
|
-
`${method} on model "${model}" requires where to cover a unique constraint
|
|
1386
|
+
`${method} on model "${model}" requires unique where shape to cover a unique constraint using Prisma unique selector syntax: ${formatUniqueConstraints(constraints)}`
|
|
1289
1387
|
);
|
|
1290
1388
|
}
|
|
1291
1389
|
}
|
|
1390
|
+
function stripUniqueWhereForcedInput(where, forced) {
|
|
1391
|
+
const result = deepClone(where);
|
|
1392
|
+
for (const [key, forcedValue] of Object.entries(forced.conditions)) {
|
|
1393
|
+
if (!(key in result))
|
|
1394
|
+
continue;
|
|
1395
|
+
const currentValue = result[key];
|
|
1396
|
+
if (isPlainObject(currentValue) && isPlainObject(forcedValue)) {
|
|
1397
|
+
const nested = { ...currentValue };
|
|
1398
|
+
for (const nestedKey of Object.keys(forcedValue)) {
|
|
1399
|
+
delete nested[nestedKey];
|
|
1400
|
+
}
|
|
1401
|
+
if (Object.keys(nested).length === 0) {
|
|
1402
|
+
delete result[key];
|
|
1403
|
+
} else {
|
|
1404
|
+
result[key] = nested;
|
|
1405
|
+
}
|
|
1406
|
+
continue;
|
|
1407
|
+
}
|
|
1408
|
+
delete result[key];
|
|
1409
|
+
}
|
|
1410
|
+
return result;
|
|
1411
|
+
}
|
|
1292
1412
|
|
|
1293
1413
|
// src/runtime/query-builder-where.ts
|
|
1294
1414
|
var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Bytes"]);
|
|
@@ -1405,7 +1525,7 @@ function isModeCompatibleOp(fieldType, op) {
|
|
|
1405
1525
|
return JSON_STRING_MODE_OPS.has(op);
|
|
1406
1526
|
return false;
|
|
1407
1527
|
}
|
|
1408
|
-
function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
1528
|
+
function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
1409
1529
|
function buildWhereSchema(model, whereConfig, depth) {
|
|
1410
1530
|
const currentDepth = depth ?? 0;
|
|
1411
1531
|
if (currentDepth > MAX_WHERE_DEPTH) {
|
|
@@ -1462,6 +1582,18 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1462
1582
|
scalarConditions
|
|
1463
1583
|
);
|
|
1464
1584
|
}
|
|
1585
|
+
for (const key of Object.keys(scalarConditions)) {
|
|
1586
|
+
if (COMBINATOR_KEYS.has(key))
|
|
1587
|
+
continue;
|
|
1588
|
+
if (!(key in fieldSchemas)) {
|
|
1589
|
+
fieldSchemas[key] = import_zod4.z.object({}).strict().optional();
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
for (const key of Object.keys(relationForced)) {
|
|
1593
|
+
if (!(key in fieldSchemas)) {
|
|
1594
|
+
fieldSchemas[key] = import_zod4.z.object({}).strict().optional();
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1465
1597
|
const schema = Object.keys(fieldSchemas).length > 0 ? import_zod4.z.object(fieldSchemas).strict().optional() : null;
|
|
1466
1598
|
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1467
1599
|
for (const key of Object.keys(whereConfig)) {
|
|
@@ -1685,7 +1817,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1685
1817
|
);
|
|
1686
1818
|
}
|
|
1687
1819
|
if (modeConfigValue === true) {
|
|
1688
|
-
opSchemas
|
|
1820
|
+
opSchemas.mode = import_zod4.z.enum(["default", "insensitive"]).optional();
|
|
1689
1821
|
} else {
|
|
1690
1822
|
const actualModeValue = isForcedValue(modeConfigValue) ? modeConfigValue.value : modeConfigValue;
|
|
1691
1823
|
const modeSchema = import_zod4.z.enum(["default", "insensitive"]);
|
|
@@ -1697,10 +1829,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1697
1829
|
`Invalid forced value for "${model}.${fieldName}.mode": ${err.message}`
|
|
1698
1830
|
);
|
|
1699
1831
|
}
|
|
1700
|
-
fieldForced
|
|
1832
|
+
fieldForced.mode = parsed;
|
|
1701
1833
|
}
|
|
1702
1834
|
} else if (hasModeCompatibleOp) {
|
|
1703
|
-
opSchemas
|
|
1835
|
+
opSchemas.mode = import_zod4.z.enum(["default", "insensitive"]).optional();
|
|
1704
1836
|
}
|
|
1705
1837
|
if (hasClientOps) {
|
|
1706
1838
|
const opObj = import_zod4.z.object(opSchemas).strict();
|
|
@@ -1728,12 +1860,60 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1728
1860
|
scalarConditions[fieldName] = fieldForced;
|
|
1729
1861
|
}
|
|
1730
1862
|
}
|
|
1863
|
+
function getUniqueConstraint(model, selector) {
|
|
1864
|
+
return (uniqueMap[model] ?? []).find(
|
|
1865
|
+
(constraint) => constraint.selector === selector
|
|
1866
|
+
) ?? null;
|
|
1867
|
+
}
|
|
1868
|
+
function buildDirectUniqueSchema(fieldMeta) {
|
|
1869
|
+
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
1870
|
+
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
1871
|
+
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
1872
|
+
}
|
|
1873
|
+
return base;
|
|
1874
|
+
}
|
|
1875
|
+
function parseForcedUniqueValue(model, fieldName, fieldMeta, value) {
|
|
1876
|
+
const schema = buildDirectUniqueSchema(fieldMeta);
|
|
1877
|
+
const actual = isForcedValue(value) ? value.value : value;
|
|
1878
|
+
try {
|
|
1879
|
+
return schema.parse(actual);
|
|
1880
|
+
} catch (err) {
|
|
1881
|
+
throw new ShapeError(
|
|
1882
|
+
`Invalid forced value for unique where "${model}.${fieldName}": ${err.message}`
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
function assertCompoundSelectorConfig(model, selector, constraint, value) {
|
|
1887
|
+
const actual = isForcedValue(value) ? value.value : value;
|
|
1888
|
+
if (!isPlainObject(actual)) {
|
|
1889
|
+
throw new ShapeError(
|
|
1890
|
+
`Compound unique selector "${model}.${selector}" must be an object with fields: ${constraint.fields.join(", ")}`
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1893
|
+
const allowed = new Set(constraint.fields);
|
|
1894
|
+
const keys = Object.keys(actual);
|
|
1895
|
+
for (const key of keys) {
|
|
1896
|
+
if (!allowed.has(key)) {
|
|
1897
|
+
throw new ShapeError(
|
|
1898
|
+
`Unknown field "${key}" in compound unique selector "${model}.${selector}". Allowed fields: ${constraint.fields.join(", ")}`
|
|
1899
|
+
);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
for (const field of constraint.fields) {
|
|
1903
|
+
if (!(field in actual)) {
|
|
1904
|
+
throw new ShapeError(
|
|
1905
|
+
`Missing field "${field}" in compound unique selector "${model}.${selector}"`
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
return actual;
|
|
1910
|
+
}
|
|
1731
1911
|
function buildUniqueWhereSchema(model, whereConfig) {
|
|
1732
1912
|
const modelFields = typeMap[model];
|
|
1733
1913
|
if (!modelFields)
|
|
1734
1914
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
1735
1915
|
const fieldSchemas = {};
|
|
1736
|
-
const
|
|
1916
|
+
const forcedConditions = {};
|
|
1737
1917
|
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1738
1918
|
for (const [key, value] of Object.entries(whereConfig)) {
|
|
1739
1919
|
if (COMBINATOR_KEYS.has(key)) {
|
|
@@ -1741,65 +1921,102 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1741
1921
|
`Combinator "${key}" is not supported in unique where for model "${model}"`
|
|
1742
1922
|
);
|
|
1743
1923
|
}
|
|
1924
|
+
const constraint = getUniqueConstraint(model, key);
|
|
1925
|
+
if (constraint && constraint.fields.length > 1) {
|
|
1926
|
+
const compoundConfig = assertCompoundSelectorConfig(
|
|
1927
|
+
model,
|
|
1928
|
+
key,
|
|
1929
|
+
constraint,
|
|
1930
|
+
value
|
|
1931
|
+
);
|
|
1932
|
+
const nestedSchemas = {};
|
|
1933
|
+
const forcedCompound = {};
|
|
1934
|
+
for (const fieldName of constraint.fields) {
|
|
1935
|
+
const fieldMeta2 = modelFields[fieldName];
|
|
1936
|
+
if (!fieldMeta2) {
|
|
1937
|
+
throw new ShapeError(
|
|
1938
|
+
`Unknown field "${fieldName}" in compound unique selector "${model}.${key}"`
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
if (fieldMeta2.isRelation) {
|
|
1942
|
+
throw new ShapeError(
|
|
1943
|
+
`Relation field "${fieldName}" cannot be used in compound unique selector "${model}.${key}"`
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
const fieldValue = compoundConfig[fieldName];
|
|
1947
|
+
const forced2 = isForcedValue(fieldValue);
|
|
1948
|
+
if (!forced2 && isPlainObject(fieldValue)) {
|
|
1949
|
+
const operators = Object.keys(fieldValue);
|
|
1950
|
+
throw new ShapeError(
|
|
1951
|
+
`Invalid compound unique where shape for "${model}.${key}.${fieldName}". Prisma compound unique selectors do not accept filter operator objects${operators.length ? `: ${operators.join(", ")}` : ""}. Use direct values only.`
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
const directSchema2 = buildDirectUniqueSchema(fieldMeta2);
|
|
1955
|
+
if (fieldValue === true) {
|
|
1956
|
+
nestedSchemas[fieldName] = directSchema2;
|
|
1957
|
+
} else {
|
|
1958
|
+
forcedCompound[fieldName] = parseForcedUniqueValue(
|
|
1959
|
+
model,
|
|
1960
|
+
fieldName,
|
|
1961
|
+
fieldMeta2,
|
|
1962
|
+
fieldValue
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
if (Object.keys(nestedSchemas).length > 0) {
|
|
1967
|
+
fieldSchemas[key] = import_zod4.z.object(nestedSchemas).strict();
|
|
1968
|
+
}
|
|
1969
|
+
if (Object.keys(forcedCompound).length > 0) {
|
|
1970
|
+
forcedConditions[key] = forcedCompound;
|
|
1971
|
+
}
|
|
1972
|
+
if (Object.keys(nestedSchemas).length === 0) {
|
|
1973
|
+
forcedOnlyKeys.add(key);
|
|
1974
|
+
}
|
|
1975
|
+
continue;
|
|
1976
|
+
}
|
|
1744
1977
|
const fieldMeta = modelFields[key];
|
|
1745
|
-
if (!fieldMeta)
|
|
1746
|
-
|
|
1747
|
-
if (fieldMeta.isRelation)
|
|
1978
|
+
if (!fieldMeta) {
|
|
1979
|
+
const selectors = (uniqueMap[model] ?? []).map((constraint2) => constraint2.selector).join(", ");
|
|
1748
1980
|
throw new ShapeError(
|
|
1749
|
-
`
|
|
1981
|
+
`Unknown unique field or selector "${key}" on model "${model}"${selectors ? `. Unique selectors: ${selectors}` : ""}`
|
|
1750
1982
|
);
|
|
1751
|
-
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
1752
|
-
let directSchema;
|
|
1753
|
-
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
1754
|
-
directSchema = wrapWithInputCoercion(
|
|
1755
|
-
fieldMeta.type,
|
|
1756
|
-
fieldMeta.isList,
|
|
1757
|
-
base
|
|
1758
|
-
);
|
|
1759
|
-
} else {
|
|
1760
|
-
directSchema = base;
|
|
1761
1983
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1984
|
+
if (fieldMeta.isRelation) {
|
|
1985
|
+
throw new ShapeError(
|
|
1986
|
+
`Relation field "${key}" cannot be used in unique where for model "${model}"`
|
|
1987
|
+
);
|
|
1766
1988
|
}
|
|
1767
|
-
|
|
1989
|
+
const forced = isForcedValue(value);
|
|
1990
|
+
if (!forced && isPlainObject(value)) {
|
|
1768
1991
|
const keys = Object.keys(value);
|
|
1769
|
-
if (keys.
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
} else {
|
|
1774
|
-
const actual2 = isForcedValue(equalsVal) ? equalsVal.value : equalsVal;
|
|
1775
|
-
try {
|
|
1776
|
-
forced[key] = directSchema.parse(actual2);
|
|
1777
|
-
} catch (err) {
|
|
1778
|
-
throw new ShapeError(
|
|
1779
|
-
`Invalid forced value for unique where "${model}.${key}": ${err.message}`
|
|
1780
|
-
);
|
|
1781
|
-
}
|
|
1782
|
-
forcedOnlyKeys.add(key);
|
|
1783
|
-
}
|
|
1784
|
-
continue;
|
|
1992
|
+
if (keys.includes("equals")) {
|
|
1993
|
+
throw new ShapeError(
|
|
1994
|
+
`Invalid unique where shape for "${model}.${key}". Prisma WhereUniqueInput does not accept filter operator objects. Use { ${key}: true } instead of { ${key}: { equals: true } }.`
|
|
1995
|
+
);
|
|
1785
1996
|
}
|
|
1786
1997
|
throw new ShapeError(
|
|
1787
|
-
`
|
|
1998
|
+
`Invalid unique where shape for "${model}.${key}". Prisma WhereUniqueInput does not accept operators: ${keys.join(", ")}. Use a direct unique value shape, for example { ${key}: true }.`
|
|
1788
1999
|
);
|
|
1789
2000
|
}
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
throw new ShapeError(
|
|
1795
|
-
`Invalid forced value for unique where "${model}.${key}": ${err.message}`
|
|
1796
|
-
);
|
|
2001
|
+
const directSchema = buildDirectUniqueSchema(fieldMeta);
|
|
2002
|
+
if (value === true) {
|
|
2003
|
+
fieldSchemas[key] = directSchema;
|
|
2004
|
+
continue;
|
|
1797
2005
|
}
|
|
2006
|
+
forcedConditions[key] = parseForcedUniqueValue(
|
|
2007
|
+
model,
|
|
2008
|
+
key,
|
|
2009
|
+
fieldMeta,
|
|
2010
|
+
value
|
|
2011
|
+
);
|
|
1798
2012
|
forcedOnlyKeys.add(key);
|
|
1799
2013
|
}
|
|
1800
2014
|
return {
|
|
1801
2015
|
schema: Object.keys(fieldSchemas).length > 0 ? import_zod4.z.object(fieldSchemas).strict() : null,
|
|
1802
|
-
forced
|
|
2016
|
+
forced: {
|
|
2017
|
+
conditions: forcedConditions,
|
|
2018
|
+
relations: {}
|
|
2019
|
+
},
|
|
1803
2020
|
forcedOnlyKeys
|
|
1804
2021
|
};
|
|
1805
2022
|
}
|
|
@@ -1818,6 +2035,15 @@ function requireConfigTrue(config, context) {
|
|
|
1818
2035
|
}
|
|
1819
2036
|
}
|
|
1820
2037
|
}
|
|
2038
|
+
function isPlainRecord(value) {
|
|
2039
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2040
|
+
}
|
|
2041
|
+
function formatUniqueConstraint2(constraint) {
|
|
2042
|
+
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
2043
|
+
}
|
|
2044
|
+
function formatUniqueConstraints2(constraints) {
|
|
2045
|
+
return constraints.map(formatUniqueConstraint2).join(" | ");
|
|
2046
|
+
}
|
|
1821
2047
|
function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
1822
2048
|
const sortEnum = import_zod5.z.enum(["asc", "desc"]);
|
|
1823
2049
|
const nullsEnum = import_zod5.z.enum(["first", "last"]);
|
|
@@ -1828,11 +2054,17 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1828
2054
|
if (!fieldMeta)
|
|
1829
2055
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
1830
2056
|
if (fieldMeta.isRelation)
|
|
1831
|
-
throw new ShapeError(
|
|
2057
|
+
throw new ShapeError(
|
|
2058
|
+
`Relation field "${fieldName}" in orderBy requires a nested config object, not true`
|
|
2059
|
+
);
|
|
1832
2060
|
if (fieldMeta.type === "Json")
|
|
1833
|
-
throw new ShapeError(
|
|
2061
|
+
throw new ShapeError(
|
|
2062
|
+
`Json field "${fieldName}" cannot be used in orderBy`
|
|
2063
|
+
);
|
|
1834
2064
|
if (fieldMeta.isList)
|
|
1835
|
-
throw new ShapeError(
|
|
2065
|
+
throw new ShapeError(
|
|
2066
|
+
`List field "${fieldName}" cannot be used in orderBy`
|
|
2067
|
+
);
|
|
1836
2068
|
}
|
|
1837
2069
|
function buildOrderBySchema(model, orderByConfig) {
|
|
1838
2070
|
const modelFields = typeMap[model];
|
|
@@ -1842,158 +2074,274 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1842
2074
|
for (const [fieldName, config] of Object.entries(orderByConfig)) {
|
|
1843
2075
|
const fieldMeta = modelFields[fieldName];
|
|
1844
2076
|
if (!fieldMeta)
|
|
1845
|
-
throw new ShapeError(
|
|
2077
|
+
throw new ShapeError(
|
|
2078
|
+
`Unknown field "${fieldName}" on model "${model}"`
|
|
2079
|
+
);
|
|
1846
2080
|
if (config === true) {
|
|
1847
2081
|
validateScalarOrderByField(fieldName, model, modelFields);
|
|
1848
2082
|
fieldSchemas[fieldName] = scalarOrderSchema.optional();
|
|
1849
2083
|
continue;
|
|
1850
2084
|
}
|
|
1851
|
-
if (
|
|
1852
|
-
throw new ShapeError(
|
|
2085
|
+
if (!isPlainRecord(config)) {
|
|
2086
|
+
throw new ShapeError(
|
|
2087
|
+
`orderBy config for "${fieldName}" on model "${model}" must be true or a relation aggregate object`
|
|
2088
|
+
);
|
|
1853
2089
|
}
|
|
1854
2090
|
if (!fieldMeta.isRelation) {
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
2091
|
+
const allowedOps = getSupportedOperators(
|
|
2092
|
+
fieldMeta.type,
|
|
2093
|
+
fieldMeta.isList
|
|
2094
|
+
);
|
|
2095
|
+
const opSchemas = {};
|
|
2096
|
+
for (const [op, enabled] of Object.entries(config)) {
|
|
2097
|
+
if (enabled !== true) {
|
|
2098
|
+
throw new ShapeError(
|
|
2099
|
+
`orderBy operator config for "${model}.${fieldName}.${op}" must be true`
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
if (!allowedOps.includes(op)) {
|
|
2103
|
+
throw new ShapeError(
|
|
2104
|
+
`Operator "${op}" not supported for orderBy field "${model}.${fieldName}"`
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
opSchemas[op] = scalarOrderSchema.optional();
|
|
2108
|
+
}
|
|
2109
|
+
const opKeys = Object.keys(opSchemas);
|
|
2110
|
+
fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
|
|
2111
|
+
(v) => opKeys.some(
|
|
2112
|
+
(k) => v[k] !== void 0
|
|
2113
|
+
),
|
|
2114
|
+
{
|
|
2115
|
+
message: `orderBy field "${fieldName}" must specify at least one operator`
|
|
2116
|
+
}
|
|
2117
|
+
).optional();
|
|
2118
|
+
continue;
|
|
1859
2119
|
}
|
|
1860
2120
|
if (fieldMeta.isList) {
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
2121
|
+
if (!("_count" in config)) {
|
|
2122
|
+
throw new ShapeError(
|
|
2123
|
+
`To-many relation orderBy "${fieldName}" only supports _count`
|
|
2124
|
+
);
|
|
1864
2125
|
}
|
|
1865
2126
|
if (config._count !== true) {
|
|
1866
|
-
throw new ShapeError(
|
|
2127
|
+
throw new ShapeError(
|
|
2128
|
+
`orderBy relation aggregate "${fieldName}._count" must be true`
|
|
2129
|
+
);
|
|
1867
2130
|
}
|
|
1868
|
-
fieldSchemas[fieldName] = import_zod5.z.object({
|
|
2131
|
+
fieldSchemas[fieldName] = import_zod5.z.object({
|
|
2132
|
+
_count: sortEnum.optional()
|
|
2133
|
+
}).strict().optional();
|
|
1869
2134
|
continue;
|
|
1870
2135
|
}
|
|
1871
|
-
const
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
for (const [nestedField, nestedVal] of Object.entries(config)) {
|
|
1877
|
-
if (nestedVal !== true) {
|
|
1878
|
-
throw new ShapeError(`Nested orderBy field "${nestedField}" on relation "${fieldName}" must be true`);
|
|
1879
|
-
}
|
|
1880
|
-
const nestedMeta = relatedFields[nestedField];
|
|
1881
|
-
if (!nestedMeta)
|
|
1882
|
-
throw new ShapeError(`Unknown field "${nestedField}" on model "${relatedModel}" in orderBy`);
|
|
1883
|
-
if (nestedMeta.isRelation)
|
|
1884
|
-
throw new ShapeError(`Nested relation "${nestedField}" in orderBy on "${fieldName}" is not supported`);
|
|
1885
|
-
if (nestedMeta.type === "Json")
|
|
1886
|
-
throw new ShapeError(`Json field "${nestedField}" cannot be used in orderBy`);
|
|
1887
|
-
if (nestedMeta.isList)
|
|
1888
|
-
throw new ShapeError(`List field "${nestedField}" cannot be used in orderBy`);
|
|
1889
|
-
nestedSchemas[nestedField] = scalarOrderSchema.optional();
|
|
1890
|
-
}
|
|
1891
|
-
const nestedKeys = Object.keys(nestedSchemas);
|
|
1892
|
-
fieldSchemas[fieldName] = import_zod5.z.object(nestedSchemas).strict().refine(
|
|
1893
|
-
(v) => nestedKeys.some((k) => v[k] !== void 0),
|
|
1894
|
-
{ message: `orderBy for relation "${fieldName}" must specify at least one field` }
|
|
1895
|
-
).optional();
|
|
2136
|
+
const nested = buildOrderBySchema(
|
|
2137
|
+
fieldMeta.type,
|
|
2138
|
+
config
|
|
2139
|
+
);
|
|
2140
|
+
fieldSchemas[fieldName] = nested;
|
|
1896
2141
|
}
|
|
1897
2142
|
const fieldKeys = Object.keys(fieldSchemas);
|
|
1898
2143
|
const singleSchema = import_zod5.z.object(fieldSchemas).strict().refine(
|
|
1899
|
-
(v) => fieldKeys.some(
|
|
2144
|
+
(v) => fieldKeys.some(
|
|
2145
|
+
(k) => v[k] !== void 0
|
|
2146
|
+
),
|
|
1900
2147
|
{ message: "orderBy must specify at least one field" }
|
|
1901
2148
|
);
|
|
1902
|
-
return import_zod5.z.union([
|
|
2149
|
+
return import_zod5.z.union([
|
|
2150
|
+
singleSchema,
|
|
2151
|
+
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))
|
|
2152
|
+
]).optional();
|
|
1903
2153
|
}
|
|
1904
2154
|
function buildTakeSchema(config) {
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2155
|
+
if (typeof config === "number") {
|
|
2156
|
+
if (!Number.isFinite(config) || !Number.isInteger(config)) {
|
|
2157
|
+
throw new ShapeError(`take must be a finite integer, got ${config}`);
|
|
2158
|
+
}
|
|
2159
|
+
if (config <= 0) {
|
|
2160
|
+
throw new ShapeError("take must be a positive integer");
|
|
2161
|
+
}
|
|
2162
|
+
return import_zod5.z.literal(config).optional();
|
|
2163
|
+
}
|
|
2164
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
2165
|
+
throw new ShapeError("take config must be a number or { max, default? }");
|
|
2166
|
+
}
|
|
2167
|
+
if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
|
|
2168
|
+
throw new ShapeError(
|
|
2169
|
+
`take.max must be a finite integer, got ${config.max}`
|
|
2170
|
+
);
|
|
1908
2171
|
}
|
|
1909
|
-
if (
|
|
1910
|
-
throw new ShapeError(
|
|
2172
|
+
if (config.max <= 0) {
|
|
2173
|
+
throw new ShapeError("take.max must be a positive integer");
|
|
1911
2174
|
}
|
|
1912
|
-
if (
|
|
1913
|
-
if (!Number.isFinite(
|
|
1914
|
-
throw new ShapeError(
|
|
2175
|
+
if (config.default !== void 0) {
|
|
2176
|
+
if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
|
|
2177
|
+
throw new ShapeError(
|
|
2178
|
+
`take.default must be a finite integer, got ${config.default}`
|
|
2179
|
+
);
|
|
1915
2180
|
}
|
|
1916
|
-
if (
|
|
1917
|
-
throw new ShapeError(
|
|
2181
|
+
if (config.default <= 0) {
|
|
2182
|
+
throw new ShapeError("take.default must be a positive integer");
|
|
1918
2183
|
}
|
|
1919
|
-
if (
|
|
1920
|
-
throw new ShapeError("take
|
|
2184
|
+
if (config.default > config.max) {
|
|
2185
|
+
throw new ShapeError("take.default cannot exceed take.max");
|
|
1921
2186
|
}
|
|
1922
|
-
return import_zod5.z.number().int().min(1).max(
|
|
2187
|
+
return import_zod5.z.number().int().min(1).max(config.max).default(config.default);
|
|
1923
2188
|
}
|
|
1924
|
-
return import_zod5.z.number().int().min(1).max(
|
|
2189
|
+
return import_zod5.z.number().int().min(1).max(config.max).optional();
|
|
1925
2190
|
}
|
|
1926
|
-
function
|
|
2191
|
+
function buildCursorFieldSchema(model, fieldName) {
|
|
1927
2192
|
const modelFields = typeMap[model];
|
|
1928
2193
|
if (!modelFields)
|
|
1929
2194
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
1930
|
-
|
|
1931
|
-
|
|
2195
|
+
const fieldMeta = modelFields[fieldName];
|
|
2196
|
+
if (!fieldMeta) {
|
|
2197
|
+
throw new ShapeError(
|
|
2198
|
+
`Unknown field "${fieldName}" on model "${model}" in cursor`
|
|
2199
|
+
);
|
|
2200
|
+
}
|
|
2201
|
+
if (fieldMeta.isRelation) {
|
|
2202
|
+
throw new ShapeError(
|
|
2203
|
+
`Relation field "${fieldName}" cannot be used in cursor`
|
|
2204
|
+
);
|
|
2205
|
+
}
|
|
2206
|
+
if (fieldMeta.isList) {
|
|
2207
|
+
throw new ShapeError(
|
|
2208
|
+
`List field "${fieldName}" cannot be used in cursor`
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
2211
|
+
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
2212
|
+
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
2213
|
+
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
2214
|
+
}
|
|
2215
|
+
return base;
|
|
2216
|
+
}
|
|
2217
|
+
function cursorConfigMatchesConstraint(cursorConfig, constraint) {
|
|
2218
|
+
if (!(constraint.selector in cursorConfig))
|
|
2219
|
+
return false;
|
|
2220
|
+
const value = cursorConfig[constraint.selector];
|
|
2221
|
+
if (constraint.fields.length === 1) {
|
|
2222
|
+
return value === true;
|
|
2223
|
+
}
|
|
2224
|
+
if (!isPlainRecord(value))
|
|
2225
|
+
return false;
|
|
2226
|
+
const keys = Object.keys(value);
|
|
2227
|
+
if (keys.length !== constraint.fields.length)
|
|
2228
|
+
return false;
|
|
2229
|
+
return constraint.fields.every((field) => value[field] === true);
|
|
2230
|
+
}
|
|
2231
|
+
function getUniqueConstraints(model) {
|
|
1932
2232
|
const constraints = uniqueMap[model];
|
|
1933
2233
|
if (constraints && constraints.length > 0) {
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2234
|
+
return constraints;
|
|
2235
|
+
}
|
|
2236
|
+
const modelFields = typeMap[model];
|
|
2237
|
+
if (!modelFields) {
|
|
2238
|
+
throw new ShapeError(`Unknown model: ${model}`);
|
|
2239
|
+
}
|
|
2240
|
+
const inferred = [];
|
|
2241
|
+
for (const [fieldName, fieldMeta] of Object.entries(modelFields)) {
|
|
2242
|
+
if (fieldMeta.isRelation)
|
|
2243
|
+
continue;
|
|
2244
|
+
if (fieldMeta.isId || fieldMeta.isUnique) {
|
|
2245
|
+
inferred.push({
|
|
2246
|
+
selector: fieldName,
|
|
2247
|
+
fields: [fieldName]
|
|
2248
|
+
});
|
|
1942
2249
|
}
|
|
1943
2250
|
}
|
|
2251
|
+
return inferred;
|
|
2252
|
+
}
|
|
2253
|
+
function buildCursorSchema(model, cursorConfig) {
|
|
2254
|
+
const constraints = getUniqueConstraints(model);
|
|
2255
|
+
if (constraints.length === 0) {
|
|
2256
|
+
throw new ShapeError(
|
|
2257
|
+
`cursor on model "${model}" requires at least one unique constraint`
|
|
2258
|
+
);
|
|
2259
|
+
}
|
|
2260
|
+
const matching = constraints.find(
|
|
2261
|
+
(constraint) => cursorConfigMatchesConstraint(cursorConfig, constraint)
|
|
2262
|
+
);
|
|
2263
|
+
if (!matching) {
|
|
2264
|
+
throw new ShapeError(
|
|
2265
|
+
`cursor on model "${model}" must exactly match a unique selector: ${formatUniqueConstraints2(constraints)}`
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
1944
2268
|
const fieldSchemas = {};
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
2269
|
+
if (matching.fields.length === 1) {
|
|
2270
|
+
fieldSchemas[matching.selector] = buildCursorFieldSchema(
|
|
2271
|
+
model,
|
|
2272
|
+
matching.fields[0]
|
|
2273
|
+
).optional();
|
|
2274
|
+
} else {
|
|
2275
|
+
const nestedSchemas = {};
|
|
2276
|
+
for (const field of matching.fields) {
|
|
2277
|
+
nestedSchemas[field] = buildCursorFieldSchema(model, field);
|
|
2278
|
+
}
|
|
2279
|
+
fieldSchemas[matching.selector] = import_zod5.z.object(nestedSchemas).strict().optional();
|
|
1954
2280
|
}
|
|
1955
|
-
return import_zod5.z.object(fieldSchemas).strict().
|
|
2281
|
+
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2282
|
+
(v) => v[matching.selector] !== void 0,
|
|
2283
|
+
{ message: `cursor must specify "${matching.selector}"` }
|
|
2284
|
+
).optional();
|
|
1956
2285
|
}
|
|
1957
2286
|
function buildDistinctSchema(model, distinctConfig) {
|
|
1958
|
-
if (distinctConfig.length === 0) {
|
|
1959
|
-
throw new ShapeError("distinct must contain at least one field");
|
|
1960
|
-
}
|
|
1961
2287
|
const modelFields = typeMap[model];
|
|
1962
2288
|
if (!modelFields)
|
|
1963
2289
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2290
|
+
if (!Array.isArray(distinctConfig) || distinctConfig.length === 0) {
|
|
2291
|
+
throw new ShapeError(
|
|
2292
|
+
`distinct on model "${model}" must be a non-empty array of scalar fields`
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
2295
|
+
const allowedFields = /* @__PURE__ */ new Set();
|
|
1964
2296
|
for (const fieldName of distinctConfig) {
|
|
1965
2297
|
const fieldMeta = modelFields[fieldName];
|
|
1966
2298
|
if (!fieldMeta)
|
|
1967
|
-
throw new ShapeError(
|
|
2299
|
+
throw new ShapeError(
|
|
2300
|
+
`Unknown field "${fieldName}" on model "${model}" in distinct`
|
|
2301
|
+
);
|
|
1968
2302
|
if (fieldMeta.isRelation)
|
|
1969
|
-
throw new ShapeError(
|
|
1970
|
-
|
|
1971
|
-
|
|
2303
|
+
throw new ShapeError(
|
|
2304
|
+
`Relation field "${fieldName}" cannot be used in distinct`
|
|
2305
|
+
);
|
|
2306
|
+
allowedFields.add(fieldName);
|
|
1972
2307
|
}
|
|
1973
|
-
|
|
1974
|
-
|
|
2308
|
+
return import_zod5.z.union([
|
|
2309
|
+
import_zod5.z.enum([...allowedFields]),
|
|
2310
|
+
import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1)
|
|
2311
|
+
]).optional();
|
|
1975
2312
|
}
|
|
1976
2313
|
function buildBySchema(model, byConfig) {
|
|
1977
|
-
if (byConfig.length === 0) {
|
|
1978
|
-
throw new ShapeError('groupBy "by" must contain at least one field');
|
|
1979
|
-
}
|
|
1980
2314
|
const modelFields = typeMap[model];
|
|
1981
2315
|
if (!modelFields)
|
|
1982
2316
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2317
|
+
if (!Array.isArray(byConfig) || byConfig.length === 0) {
|
|
2318
|
+
throw new ShapeError(
|
|
2319
|
+
`groupBy "by" on model "${model}" must be a non-empty array`
|
|
2320
|
+
);
|
|
2321
|
+
}
|
|
2322
|
+
const allowedFields = /* @__PURE__ */ new Set();
|
|
1983
2323
|
for (const fieldName of byConfig) {
|
|
1984
2324
|
const fieldMeta = modelFields[fieldName];
|
|
1985
2325
|
if (!fieldMeta)
|
|
1986
|
-
throw new ShapeError(
|
|
2326
|
+
throw new ShapeError(
|
|
2327
|
+
`Unknown field "${fieldName}" on model "${model}" in groupBy by`
|
|
2328
|
+
);
|
|
1987
2329
|
if (fieldMeta.isRelation)
|
|
1988
|
-
throw new ShapeError(
|
|
2330
|
+
throw new ShapeError(
|
|
2331
|
+
`Relation field "${fieldName}" cannot be used in groupBy by`
|
|
2332
|
+
);
|
|
2333
|
+
if (fieldMeta.isList)
|
|
2334
|
+
throw new ShapeError(
|
|
2335
|
+
`List field "${fieldName}" cannot be used in groupBy by`
|
|
2336
|
+
);
|
|
1989
2337
|
if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
|
|
1990
|
-
throw new ShapeError(
|
|
2338
|
+
throw new ShapeError(
|
|
2339
|
+
`${fieldMeta.type} field "${fieldName}" cannot be used in groupBy by`
|
|
2340
|
+
);
|
|
1991
2341
|
}
|
|
1992
|
-
|
|
1993
|
-
throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
|
|
2342
|
+
allowedFields.add(fieldName);
|
|
1994
2343
|
}
|
|
1995
|
-
|
|
1996
|
-
return import_zod5.z.union([enumSchema, import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(enumSchema).min(1))]);
|
|
2344
|
+
return import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1);
|
|
1997
2345
|
}
|
|
1998
2346
|
function buildHavingSchema(model, havingConfig) {
|
|
1999
2347
|
const modelFields = typeMap[model];
|
|
@@ -2004,82 +2352,88 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2004
2352
|
for (const fieldName of Object.keys(havingConfig)) {
|
|
2005
2353
|
const fieldMeta = modelFields[fieldName];
|
|
2006
2354
|
if (!fieldMeta)
|
|
2007
|
-
throw new ShapeError(
|
|
2355
|
+
throw new ShapeError(
|
|
2356
|
+
`Unknown field "${fieldName}" on model "${model}" in having`
|
|
2357
|
+
);
|
|
2008
2358
|
if (fieldMeta.isRelation)
|
|
2009
|
-
throw new ShapeError(
|
|
2359
|
+
throw new ShapeError(
|
|
2360
|
+
`Relation field "${fieldName}" cannot be used in having`
|
|
2361
|
+
);
|
|
2010
2362
|
if (fieldMeta.isList)
|
|
2011
|
-
throw new ShapeError(
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2363
|
+
throw new ShapeError(
|
|
2364
|
+
`List field "${fieldName}" cannot be used in having`
|
|
2365
|
+
);
|
|
2366
|
+
if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
|
|
2367
|
+
throw new ShapeError(
|
|
2368
|
+
`${fieldMeta.type} field "${fieldName}" cannot be used in having`
|
|
2369
|
+
);
|
|
2015
2370
|
}
|
|
2371
|
+
const allowedOps = getSupportedOperators(
|
|
2372
|
+
fieldMeta.type,
|
|
2373
|
+
fieldMeta.isList
|
|
2374
|
+
);
|
|
2016
2375
|
const opSchemas = {};
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2376
|
+
for (const op of allowedOps) {
|
|
2377
|
+
opSchemas[op] = createOperatorSchema(
|
|
2378
|
+
fieldMeta,
|
|
2379
|
+
op,
|
|
2380
|
+
enumMap,
|
|
2381
|
+
scalarBase
|
|
2382
|
+
).optional();
|
|
2021
2383
|
}
|
|
2022
|
-
if (fieldMeta.type === "String"
|
|
2023
|
-
opSchemas
|
|
2384
|
+
if (fieldMeta.type === "String") {
|
|
2385
|
+
opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
|
|
2024
2386
|
}
|
|
2387
|
+
const opKeys = Object.keys(opSchemas).filter((key) => key !== "mode");
|
|
2025
2388
|
fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
|
|
2026
2389
|
(v) => opKeys.some((k) => v[k] !== void 0),
|
|
2027
|
-
{
|
|
2390
|
+
{
|
|
2391
|
+
message: `having field "${fieldName}" must specify at least one operator`
|
|
2392
|
+
}
|
|
2028
2393
|
).optional();
|
|
2029
2394
|
}
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(havingSchema).min(1))
|
|
2038
|
-
]).optional();
|
|
2039
|
-
const allKeys = [...havingFieldKeys, "AND", "OR", "NOT"];
|
|
2040
|
-
return import_zod5.z.object(allSchemas).strict().refine(
|
|
2041
|
-
(v) => allKeys.some((k) => v[k] !== void 0),
|
|
2042
|
-
{ message: "having must specify at least one field or combinator" }
|
|
2043
|
-
);
|
|
2044
|
-
});
|
|
2045
|
-
return havingSchema.optional();
|
|
2395
|
+
const fieldKeys = Object.keys(fieldSchemas);
|
|
2396
|
+
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2397
|
+
(v) => fieldKeys.some(
|
|
2398
|
+
(k) => v[k] !== void 0
|
|
2399
|
+
),
|
|
2400
|
+
{ message: "having must specify at least one field" }
|
|
2401
|
+
).optional();
|
|
2046
2402
|
}
|
|
2047
|
-
function buildAggregateFieldSchema(model,
|
|
2403
|
+
function buildAggregateFieldSchema(model, op, config) {
|
|
2048
2404
|
const modelFields = typeMap[model];
|
|
2049
2405
|
if (!modelFields)
|
|
2050
2406
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2051
|
-
requireConfigTrue(
|
|
2052
|
-
const
|
|
2053
|
-
const isComparableOnly = opName === "_min" || opName === "_max";
|
|
2407
|
+
requireConfigTrue(config, `${op} on model "${model}"`);
|
|
2408
|
+
const allowedTypes = op === "_avg" || op === "_sum" ? NUMERIC_TYPES : COMPARABLE_TYPES;
|
|
2054
2409
|
const fieldSchemas = {};
|
|
2055
|
-
for (const fieldName of Object.keys(
|
|
2056
|
-
if (fieldName === "_all" && opName === "_count") {
|
|
2057
|
-
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2058
|
-
continue;
|
|
2059
|
-
}
|
|
2410
|
+
for (const fieldName of Object.keys(config)) {
|
|
2060
2411
|
const fieldMeta = modelFields[fieldName];
|
|
2061
2412
|
if (!fieldMeta)
|
|
2062
|
-
throw new ShapeError(
|
|
2413
|
+
throw new ShapeError(
|
|
2414
|
+
`Unknown field "${fieldName}" on model "${model}" in ${op}`
|
|
2415
|
+
);
|
|
2063
2416
|
if (fieldMeta.isRelation)
|
|
2064
|
-
throw new ShapeError(
|
|
2417
|
+
throw new ShapeError(
|
|
2418
|
+
`Relation field "${fieldName}" cannot be used in ${op}`
|
|
2419
|
+
);
|
|
2065
2420
|
if (fieldMeta.isList)
|
|
2066
|
-
throw new ShapeError(`List field "${fieldName}" cannot be used in ${opName}`);
|
|
2067
|
-
if (isNumericOnly && !NUMERIC_TYPES.has(fieldMeta.type)) {
|
|
2068
2421
|
throw new ShapeError(
|
|
2069
|
-
`
|
|
2422
|
+
`List field "${fieldName}" cannot be used in ${op}`
|
|
2070
2423
|
);
|
|
2071
|
-
|
|
2072
|
-
if (isComparableOnly && !COMPARABLE_TYPES.has(fieldMeta.type)) {
|
|
2424
|
+
if (!allowedTypes.has(fieldMeta.type)) {
|
|
2073
2425
|
throw new ShapeError(
|
|
2074
|
-
`Field "${fieldName}"
|
|
2426
|
+
`Field "${fieldName}" of type "${fieldMeta.type}" cannot be used in ${op}`
|
|
2075
2427
|
);
|
|
2076
2428
|
}
|
|
2077
2429
|
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2078
2430
|
}
|
|
2079
|
-
const
|
|
2431
|
+
const aggregateFieldKeys = Object.keys(fieldSchemas);
|
|
2080
2432
|
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2081
|
-
(v) =>
|
|
2082
|
-
|
|
2433
|
+
(v) => aggregateFieldKeys.some(
|
|
2434
|
+
(k) => v[k] !== void 0
|
|
2435
|
+
),
|
|
2436
|
+
{ message: `${op} must specify at least one field` }
|
|
2083
2437
|
).optional();
|
|
2084
2438
|
}
|
|
2085
2439
|
function buildCountFieldSchema(model, config, context) {
|
|
@@ -2095,15 +2449,21 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2095
2449
|
if (fieldName !== "_all") {
|
|
2096
2450
|
const fieldMeta = modelFields[fieldName];
|
|
2097
2451
|
if (!fieldMeta)
|
|
2098
|
-
throw new ShapeError(
|
|
2452
|
+
throw new ShapeError(
|
|
2453
|
+
`Unknown field "${fieldName}" on model "${model}" in ${context}`
|
|
2454
|
+
);
|
|
2099
2455
|
if (fieldMeta.isRelation)
|
|
2100
|
-
throw new ShapeError(
|
|
2456
|
+
throw new ShapeError(
|
|
2457
|
+
`Relation field "${fieldName}" cannot be used in ${context}`
|
|
2458
|
+
);
|
|
2101
2459
|
}
|
|
2102
2460
|
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2103
2461
|
}
|
|
2104
2462
|
const countFieldKeys = Object.keys(fieldSchemas);
|
|
2105
2463
|
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2106
|
-
(v) => countFieldKeys.some(
|
|
2464
|
+
(v) => countFieldKeys.some(
|
|
2465
|
+
(k) => v[k] !== void 0
|
|
2466
|
+
),
|
|
2107
2467
|
{ message: `${context} must specify at least one field` }
|
|
2108
2468
|
).optional();
|
|
2109
2469
|
}
|
|
@@ -2115,19 +2475,25 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2115
2475
|
const fieldSchemas = {};
|
|
2116
2476
|
for (const fieldName of Object.keys(selectConfig)) {
|
|
2117
2477
|
if (fieldName === "_all") {
|
|
2118
|
-
fieldSchemas
|
|
2478
|
+
fieldSchemas._all = import_zod5.z.literal(true).optional();
|
|
2119
2479
|
continue;
|
|
2120
2480
|
}
|
|
2121
2481
|
const fieldMeta = modelFields[fieldName];
|
|
2122
2482
|
if (!fieldMeta)
|
|
2123
|
-
throw new ShapeError(
|
|
2483
|
+
throw new ShapeError(
|
|
2484
|
+
`Unknown field "${fieldName}" on model "${model}" in count select`
|
|
2485
|
+
);
|
|
2124
2486
|
if (fieldMeta.isRelation)
|
|
2125
|
-
throw new ShapeError(
|
|
2487
|
+
throw new ShapeError(
|
|
2488
|
+
`Relation field "${fieldName}" cannot be used in count select`
|
|
2489
|
+
);
|
|
2126
2490
|
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2127
2491
|
}
|
|
2128
2492
|
const countSelectKeys = Object.keys(fieldSchemas);
|
|
2129
2493
|
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2130
|
-
(v) => countSelectKeys.some(
|
|
2494
|
+
(v) => countSelectKeys.some(
|
|
2495
|
+
(k) => v[k] !== void 0
|
|
2496
|
+
),
|
|
2131
2497
|
{ message: "count select must specify at least one field" }
|
|
2132
2498
|
).optional();
|
|
2133
2499
|
}
|
|
@@ -2536,7 +2902,12 @@ var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
|
|
|
2536
2902
|
"findUniqueOrThrow"
|
|
2537
2903
|
]);
|
|
2538
2904
|
function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
2539
|
-
const whereBuilder = createWhereBuilder(
|
|
2905
|
+
const whereBuilder = createWhereBuilder(
|
|
2906
|
+
typeMap,
|
|
2907
|
+
enumMap,
|
|
2908
|
+
scalarBase,
|
|
2909
|
+
uniqueMap
|
|
2910
|
+
);
|
|
2540
2911
|
const argsBuilder = createArgsBuilder(
|
|
2541
2912
|
typeMap,
|
|
2542
2913
|
enumMap,
|
|
@@ -2558,24 +2929,28 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2558
2929
|
function validateShapeArgs(method, shape) {
|
|
2559
2930
|
const allowed = METHOD_ALLOWED_ARGS[method];
|
|
2560
2931
|
for (const key of Object.keys(shape)) {
|
|
2561
|
-
if (!SHAPE_CONFIG_KEYS.has(key))
|
|
2932
|
+
if (!SHAPE_CONFIG_KEYS.has(key)) {
|
|
2562
2933
|
throw new ShapeError(`Unknown shape config key "${key}"`);
|
|
2563
|
-
|
|
2934
|
+
}
|
|
2935
|
+
if (!allowed.has(key)) {
|
|
2564
2936
|
throw new ShapeError(`Arg "${key}" not allowed for method "${method}"`);
|
|
2937
|
+
}
|
|
2565
2938
|
}
|
|
2566
2939
|
if (UNIQUE_WHERE_METHODS.has(method) && !shape.where) {
|
|
2567
2940
|
throw new ShapeError(`${method} shape must define "where"`);
|
|
2568
2941
|
}
|
|
2569
|
-
if (method === "groupBy" && !shape.by)
|
|
2942
|
+
if (method === "groupBy" && !shape.by) {
|
|
2570
2943
|
throw new ShapeError('groupBy shape must define "by"');
|
|
2944
|
+
}
|
|
2571
2945
|
if (method === "groupBy" && (shape.include || shape.select)) {
|
|
2572
2946
|
throw new ShapeError('groupBy does not support "include" or "select"');
|
|
2573
2947
|
}
|
|
2574
2948
|
if (method === "aggregate" && (shape.include || shape.select)) {
|
|
2575
2949
|
throw new ShapeError('aggregate does not support "include" or "select"');
|
|
2576
2950
|
}
|
|
2577
|
-
if (method === "count" && shape.include)
|
|
2951
|
+
if (method === "count" && shape.include) {
|
|
2578
2952
|
throw new ShapeError('count does not support "include"');
|
|
2953
|
+
}
|
|
2579
2954
|
if (method === "groupBy" && shape.orderBy && shape.orderBy !== true) {
|
|
2580
2955
|
const bySet = new Set(shape.by);
|
|
2581
2956
|
for (const fieldName of Object.keys(shape.orderBy)) {
|
|
@@ -2630,30 +3005,28 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2630
3005
|
let forcedIncludeCountWhere = {};
|
|
2631
3006
|
let forcedSelectCountWhere = {};
|
|
2632
3007
|
if (shape.where) {
|
|
2633
|
-
const
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
forcedWhere = forced;
|
|
2640
|
-
forcedOnlyWhereKeys = forcedOnlyKeys;
|
|
3008
|
+
const builtWhere = UNIQUE_WHERE_METHODS.has(method) ? whereBuilder.buildUniqueWhereSchema(model, shape.where) : whereBuilder.buildWhereSchema(model, shape.where);
|
|
3009
|
+
if (builtWhere.schema) {
|
|
3010
|
+
schemaFields.where = builtWhere.schema;
|
|
3011
|
+
}
|
|
3012
|
+
forcedWhere = builtWhere.forced;
|
|
3013
|
+
forcedOnlyWhereKeys = builtWhere.forcedOnlyKeys;
|
|
2641
3014
|
}
|
|
2642
3015
|
if (shape.include) {
|
|
2643
3016
|
const result = projectionBuilder.buildIncludeSchema(model, shape.include);
|
|
2644
|
-
schemaFields
|
|
3017
|
+
schemaFields.include = result.schema;
|
|
2645
3018
|
forcedIncludeTree = result.forcedTree;
|
|
2646
3019
|
forcedIncludeCountWhere = result.forcedCountWhere;
|
|
2647
3020
|
}
|
|
2648
3021
|
if (shape.select) {
|
|
2649
3022
|
if (method === "count") {
|
|
2650
|
-
schemaFields
|
|
3023
|
+
schemaFields.select = argsBuilder.buildCountSelectSchema(
|
|
2651
3024
|
model,
|
|
2652
3025
|
shape.select
|
|
2653
3026
|
);
|
|
2654
3027
|
} else {
|
|
2655
3028
|
const result = projectionBuilder.buildSelectSchema(model, shape.select);
|
|
2656
|
-
schemaFields
|
|
3029
|
+
schemaFields.select = result.schema;
|
|
2657
3030
|
forcedSelectTree = result.forcedTree;
|
|
2658
3031
|
forcedSelectCountWhere = result.forcedCountWhere;
|
|
2659
3032
|
}
|
|
@@ -2667,7 +3040,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2667
3040
|
for (const field of shape.by) {
|
|
2668
3041
|
groupByOrderFields[field] = sortEnum.optional();
|
|
2669
3042
|
}
|
|
2670
|
-
groupByOrderFields
|
|
3043
|
+
groupByOrderFields._count = sortEnum.optional();
|
|
2671
3044
|
const fieldKeys = Object.keys(groupByOrderFields);
|
|
2672
3045
|
const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
|
|
2673
3046
|
(v) => fieldKeys.some(
|
|
@@ -2675,13 +3048,16 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2675
3048
|
),
|
|
2676
3049
|
{ message: "orderBy must specify at least one field" }
|
|
2677
3050
|
);
|
|
2678
|
-
schemaFields
|
|
3051
|
+
schemaFields.orderBy = import_zod7.z.union([
|
|
3052
|
+
singleSchema,
|
|
3053
|
+
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3054
|
+
]).optional();
|
|
2679
3055
|
} else {
|
|
2680
3056
|
const groupByOrderFields = {};
|
|
2681
3057
|
for (const [fieldName, config] of Object.entries(shape.orderBy)) {
|
|
2682
3058
|
if (fieldName === "_count") {
|
|
2683
3059
|
if (config === true) {
|
|
2684
|
-
groupByOrderFields
|
|
3060
|
+
groupByOrderFields._count = sortEnum.optional();
|
|
2685
3061
|
} else if (typeof config === "object" && config !== null) {
|
|
2686
3062
|
const countFields = {};
|
|
2687
3063
|
for (const countField of Object.keys(config)) {
|
|
@@ -2693,7 +3069,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2693
3069
|
countFields[countField] = sortEnum.optional();
|
|
2694
3070
|
}
|
|
2695
3071
|
const countKeys = Object.keys(countFields);
|
|
2696
|
-
groupByOrderFields
|
|
3072
|
+
groupByOrderFields._count = import_zod7.z.object(countFields).strict().refine(
|
|
2697
3073
|
(v) => countKeys.some(
|
|
2698
3074
|
(k) => v[k] !== void 0
|
|
2699
3075
|
),
|
|
@@ -2718,70 +3094,83 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2718
3094
|
),
|
|
2719
3095
|
{ message: "orderBy must specify at least one field" }
|
|
2720
3096
|
);
|
|
2721
|
-
schemaFields
|
|
3097
|
+
schemaFields.orderBy = import_zod7.z.union([
|
|
3098
|
+
singleSchema,
|
|
3099
|
+
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3100
|
+
]).optional();
|
|
2722
3101
|
}
|
|
2723
3102
|
} else {
|
|
2724
|
-
schemaFields
|
|
3103
|
+
schemaFields.orderBy = argsBuilder.buildOrderBySchema(
|
|
2725
3104
|
model,
|
|
2726
3105
|
shape.orderBy
|
|
2727
3106
|
);
|
|
2728
3107
|
}
|
|
2729
3108
|
}
|
|
2730
|
-
if (shape.cursor)
|
|
2731
|
-
schemaFields
|
|
3109
|
+
if (shape.cursor) {
|
|
3110
|
+
schemaFields.cursor = argsBuilder.buildCursorSchema(
|
|
2732
3111
|
model,
|
|
2733
3112
|
shape.cursor
|
|
2734
3113
|
);
|
|
2735
|
-
|
|
2736
|
-
|
|
3114
|
+
}
|
|
3115
|
+
if (shape.take) {
|
|
3116
|
+
schemaFields.take = argsBuilder.buildTakeSchema(shape.take);
|
|
3117
|
+
}
|
|
2737
3118
|
if (shape.skip !== void 0) {
|
|
2738
3119
|
if (shape.skip !== true) {
|
|
2739
3120
|
throw new ShapeError('Shape config "skip" must be true');
|
|
2740
3121
|
}
|
|
2741
|
-
schemaFields
|
|
3122
|
+
schemaFields.skip = import_zod7.z.number().int().min(0).optional();
|
|
2742
3123
|
}
|
|
2743
|
-
if (shape.distinct)
|
|
2744
|
-
schemaFields
|
|
3124
|
+
if (shape.distinct) {
|
|
3125
|
+
schemaFields.distinct = argsBuilder.buildDistinctSchema(
|
|
2745
3126
|
model,
|
|
2746
3127
|
shape.distinct
|
|
2747
3128
|
);
|
|
2748
|
-
|
|
2749
|
-
|
|
3129
|
+
}
|
|
3130
|
+
if (shape._count) {
|
|
3131
|
+
schemaFields._count = argsBuilder.buildCountFieldSchema(
|
|
2750
3132
|
model,
|
|
2751
3133
|
shape._count,
|
|
2752
3134
|
"_count"
|
|
2753
3135
|
);
|
|
2754
|
-
|
|
2755
|
-
|
|
3136
|
+
}
|
|
3137
|
+
if (shape._avg) {
|
|
3138
|
+
schemaFields._avg = argsBuilder.buildAggregateFieldSchema(
|
|
2756
3139
|
model,
|
|
2757
3140
|
"_avg",
|
|
2758
3141
|
shape._avg
|
|
2759
3142
|
);
|
|
2760
|
-
|
|
2761
|
-
|
|
3143
|
+
}
|
|
3144
|
+
if (shape._sum) {
|
|
3145
|
+
schemaFields._sum = argsBuilder.buildAggregateFieldSchema(
|
|
2762
3146
|
model,
|
|
2763
3147
|
"_sum",
|
|
2764
3148
|
shape._sum
|
|
2765
3149
|
);
|
|
2766
|
-
|
|
2767
|
-
|
|
3150
|
+
}
|
|
3151
|
+
if (shape._min) {
|
|
3152
|
+
schemaFields._min = argsBuilder.buildAggregateFieldSchema(
|
|
2768
3153
|
model,
|
|
2769
3154
|
"_min",
|
|
2770
3155
|
shape._min
|
|
2771
3156
|
);
|
|
2772
|
-
|
|
2773
|
-
|
|
3157
|
+
}
|
|
3158
|
+
if (shape._max) {
|
|
3159
|
+
schemaFields._max = argsBuilder.buildAggregateFieldSchema(
|
|
2774
3160
|
model,
|
|
2775
3161
|
"_max",
|
|
2776
3162
|
shape._max
|
|
2777
3163
|
);
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
3164
|
+
}
|
|
3165
|
+
if (shape.by) {
|
|
3166
|
+
schemaFields.by = argsBuilder.buildBySchema(model, shape.by);
|
|
3167
|
+
}
|
|
3168
|
+
if (shape.having) {
|
|
3169
|
+
schemaFields.having = argsBuilder.buildHavingSchema(
|
|
2782
3170
|
model,
|
|
2783
3171
|
shape.having
|
|
2784
3172
|
);
|
|
3173
|
+
}
|
|
2785
3174
|
return {
|
|
2786
3175
|
zodSchema: import_zod7.z.object(schemaFields).strict(),
|
|
2787
3176
|
forcedWhere,
|
|
@@ -2799,7 +3188,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2799
3188
|
return { key: matched, shape: shapes[matched] };
|
|
2800
3189
|
}
|
|
2801
3190
|
function resolveDefaultShape(config, model, method, normalizedBody, opts, builtCache, isUnique) {
|
|
2802
|
-
const shapeOrFn = config
|
|
3191
|
+
const shapeOrFn = config.default;
|
|
2803
3192
|
let built;
|
|
2804
3193
|
if (typeof shapeOrFn === "function") {
|
|
2805
3194
|
const resolved = resolveAndValidateShape(shapeOrFn, opts?.ctx);
|
|
@@ -2853,8 +3242,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2853
3242
|
built = builtCache.get("_default");
|
|
2854
3243
|
}
|
|
2855
3244
|
} else {
|
|
2856
|
-
if (!isPlainObject(normalizedBody))
|
|
3245
|
+
if (!isPlainObject(normalizedBody)) {
|
|
2857
3246
|
throw new ShapeError("Request body must be an object");
|
|
3247
|
+
}
|
|
2858
3248
|
if ("caller" in normalizedBody) {
|
|
2859
3249
|
throw new CallerError(
|
|
2860
3250
|
"Pass caller via opts.caller, not in the request body."
|
|
@@ -4184,8 +4574,9 @@ function buildDefaultSelectInput(config) {
|
|
|
4184
4574
|
const nested = {};
|
|
4185
4575
|
if (value.select)
|
|
4186
4576
|
nested.select = buildDefaultSelectInput(value.select);
|
|
4187
|
-
if (value.include)
|
|
4577
|
+
if (value.include) {
|
|
4188
4578
|
nested.include = buildDefaultIncludeInput(value.include);
|
|
4579
|
+
}
|
|
4189
4580
|
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
4190
4581
|
}
|
|
4191
4582
|
}
|
|
@@ -4204,8 +4595,9 @@ function buildDefaultIncludeInput(config) {
|
|
|
4204
4595
|
result[key] = true;
|
|
4205
4596
|
} else {
|
|
4206
4597
|
const nested = {};
|
|
4207
|
-
if (value.include)
|
|
4598
|
+
if (value.include) {
|
|
4208
4599
|
nested.include = buildDefaultIncludeInput(value.include);
|
|
4600
|
+
}
|
|
4209
4601
|
if (value.select)
|
|
4210
4602
|
nested.select = buildDefaultSelectInput(value.select);
|
|
4211
4603
|
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
@@ -4216,8 +4608,9 @@ function buildDefaultIncludeInput(config) {
|
|
|
4216
4608
|
function buildDefaultCountInput(config) {
|
|
4217
4609
|
if (config === true)
|
|
4218
4610
|
return true;
|
|
4219
|
-
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select))
|
|
4611
|
+
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select)) {
|
|
4220
4612
|
return true;
|
|
4613
|
+
}
|
|
4221
4614
|
const selectObj = config.select;
|
|
4222
4615
|
const result = {};
|
|
4223
4616
|
for (const key of Object.keys(selectObj)) {
|
|
@@ -4299,8 +4692,9 @@ function checkIncludeForClientArgs(config) {
|
|
|
4299
4692
|
continue;
|
|
4300
4693
|
if (value.orderBy || value.cursor || value.take || value.skip)
|
|
4301
4694
|
return true;
|
|
4302
|
-
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where))
|
|
4695
|
+
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where)) {
|
|
4303
4696
|
return true;
|
|
4697
|
+
}
|
|
4304
4698
|
if (value.include && checkIncludeForClientArgs(value.include))
|
|
4305
4699
|
return true;
|
|
4306
4700
|
if (value.select && checkSelectForClientArgs(value.select))
|
|
@@ -4327,8 +4721,9 @@ function checkSelectForClientArgs(config) {
|
|
|
4327
4721
|
continue;
|
|
4328
4722
|
if (value.orderBy || value.cursor || value.take || value.skip)
|
|
4329
4723
|
return true;
|
|
4330
|
-
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where))
|
|
4724
|
+
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where)) {
|
|
4331
4725
|
return true;
|
|
4726
|
+
}
|
|
4332
4727
|
if (value.select && checkSelectForClientArgs(value.select))
|
|
4333
4728
|
return true;
|
|
4334
4729
|
if (value.include && checkIncludeForClientArgs(value.include))
|
|
@@ -4389,36 +4784,7 @@ function createModelGuardExtension(config) {
|
|
|
4389
4784
|
validateUniqueEquality(modelName, shape.where, method, uniqueMap, typeMap);
|
|
4390
4785
|
}
|
|
4391
4786
|
function validateUniqueWhereShapeConfig(modelName, where, method) {
|
|
4392
|
-
|
|
4393
|
-
if (!constraints || constraints.length === 0)
|
|
4394
|
-
return;
|
|
4395
|
-
const equalityFields = /* @__PURE__ */ new Set();
|
|
4396
|
-
for (const [key, value] of Object.entries(where)) {
|
|
4397
|
-
if (key === "AND" || key === "OR" || key === "NOT")
|
|
4398
|
-
continue;
|
|
4399
|
-
if (value === true) {
|
|
4400
|
-
equalityFields.add(key);
|
|
4401
|
-
continue;
|
|
4402
|
-
}
|
|
4403
|
-
if (isPlainObject(value)) {
|
|
4404
|
-
if ("equals" in value) {
|
|
4405
|
-
equalityFields.add(key);
|
|
4406
|
-
}
|
|
4407
|
-
continue;
|
|
4408
|
-
}
|
|
4409
|
-
if (value !== null && value !== void 0) {
|
|
4410
|
-
equalityFields.add(key);
|
|
4411
|
-
}
|
|
4412
|
-
}
|
|
4413
|
-
const valid = constraints.some(
|
|
4414
|
-
(constraint) => constraint.every((field) => equalityFields.has(field))
|
|
4415
|
-
);
|
|
4416
|
-
if (!valid) {
|
|
4417
|
-
const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
|
|
4418
|
-
throw new ShapeError(
|
|
4419
|
-
`${method} on model "${modelName}" requires where to cover a unique constraint with equality operators only: ${constraintDesc}`
|
|
4420
|
-
);
|
|
4421
|
-
}
|
|
4787
|
+
validateUniqueEquality(modelName, where, method, uniqueMap, typeMap);
|
|
4422
4788
|
}
|
|
4423
4789
|
function createGuardedMethods(modelName, modelDelegate, input, explicitCaller) {
|
|
4424
4790
|
function callDelegate(method, args) {
|
|
@@ -4692,10 +5058,10 @@ function createModelGuardExtension(config) {
|
|
|
4692
5058
|
`Invalid "where" on model "${modelName}": unique where must be a plain object`
|
|
4693
5059
|
);
|
|
4694
5060
|
}
|
|
4695
|
-
const sanitized =
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
}
|
|
5061
|
+
const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(
|
|
5062
|
+
bodyWhere,
|
|
5063
|
+
built.forced
|
|
5064
|
+
) : { ...bodyWhere };
|
|
4699
5065
|
try {
|
|
4700
5066
|
result = built.schema.parse(sanitized);
|
|
4701
5067
|
} catch (err) {
|
|
@@ -4708,16 +5074,23 @@ function createModelGuardExtension(config) {
|
|
|
4708
5074
|
}
|
|
4709
5075
|
} else if (bodyWhere !== void 0 && bodyWhere !== null) {
|
|
4710
5076
|
if (isPlainObject(bodyWhere)) {
|
|
4711
|
-
const
|
|
4712
|
-
|
|
5077
|
+
const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(
|
|
5078
|
+
bodyWhere,
|
|
5079
|
+
built.forced
|
|
5080
|
+
) : { ...bodyWhere };
|
|
5081
|
+
if (Object.keys(sanitized).length > 0) {
|
|
4713
5082
|
throw new ShapeError(
|
|
4714
5083
|
`Unique where on model "${modelName}" contains only forced values. Client where input is not accepted.`
|
|
4715
5084
|
);
|
|
4716
5085
|
}
|
|
5086
|
+
} else {
|
|
5087
|
+
throw new ShapeError(
|
|
5088
|
+
`Invalid "where" on model "${modelName}": unique where must be a plain object`
|
|
5089
|
+
);
|
|
4717
5090
|
}
|
|
4718
5091
|
}
|
|
4719
|
-
|
|
4720
|
-
result
|
|
5092
|
+
if (hasWhereForced(built.forced)) {
|
|
5093
|
+
result = mergeUniqueWhereForced(result, built.forced);
|
|
4721
5094
|
}
|
|
4722
5095
|
return result;
|
|
4723
5096
|
}
|
|
@@ -4730,7 +5103,9 @@ function createModelGuardExtension(config) {
|
|
|
4730
5103
|
);
|
|
4731
5104
|
if (Object.keys(where).length === 0) {
|
|
4732
5105
|
const constraints = uniqueMap[modelName];
|
|
4733
|
-
const constraintDesc = constraints ? constraints.map(
|
|
5106
|
+
const constraintDesc = constraints ? constraints.map(
|
|
5107
|
+
(constraint) => constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`
|
|
5108
|
+
).join(" | ") : "unknown";
|
|
4734
5109
|
const expectedFields = shape.where ? Object.keys(shape.where).join(", ") : "none defined";
|
|
4735
5110
|
throw new ShapeError(
|
|
4736
5111
|
`${method} on model "${modelName}" requires a unique where condition. Unique constraints: ${constraintDesc}. Shape allows: ${expectedFields}`
|
|
@@ -4806,8 +5181,9 @@ function createModelGuardExtension(config) {
|
|
|
4806
5181
|
return (body) => {
|
|
4807
5182
|
const caller = resolveCaller();
|
|
4808
5183
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
4809
|
-
if (!resolved.shape.data)
|
|
5184
|
+
if (!resolved.shape.data) {
|
|
4810
5185
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5186
|
+
}
|
|
4811
5187
|
validateMutationShapeKeys(
|
|
4812
5188
|
resolved.shape,
|
|
4813
5189
|
allowedShapeKeys,
|
|
@@ -4838,10 +5214,12 @@ function createModelGuardExtension(config) {
|
|
|
4838
5214
|
);
|
|
4839
5215
|
args = { data };
|
|
4840
5216
|
} else {
|
|
4841
|
-
if (!Array.isArray(resolved.body.data))
|
|
5217
|
+
if (!Array.isArray(resolved.body.data)) {
|
|
4842
5218
|
throw new ShapeError(`${method} expects data to be an array`);
|
|
4843
|
-
|
|
5219
|
+
}
|
|
5220
|
+
if (resolved.body.data.length === 0) {
|
|
4844
5221
|
throw new ShapeError(`${method} received empty data array`);
|
|
5222
|
+
}
|
|
4845
5223
|
const data = resolved.body.data.map(
|
|
4846
5224
|
(item) => validateAndMergeData(item, dataSchema, method, modelName)
|
|
4847
5225
|
);
|
|
@@ -4875,8 +5253,9 @@ function createModelGuardExtension(config) {
|
|
|
4875
5253
|
return (body) => {
|
|
4876
5254
|
const caller = resolveCaller();
|
|
4877
5255
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
4878
|
-
if (!resolved.shape.data)
|
|
5256
|
+
if (!resolved.shape.data) {
|
|
4879
5257
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5258
|
+
}
|
|
4880
5259
|
validateMutationShapeKeys(
|
|
4881
5260
|
resolved.shape,
|
|
4882
5261
|
allowedShapeKeys,
|
|
@@ -4955,8 +5334,9 @@ function createModelGuardExtension(config) {
|
|
|
4955
5334
|
return (body) => {
|
|
4956
5335
|
const caller = resolveCaller();
|
|
4957
5336
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
4958
|
-
if (resolved.shape.data)
|
|
5337
|
+
if (resolved.shape.data) {
|
|
4959
5338
|
throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
|
|
5339
|
+
}
|
|
4960
5340
|
validateMutationShapeKeys(
|
|
4961
5341
|
resolved.shape,
|
|
4962
5342
|
allowedShapeKeys,
|