prisma-guard 1.23.0 → 1.25.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 +312 -257
- package/dist/generator/index.js.map +1 -1
- package/dist/runtime/index.cjs +766 -403
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +65 -25
- package/dist/runtime/index.d.ts +65 -25
- package/dist/runtime/index.js +766 -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
|
-
if (!value || !isPlainObject(value))
|
|
1270
|
-
continue;
|
|
1271
|
-
if ("equals" in value) {
|
|
1272
|
-
fields.add(key);
|
|
1321
|
+
if (fieldMeta.isRelation) {
|
|
1322
|
+
throw new ShapeError(
|
|
1323
|
+
`Relation field "${model}.${field}" cannot be used in unique where`
|
|
1324
|
+
);
|
|
1273
1325
|
}
|
|
1274
1326
|
}
|
|
1275
|
-
|
|
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
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
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) {
|
|
@@ -1685,7 +1805,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1685
1805
|
);
|
|
1686
1806
|
}
|
|
1687
1807
|
if (modeConfigValue === true) {
|
|
1688
|
-
opSchemas
|
|
1808
|
+
opSchemas.mode = import_zod4.z.enum(["default", "insensitive"]).optional();
|
|
1689
1809
|
} else {
|
|
1690
1810
|
const actualModeValue = isForcedValue(modeConfigValue) ? modeConfigValue.value : modeConfigValue;
|
|
1691
1811
|
const modeSchema = import_zod4.z.enum(["default", "insensitive"]);
|
|
@@ -1697,10 +1817,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1697
1817
|
`Invalid forced value for "${model}.${fieldName}.mode": ${err.message}`
|
|
1698
1818
|
);
|
|
1699
1819
|
}
|
|
1700
|
-
fieldForced
|
|
1820
|
+
fieldForced.mode = parsed;
|
|
1701
1821
|
}
|
|
1702
1822
|
} else if (hasModeCompatibleOp) {
|
|
1703
|
-
opSchemas
|
|
1823
|
+
opSchemas.mode = import_zod4.z.enum(["default", "insensitive"]).optional();
|
|
1704
1824
|
}
|
|
1705
1825
|
if (hasClientOps) {
|
|
1706
1826
|
const opObj = import_zod4.z.object(opSchemas).strict();
|
|
@@ -1728,12 +1848,60 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1728
1848
|
scalarConditions[fieldName] = fieldForced;
|
|
1729
1849
|
}
|
|
1730
1850
|
}
|
|
1851
|
+
function getUniqueConstraint(model, selector) {
|
|
1852
|
+
return (uniqueMap[model] ?? []).find(
|
|
1853
|
+
(constraint) => constraint.selector === selector
|
|
1854
|
+
) ?? null;
|
|
1855
|
+
}
|
|
1856
|
+
function buildDirectUniqueSchema(fieldMeta) {
|
|
1857
|
+
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
1858
|
+
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
1859
|
+
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
1860
|
+
}
|
|
1861
|
+
return base;
|
|
1862
|
+
}
|
|
1863
|
+
function parseForcedUniqueValue(model, fieldName, fieldMeta, value) {
|
|
1864
|
+
const schema = buildDirectUniqueSchema(fieldMeta);
|
|
1865
|
+
const actual = isForcedValue(value) ? value.value : value;
|
|
1866
|
+
try {
|
|
1867
|
+
return schema.parse(actual);
|
|
1868
|
+
} catch (err) {
|
|
1869
|
+
throw new ShapeError(
|
|
1870
|
+
`Invalid forced value for unique where "${model}.${fieldName}": ${err.message}`
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
function assertCompoundSelectorConfig(model, selector, constraint, value) {
|
|
1875
|
+
const actual = isForcedValue(value) ? value.value : value;
|
|
1876
|
+
if (!isPlainObject(actual)) {
|
|
1877
|
+
throw new ShapeError(
|
|
1878
|
+
`Compound unique selector "${model}.${selector}" must be an object with fields: ${constraint.fields.join(", ")}`
|
|
1879
|
+
);
|
|
1880
|
+
}
|
|
1881
|
+
const allowed = new Set(constraint.fields);
|
|
1882
|
+
const keys = Object.keys(actual);
|
|
1883
|
+
for (const key of keys) {
|
|
1884
|
+
if (!allowed.has(key)) {
|
|
1885
|
+
throw new ShapeError(
|
|
1886
|
+
`Unknown field "${key}" in compound unique selector "${model}.${selector}". Allowed fields: ${constraint.fields.join(", ")}`
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
for (const field of constraint.fields) {
|
|
1891
|
+
if (!(field in actual)) {
|
|
1892
|
+
throw new ShapeError(
|
|
1893
|
+
`Missing field "${field}" in compound unique selector "${model}.${selector}"`
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
return actual;
|
|
1898
|
+
}
|
|
1731
1899
|
function buildUniqueWhereSchema(model, whereConfig) {
|
|
1732
1900
|
const modelFields = typeMap[model];
|
|
1733
1901
|
if (!modelFields)
|
|
1734
1902
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
1735
1903
|
const fieldSchemas = {};
|
|
1736
|
-
const
|
|
1904
|
+
const forcedConditions = {};
|
|
1737
1905
|
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1738
1906
|
for (const [key, value] of Object.entries(whereConfig)) {
|
|
1739
1907
|
if (COMBINATOR_KEYS.has(key)) {
|
|
@@ -1741,65 +1909,97 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1741
1909
|
`Combinator "${key}" is not supported in unique where for model "${model}"`
|
|
1742
1910
|
);
|
|
1743
1911
|
}
|
|
1912
|
+
const constraint = getUniqueConstraint(model, key);
|
|
1913
|
+
if (constraint && constraint.fields.length > 1) {
|
|
1914
|
+
const compoundConfig = assertCompoundSelectorConfig(
|
|
1915
|
+
model,
|
|
1916
|
+
key,
|
|
1917
|
+
constraint,
|
|
1918
|
+
value
|
|
1919
|
+
);
|
|
1920
|
+
const nestedSchemas = {};
|
|
1921
|
+
const forcedCompound = {};
|
|
1922
|
+
for (const fieldName of constraint.fields) {
|
|
1923
|
+
const fieldMeta2 = modelFields[fieldName];
|
|
1924
|
+
if (!fieldMeta2) {
|
|
1925
|
+
throw new ShapeError(
|
|
1926
|
+
`Unknown field "${fieldName}" in compound unique selector "${model}.${key}"`
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1929
|
+
if (fieldMeta2.isRelation) {
|
|
1930
|
+
throw new ShapeError(
|
|
1931
|
+
`Relation field "${fieldName}" cannot be used in compound unique selector "${model}.${key}"`
|
|
1932
|
+
);
|
|
1933
|
+
}
|
|
1934
|
+
const fieldValue = compoundConfig[fieldName];
|
|
1935
|
+
const forced2 = isForcedValue(fieldValue);
|
|
1936
|
+
if (!forced2 && isPlainObject(fieldValue)) {
|
|
1937
|
+
const operators = Object.keys(fieldValue);
|
|
1938
|
+
throw new ShapeError(
|
|
1939
|
+
`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.`
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
const directSchema2 = buildDirectUniqueSchema(fieldMeta2);
|
|
1943
|
+
if (fieldValue === true) {
|
|
1944
|
+
nestedSchemas[fieldName] = directSchema2;
|
|
1945
|
+
} else {
|
|
1946
|
+
forcedCompound[fieldName] = parseForcedUniqueValue(
|
|
1947
|
+
model,
|
|
1948
|
+
fieldName,
|
|
1949
|
+
fieldMeta2,
|
|
1950
|
+
fieldValue
|
|
1951
|
+
);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
if (Object.keys(nestedSchemas).length > 0) {
|
|
1955
|
+
fieldSchemas[key] = import_zod4.z.object(nestedSchemas).strict();
|
|
1956
|
+
}
|
|
1957
|
+
if (Object.keys(forcedCompound).length > 0) {
|
|
1958
|
+
forcedConditions[key] = forcedCompound;
|
|
1959
|
+
}
|
|
1960
|
+
if (Object.keys(nestedSchemas).length === 0) {
|
|
1961
|
+
forcedOnlyKeys.add(key);
|
|
1962
|
+
}
|
|
1963
|
+
continue;
|
|
1964
|
+
}
|
|
1744
1965
|
const fieldMeta = modelFields[key];
|
|
1745
|
-
if (!fieldMeta)
|
|
1746
|
-
|
|
1747
|
-
if (fieldMeta.isRelation)
|
|
1966
|
+
if (!fieldMeta) {
|
|
1967
|
+
const selectors = (uniqueMap[model] ?? []).map((constraint2) => constraint2.selector).join(", ");
|
|
1748
1968
|
throw new ShapeError(
|
|
1749
|
-
`
|
|
1750
|
-
);
|
|
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
|
|
1969
|
+
`Unknown unique field or selector "${key}" on model "${model}"${selectors ? `. Unique selectors: ${selectors}` : ""}`
|
|
1758
1970
|
);
|
|
1759
|
-
} else {
|
|
1760
|
-
directSchema = base;
|
|
1761
1971
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1972
|
+
if (fieldMeta.isRelation) {
|
|
1973
|
+
throw new ShapeError(
|
|
1974
|
+
`Relation field "${key}" cannot be used in unique where for model "${model}"`
|
|
1975
|
+
);
|
|
1766
1976
|
}
|
|
1767
|
-
|
|
1977
|
+
const forced = isForcedValue(value);
|
|
1978
|
+
if (!forced && isPlainObject(value)) {
|
|
1768
1979
|
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;
|
|
1980
|
+
if (keys.includes("equals")) {
|
|
1981
|
+
throw new ShapeError(
|
|
1982
|
+
`Invalid unique where shape for "${model}.${key}". Prisma WhereUniqueInput does not accept filter operator objects. Use { ${key}: true } instead of { ${key}: { equals: true } }.`
|
|
1983
|
+
);
|
|
1785
1984
|
}
|
|
1786
1985
|
throw new ShapeError(
|
|
1787
|
-
`
|
|
1986
|
+
`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
1987
|
);
|
|
1789
1988
|
}
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
throw new ShapeError(
|
|
1795
|
-
`Invalid forced value for unique where "${model}.${key}": ${err.message}`
|
|
1796
|
-
);
|
|
1989
|
+
const directSchema = buildDirectUniqueSchema(fieldMeta);
|
|
1990
|
+
if (value === true) {
|
|
1991
|
+
fieldSchemas[key] = directSchema;
|
|
1992
|
+
continue;
|
|
1797
1993
|
}
|
|
1994
|
+
forcedConditions[key] = parseForcedUniqueValue(model, key, fieldMeta, value);
|
|
1798
1995
|
forcedOnlyKeys.add(key);
|
|
1799
1996
|
}
|
|
1800
1997
|
return {
|
|
1801
1998
|
schema: Object.keys(fieldSchemas).length > 0 ? import_zod4.z.object(fieldSchemas).strict() : null,
|
|
1802
|
-
forced
|
|
1999
|
+
forced: {
|
|
2000
|
+
conditions: forcedConditions,
|
|
2001
|
+
relations: {}
|
|
2002
|
+
},
|
|
1803
2003
|
forcedOnlyKeys
|
|
1804
2004
|
};
|
|
1805
2005
|
}
|
|
@@ -1818,6 +2018,15 @@ function requireConfigTrue(config, context) {
|
|
|
1818
2018
|
}
|
|
1819
2019
|
}
|
|
1820
2020
|
}
|
|
2021
|
+
function isPlainRecord(value) {
|
|
2022
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2023
|
+
}
|
|
2024
|
+
function formatUniqueConstraint2(constraint) {
|
|
2025
|
+
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
2026
|
+
}
|
|
2027
|
+
function formatUniqueConstraints2(constraints) {
|
|
2028
|
+
return constraints.map(formatUniqueConstraint2).join(" | ");
|
|
2029
|
+
}
|
|
1821
2030
|
function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
1822
2031
|
const sortEnum = import_zod5.z.enum(["asc", "desc"]);
|
|
1823
2032
|
const nullsEnum = import_zod5.z.enum(["first", "last"]);
|
|
@@ -1828,11 +2037,17 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1828
2037
|
if (!fieldMeta)
|
|
1829
2038
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
1830
2039
|
if (fieldMeta.isRelation)
|
|
1831
|
-
throw new ShapeError(
|
|
2040
|
+
throw new ShapeError(
|
|
2041
|
+
`Relation field "${fieldName}" in orderBy requires a nested config object, not true`
|
|
2042
|
+
);
|
|
1832
2043
|
if (fieldMeta.type === "Json")
|
|
1833
|
-
throw new ShapeError(
|
|
2044
|
+
throw new ShapeError(
|
|
2045
|
+
`Json field "${fieldName}" cannot be used in orderBy`
|
|
2046
|
+
);
|
|
1834
2047
|
if (fieldMeta.isList)
|
|
1835
|
-
throw new ShapeError(
|
|
2048
|
+
throw new ShapeError(
|
|
2049
|
+
`List field "${fieldName}" cannot be used in orderBy`
|
|
2050
|
+
);
|
|
1836
2051
|
}
|
|
1837
2052
|
function buildOrderBySchema(model, orderByConfig) {
|
|
1838
2053
|
const modelFields = typeMap[model];
|
|
@@ -1842,158 +2057,274 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1842
2057
|
for (const [fieldName, config] of Object.entries(orderByConfig)) {
|
|
1843
2058
|
const fieldMeta = modelFields[fieldName];
|
|
1844
2059
|
if (!fieldMeta)
|
|
1845
|
-
throw new ShapeError(
|
|
2060
|
+
throw new ShapeError(
|
|
2061
|
+
`Unknown field "${fieldName}" on model "${model}"`
|
|
2062
|
+
);
|
|
1846
2063
|
if (config === true) {
|
|
1847
2064
|
validateScalarOrderByField(fieldName, model, modelFields);
|
|
1848
2065
|
fieldSchemas[fieldName] = scalarOrderSchema.optional();
|
|
1849
2066
|
continue;
|
|
1850
2067
|
}
|
|
1851
|
-
if (
|
|
1852
|
-
throw new ShapeError(
|
|
2068
|
+
if (!isPlainRecord(config)) {
|
|
2069
|
+
throw new ShapeError(
|
|
2070
|
+
`orderBy config for "${fieldName}" on model "${model}" must be true or a relation aggregate object`
|
|
2071
|
+
);
|
|
1853
2072
|
}
|
|
1854
2073
|
if (!fieldMeta.isRelation) {
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
2074
|
+
const allowedOps = getSupportedOperators(
|
|
2075
|
+
fieldMeta.type,
|
|
2076
|
+
fieldMeta.isList
|
|
2077
|
+
);
|
|
2078
|
+
const opSchemas = {};
|
|
2079
|
+
for (const [op, enabled] of Object.entries(config)) {
|
|
2080
|
+
if (enabled !== true) {
|
|
2081
|
+
throw new ShapeError(
|
|
2082
|
+
`orderBy operator config for "${model}.${fieldName}.${op}" must be true`
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
if (!allowedOps.includes(op)) {
|
|
2086
|
+
throw new ShapeError(
|
|
2087
|
+
`Operator "${op}" not supported for orderBy field "${model}.${fieldName}"`
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
opSchemas[op] = scalarOrderSchema.optional();
|
|
2091
|
+
}
|
|
2092
|
+
const opKeys = Object.keys(opSchemas);
|
|
2093
|
+
fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
|
|
2094
|
+
(v) => opKeys.some(
|
|
2095
|
+
(k) => v[k] !== void 0
|
|
2096
|
+
),
|
|
2097
|
+
{
|
|
2098
|
+
message: `orderBy field "${fieldName}" must specify at least one operator`
|
|
2099
|
+
}
|
|
2100
|
+
).optional();
|
|
2101
|
+
continue;
|
|
1859
2102
|
}
|
|
1860
2103
|
if (fieldMeta.isList) {
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
2104
|
+
if (!("_count" in config)) {
|
|
2105
|
+
throw new ShapeError(
|
|
2106
|
+
`To-many relation orderBy "${fieldName}" only supports _count`
|
|
2107
|
+
);
|
|
1864
2108
|
}
|
|
1865
2109
|
if (config._count !== true) {
|
|
1866
|
-
throw new ShapeError(
|
|
2110
|
+
throw new ShapeError(
|
|
2111
|
+
`orderBy relation aggregate "${fieldName}._count" must be true`
|
|
2112
|
+
);
|
|
1867
2113
|
}
|
|
1868
|
-
fieldSchemas[fieldName] = import_zod5.z.object({
|
|
2114
|
+
fieldSchemas[fieldName] = import_zod5.z.object({
|
|
2115
|
+
_count: sortEnum.optional()
|
|
2116
|
+
}).strict().optional();
|
|
1869
2117
|
continue;
|
|
1870
2118
|
}
|
|
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();
|
|
2119
|
+
const nested = buildOrderBySchema(
|
|
2120
|
+
fieldMeta.type,
|
|
2121
|
+
config
|
|
2122
|
+
);
|
|
2123
|
+
fieldSchemas[fieldName] = nested;
|
|
1896
2124
|
}
|
|
1897
2125
|
const fieldKeys = Object.keys(fieldSchemas);
|
|
1898
2126
|
const singleSchema = import_zod5.z.object(fieldSchemas).strict().refine(
|
|
1899
|
-
(v) => fieldKeys.some(
|
|
2127
|
+
(v) => fieldKeys.some(
|
|
2128
|
+
(k) => v[k] !== void 0
|
|
2129
|
+
),
|
|
1900
2130
|
{ message: "orderBy must specify at least one field" }
|
|
1901
2131
|
);
|
|
1902
|
-
return import_zod5.z.union([
|
|
2132
|
+
return import_zod5.z.union([
|
|
2133
|
+
singleSchema,
|
|
2134
|
+
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))
|
|
2135
|
+
]).optional();
|
|
1903
2136
|
}
|
|
1904
2137
|
function buildTakeSchema(config) {
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2138
|
+
if (typeof config === "number") {
|
|
2139
|
+
if (!Number.isFinite(config) || !Number.isInteger(config)) {
|
|
2140
|
+
throw new ShapeError(`take must be a finite integer, got ${config}`);
|
|
2141
|
+
}
|
|
2142
|
+
if (config <= 0) {
|
|
2143
|
+
throw new ShapeError("take must be a positive integer");
|
|
2144
|
+
}
|
|
2145
|
+
return import_zod5.z.literal(config).optional();
|
|
2146
|
+
}
|
|
2147
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
2148
|
+
throw new ShapeError("take config must be a number or { max, default? }");
|
|
2149
|
+
}
|
|
2150
|
+
if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
|
|
2151
|
+
throw new ShapeError(
|
|
2152
|
+
`take.max must be a finite integer, got ${config.max}`
|
|
2153
|
+
);
|
|
1908
2154
|
}
|
|
1909
|
-
if (
|
|
1910
|
-
throw new ShapeError(
|
|
2155
|
+
if (config.max <= 0) {
|
|
2156
|
+
throw new ShapeError("take.max must be a positive integer");
|
|
1911
2157
|
}
|
|
1912
|
-
if (
|
|
1913
|
-
if (!Number.isFinite(
|
|
1914
|
-
throw new ShapeError(
|
|
2158
|
+
if (config.default !== void 0) {
|
|
2159
|
+
if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
|
|
2160
|
+
throw new ShapeError(
|
|
2161
|
+
`take.default must be a finite integer, got ${config.default}`
|
|
2162
|
+
);
|
|
1915
2163
|
}
|
|
1916
|
-
if (
|
|
1917
|
-
throw new ShapeError(
|
|
2164
|
+
if (config.default <= 0) {
|
|
2165
|
+
throw new ShapeError("take.default must be a positive integer");
|
|
1918
2166
|
}
|
|
1919
|
-
if (
|
|
1920
|
-
throw new ShapeError("take
|
|
2167
|
+
if (config.default > config.max) {
|
|
2168
|
+
throw new ShapeError("take.default cannot exceed take.max");
|
|
1921
2169
|
}
|
|
1922
|
-
return import_zod5.z.number().int().min(1).max(
|
|
2170
|
+
return import_zod5.z.number().int().min(1).max(config.max).default(config.default);
|
|
1923
2171
|
}
|
|
1924
|
-
return import_zod5.z.number().int().min(1).max(
|
|
2172
|
+
return import_zod5.z.number().int().min(1).max(config.max).optional();
|
|
1925
2173
|
}
|
|
1926
|
-
function
|
|
2174
|
+
function buildCursorFieldSchema(model, fieldName) {
|
|
1927
2175
|
const modelFields = typeMap[model];
|
|
1928
2176
|
if (!modelFields)
|
|
1929
2177
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
1930
|
-
|
|
1931
|
-
|
|
2178
|
+
const fieldMeta = modelFields[fieldName];
|
|
2179
|
+
if (!fieldMeta) {
|
|
2180
|
+
throw new ShapeError(
|
|
2181
|
+
`Unknown field "${fieldName}" on model "${model}" in cursor`
|
|
2182
|
+
);
|
|
2183
|
+
}
|
|
2184
|
+
if (fieldMeta.isRelation) {
|
|
2185
|
+
throw new ShapeError(
|
|
2186
|
+
`Relation field "${fieldName}" cannot be used in cursor`
|
|
2187
|
+
);
|
|
2188
|
+
}
|
|
2189
|
+
if (fieldMeta.isList) {
|
|
2190
|
+
throw new ShapeError(
|
|
2191
|
+
`List field "${fieldName}" cannot be used in cursor`
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
2195
|
+
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
2196
|
+
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
2197
|
+
}
|
|
2198
|
+
return base;
|
|
2199
|
+
}
|
|
2200
|
+
function cursorConfigMatchesConstraint(cursorConfig, constraint) {
|
|
2201
|
+
if (!(constraint.selector in cursorConfig))
|
|
2202
|
+
return false;
|
|
2203
|
+
const value = cursorConfig[constraint.selector];
|
|
2204
|
+
if (constraint.fields.length === 1) {
|
|
2205
|
+
return value === true;
|
|
2206
|
+
}
|
|
2207
|
+
if (!isPlainRecord(value))
|
|
2208
|
+
return false;
|
|
2209
|
+
const keys = Object.keys(value);
|
|
2210
|
+
if (keys.length !== constraint.fields.length)
|
|
2211
|
+
return false;
|
|
2212
|
+
return constraint.fields.every((field) => value[field] === true);
|
|
2213
|
+
}
|
|
2214
|
+
function getUniqueConstraints(model) {
|
|
1932
2215
|
const constraints = uniqueMap[model];
|
|
1933
2216
|
if (constraints && constraints.length > 0) {
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2217
|
+
return constraints;
|
|
2218
|
+
}
|
|
2219
|
+
const modelFields = typeMap[model];
|
|
2220
|
+
if (!modelFields) {
|
|
2221
|
+
throw new ShapeError(`Unknown model: ${model}`);
|
|
2222
|
+
}
|
|
2223
|
+
const inferred = [];
|
|
2224
|
+
for (const [fieldName, fieldMeta] of Object.entries(modelFields)) {
|
|
2225
|
+
if (fieldMeta.isRelation)
|
|
2226
|
+
continue;
|
|
2227
|
+
if (fieldMeta.isId || fieldMeta.isUnique) {
|
|
2228
|
+
inferred.push({
|
|
2229
|
+
selector: fieldName,
|
|
2230
|
+
fields: [fieldName]
|
|
2231
|
+
});
|
|
1942
2232
|
}
|
|
1943
2233
|
}
|
|
2234
|
+
return inferred;
|
|
2235
|
+
}
|
|
2236
|
+
function buildCursorSchema(model, cursorConfig) {
|
|
2237
|
+
const constraints = getUniqueConstraints(model);
|
|
2238
|
+
if (constraints.length === 0) {
|
|
2239
|
+
throw new ShapeError(
|
|
2240
|
+
`cursor on model "${model}" requires at least one unique constraint`
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
const matching = constraints.find(
|
|
2244
|
+
(constraint) => cursorConfigMatchesConstraint(cursorConfig, constraint)
|
|
2245
|
+
);
|
|
2246
|
+
if (!matching) {
|
|
2247
|
+
throw new ShapeError(
|
|
2248
|
+
`cursor on model "${model}" must exactly match a unique selector: ${formatUniqueConstraints2(constraints)}`
|
|
2249
|
+
);
|
|
2250
|
+
}
|
|
1944
2251
|
const fieldSchemas = {};
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
2252
|
+
if (matching.fields.length === 1) {
|
|
2253
|
+
fieldSchemas[matching.selector] = buildCursorFieldSchema(
|
|
2254
|
+
model,
|
|
2255
|
+
matching.fields[0]
|
|
2256
|
+
).optional();
|
|
2257
|
+
} else {
|
|
2258
|
+
const nestedSchemas = {};
|
|
2259
|
+
for (const field of matching.fields) {
|
|
2260
|
+
nestedSchemas[field] = buildCursorFieldSchema(model, field);
|
|
2261
|
+
}
|
|
2262
|
+
fieldSchemas[matching.selector] = import_zod5.z.object(nestedSchemas).strict().optional();
|
|
1954
2263
|
}
|
|
1955
|
-
return import_zod5.z.object(fieldSchemas).strict().
|
|
2264
|
+
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2265
|
+
(v) => v[matching.selector] !== void 0,
|
|
2266
|
+
{ message: `cursor must specify "${matching.selector}"` }
|
|
2267
|
+
).optional();
|
|
1956
2268
|
}
|
|
1957
2269
|
function buildDistinctSchema(model, distinctConfig) {
|
|
1958
|
-
if (distinctConfig.length === 0) {
|
|
1959
|
-
throw new ShapeError("distinct must contain at least one field");
|
|
1960
|
-
}
|
|
1961
2270
|
const modelFields = typeMap[model];
|
|
1962
2271
|
if (!modelFields)
|
|
1963
2272
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2273
|
+
if (!Array.isArray(distinctConfig) || distinctConfig.length === 0) {
|
|
2274
|
+
throw new ShapeError(
|
|
2275
|
+
`distinct on model "${model}" must be a non-empty array of scalar fields`
|
|
2276
|
+
);
|
|
2277
|
+
}
|
|
2278
|
+
const allowedFields = /* @__PURE__ */ new Set();
|
|
1964
2279
|
for (const fieldName of distinctConfig) {
|
|
1965
2280
|
const fieldMeta = modelFields[fieldName];
|
|
1966
2281
|
if (!fieldMeta)
|
|
1967
|
-
throw new ShapeError(
|
|
2282
|
+
throw new ShapeError(
|
|
2283
|
+
`Unknown field "${fieldName}" on model "${model}" in distinct`
|
|
2284
|
+
);
|
|
1968
2285
|
if (fieldMeta.isRelation)
|
|
1969
|
-
throw new ShapeError(
|
|
1970
|
-
|
|
1971
|
-
|
|
2286
|
+
throw new ShapeError(
|
|
2287
|
+
`Relation field "${fieldName}" cannot be used in distinct`
|
|
2288
|
+
);
|
|
2289
|
+
allowedFields.add(fieldName);
|
|
1972
2290
|
}
|
|
1973
|
-
|
|
1974
|
-
|
|
2291
|
+
return import_zod5.z.union([
|
|
2292
|
+
import_zod5.z.enum([...allowedFields]),
|
|
2293
|
+
import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1)
|
|
2294
|
+
]).optional();
|
|
1975
2295
|
}
|
|
1976
2296
|
function buildBySchema(model, byConfig) {
|
|
1977
|
-
if (byConfig.length === 0) {
|
|
1978
|
-
throw new ShapeError('groupBy "by" must contain at least one field');
|
|
1979
|
-
}
|
|
1980
2297
|
const modelFields = typeMap[model];
|
|
1981
2298
|
if (!modelFields)
|
|
1982
2299
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2300
|
+
if (!Array.isArray(byConfig) || byConfig.length === 0) {
|
|
2301
|
+
throw new ShapeError(
|
|
2302
|
+
`groupBy "by" on model "${model}" must be a non-empty array`
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
const allowedFields = /* @__PURE__ */ new Set();
|
|
1983
2306
|
for (const fieldName of byConfig) {
|
|
1984
2307
|
const fieldMeta = modelFields[fieldName];
|
|
1985
2308
|
if (!fieldMeta)
|
|
1986
|
-
throw new ShapeError(
|
|
2309
|
+
throw new ShapeError(
|
|
2310
|
+
`Unknown field "${fieldName}" on model "${model}" in groupBy by`
|
|
2311
|
+
);
|
|
1987
2312
|
if (fieldMeta.isRelation)
|
|
1988
|
-
throw new ShapeError(
|
|
2313
|
+
throw new ShapeError(
|
|
2314
|
+
`Relation field "${fieldName}" cannot be used in groupBy by`
|
|
2315
|
+
);
|
|
2316
|
+
if (fieldMeta.isList)
|
|
2317
|
+
throw new ShapeError(
|
|
2318
|
+
`List field "${fieldName}" cannot be used in groupBy by`
|
|
2319
|
+
);
|
|
1989
2320
|
if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
|
|
1990
|
-
throw new ShapeError(
|
|
2321
|
+
throw new ShapeError(
|
|
2322
|
+
`${fieldMeta.type} field "${fieldName}" cannot be used in groupBy by`
|
|
2323
|
+
);
|
|
1991
2324
|
}
|
|
1992
|
-
|
|
1993
|
-
throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
|
|
2325
|
+
allowedFields.add(fieldName);
|
|
1994
2326
|
}
|
|
1995
|
-
|
|
1996
|
-
return import_zod5.z.union([enumSchema, import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(enumSchema).min(1))]);
|
|
2327
|
+
return import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1);
|
|
1997
2328
|
}
|
|
1998
2329
|
function buildHavingSchema(model, havingConfig) {
|
|
1999
2330
|
const modelFields = typeMap[model];
|
|
@@ -2004,82 +2335,88 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2004
2335
|
for (const fieldName of Object.keys(havingConfig)) {
|
|
2005
2336
|
const fieldMeta = modelFields[fieldName];
|
|
2006
2337
|
if (!fieldMeta)
|
|
2007
|
-
throw new ShapeError(
|
|
2338
|
+
throw new ShapeError(
|
|
2339
|
+
`Unknown field "${fieldName}" on model "${model}" in having`
|
|
2340
|
+
);
|
|
2008
2341
|
if (fieldMeta.isRelation)
|
|
2009
|
-
throw new ShapeError(
|
|
2342
|
+
throw new ShapeError(
|
|
2343
|
+
`Relation field "${fieldName}" cannot be used in having`
|
|
2344
|
+
);
|
|
2010
2345
|
if (fieldMeta.isList)
|
|
2011
|
-
throw new ShapeError(
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2346
|
+
throw new ShapeError(
|
|
2347
|
+
`List field "${fieldName}" cannot be used in having`
|
|
2348
|
+
);
|
|
2349
|
+
if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
|
|
2350
|
+
throw new ShapeError(
|
|
2351
|
+
`${fieldMeta.type} field "${fieldName}" cannot be used in having`
|
|
2352
|
+
);
|
|
2015
2353
|
}
|
|
2354
|
+
const allowedOps = getSupportedOperators(
|
|
2355
|
+
fieldMeta.type,
|
|
2356
|
+
fieldMeta.isList
|
|
2357
|
+
);
|
|
2016
2358
|
const opSchemas = {};
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2359
|
+
for (const op of allowedOps) {
|
|
2360
|
+
opSchemas[op] = createOperatorSchema(
|
|
2361
|
+
fieldMeta,
|
|
2362
|
+
op,
|
|
2363
|
+
enumMap,
|
|
2364
|
+
scalarBase
|
|
2365
|
+
).optional();
|
|
2021
2366
|
}
|
|
2022
|
-
if (fieldMeta.type === "String"
|
|
2023
|
-
opSchemas
|
|
2367
|
+
if (fieldMeta.type === "String") {
|
|
2368
|
+
opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
|
|
2024
2369
|
}
|
|
2370
|
+
const opKeys = Object.keys(opSchemas).filter((key) => key !== "mode");
|
|
2025
2371
|
fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
|
|
2026
2372
|
(v) => opKeys.some((k) => v[k] !== void 0),
|
|
2027
|
-
{
|
|
2373
|
+
{
|
|
2374
|
+
message: `having field "${fieldName}" must specify at least one operator`
|
|
2375
|
+
}
|
|
2028
2376
|
).optional();
|
|
2029
2377
|
}
|
|
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();
|
|
2378
|
+
const fieldKeys = Object.keys(fieldSchemas);
|
|
2379
|
+
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2380
|
+
(v) => fieldKeys.some(
|
|
2381
|
+
(k) => v[k] !== void 0
|
|
2382
|
+
),
|
|
2383
|
+
{ message: "having must specify at least one field" }
|
|
2384
|
+
).optional();
|
|
2046
2385
|
}
|
|
2047
|
-
function buildAggregateFieldSchema(model,
|
|
2386
|
+
function buildAggregateFieldSchema(model, op, config) {
|
|
2048
2387
|
const modelFields = typeMap[model];
|
|
2049
2388
|
if (!modelFields)
|
|
2050
2389
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2051
|
-
requireConfigTrue(
|
|
2052
|
-
const
|
|
2053
|
-
const isComparableOnly = opName === "_min" || opName === "_max";
|
|
2390
|
+
requireConfigTrue(config, `${op} on model "${model}"`);
|
|
2391
|
+
const allowedTypes = op === "_avg" || op === "_sum" ? NUMERIC_TYPES : COMPARABLE_TYPES;
|
|
2054
2392
|
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
|
-
}
|
|
2393
|
+
for (const fieldName of Object.keys(config)) {
|
|
2060
2394
|
const fieldMeta = modelFields[fieldName];
|
|
2061
2395
|
if (!fieldMeta)
|
|
2062
|
-
throw new ShapeError(
|
|
2396
|
+
throw new ShapeError(
|
|
2397
|
+
`Unknown field "${fieldName}" on model "${model}" in ${op}`
|
|
2398
|
+
);
|
|
2063
2399
|
if (fieldMeta.isRelation)
|
|
2064
|
-
throw new ShapeError(
|
|
2400
|
+
throw new ShapeError(
|
|
2401
|
+
`Relation field "${fieldName}" cannot be used in ${op}`
|
|
2402
|
+
);
|
|
2065
2403
|
if (fieldMeta.isList)
|
|
2066
|
-
throw new ShapeError(`List field "${fieldName}" cannot be used in ${opName}`);
|
|
2067
|
-
if (isNumericOnly && !NUMERIC_TYPES.has(fieldMeta.type)) {
|
|
2068
2404
|
throw new ShapeError(
|
|
2069
|
-
`
|
|
2405
|
+
`List field "${fieldName}" cannot be used in ${op}`
|
|
2070
2406
|
);
|
|
2071
|
-
|
|
2072
|
-
if (isComparableOnly && !COMPARABLE_TYPES.has(fieldMeta.type)) {
|
|
2407
|
+
if (!allowedTypes.has(fieldMeta.type)) {
|
|
2073
2408
|
throw new ShapeError(
|
|
2074
|
-
`Field "${fieldName}"
|
|
2409
|
+
`Field "${fieldName}" of type "${fieldMeta.type}" cannot be used in ${op}`
|
|
2075
2410
|
);
|
|
2076
2411
|
}
|
|
2077
2412
|
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2078
2413
|
}
|
|
2079
|
-
const
|
|
2414
|
+
const aggregateFieldKeys = Object.keys(fieldSchemas);
|
|
2080
2415
|
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2081
|
-
(v) =>
|
|
2082
|
-
|
|
2416
|
+
(v) => aggregateFieldKeys.some(
|
|
2417
|
+
(k) => v[k] !== void 0
|
|
2418
|
+
),
|
|
2419
|
+
{ message: `${op} must specify at least one field` }
|
|
2083
2420
|
).optional();
|
|
2084
2421
|
}
|
|
2085
2422
|
function buildCountFieldSchema(model, config, context) {
|
|
@@ -2095,15 +2432,21 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2095
2432
|
if (fieldName !== "_all") {
|
|
2096
2433
|
const fieldMeta = modelFields[fieldName];
|
|
2097
2434
|
if (!fieldMeta)
|
|
2098
|
-
throw new ShapeError(
|
|
2435
|
+
throw new ShapeError(
|
|
2436
|
+
`Unknown field "${fieldName}" on model "${model}" in ${context}`
|
|
2437
|
+
);
|
|
2099
2438
|
if (fieldMeta.isRelation)
|
|
2100
|
-
throw new ShapeError(
|
|
2439
|
+
throw new ShapeError(
|
|
2440
|
+
`Relation field "${fieldName}" cannot be used in ${context}`
|
|
2441
|
+
);
|
|
2101
2442
|
}
|
|
2102
2443
|
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2103
2444
|
}
|
|
2104
2445
|
const countFieldKeys = Object.keys(fieldSchemas);
|
|
2105
2446
|
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2106
|
-
(v) => countFieldKeys.some(
|
|
2447
|
+
(v) => countFieldKeys.some(
|
|
2448
|
+
(k) => v[k] !== void 0
|
|
2449
|
+
),
|
|
2107
2450
|
{ message: `${context} must specify at least one field` }
|
|
2108
2451
|
).optional();
|
|
2109
2452
|
}
|
|
@@ -2115,19 +2458,25 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2115
2458
|
const fieldSchemas = {};
|
|
2116
2459
|
for (const fieldName of Object.keys(selectConfig)) {
|
|
2117
2460
|
if (fieldName === "_all") {
|
|
2118
|
-
fieldSchemas
|
|
2461
|
+
fieldSchemas._all = import_zod5.z.literal(true).optional();
|
|
2119
2462
|
continue;
|
|
2120
2463
|
}
|
|
2121
2464
|
const fieldMeta = modelFields[fieldName];
|
|
2122
2465
|
if (!fieldMeta)
|
|
2123
|
-
throw new ShapeError(
|
|
2466
|
+
throw new ShapeError(
|
|
2467
|
+
`Unknown field "${fieldName}" on model "${model}" in count select`
|
|
2468
|
+
);
|
|
2124
2469
|
if (fieldMeta.isRelation)
|
|
2125
|
-
throw new ShapeError(
|
|
2470
|
+
throw new ShapeError(
|
|
2471
|
+
`Relation field "${fieldName}" cannot be used in count select`
|
|
2472
|
+
);
|
|
2126
2473
|
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2127
2474
|
}
|
|
2128
2475
|
const countSelectKeys = Object.keys(fieldSchemas);
|
|
2129
2476
|
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2130
|
-
(v) => countSelectKeys.some(
|
|
2477
|
+
(v) => countSelectKeys.some(
|
|
2478
|
+
(k) => v[k] !== void 0
|
|
2479
|
+
),
|
|
2131
2480
|
{ message: "count select must specify at least one field" }
|
|
2132
2481
|
).optional();
|
|
2133
2482
|
}
|
|
@@ -2536,7 +2885,12 @@ var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
|
|
|
2536
2885
|
"findUniqueOrThrow"
|
|
2537
2886
|
]);
|
|
2538
2887
|
function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
2539
|
-
const whereBuilder = createWhereBuilder(
|
|
2888
|
+
const whereBuilder = createWhereBuilder(
|
|
2889
|
+
typeMap,
|
|
2890
|
+
enumMap,
|
|
2891
|
+
scalarBase,
|
|
2892
|
+
uniqueMap
|
|
2893
|
+
);
|
|
2540
2894
|
const argsBuilder = createArgsBuilder(
|
|
2541
2895
|
typeMap,
|
|
2542
2896
|
enumMap,
|
|
@@ -2558,24 +2912,28 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2558
2912
|
function validateShapeArgs(method, shape) {
|
|
2559
2913
|
const allowed = METHOD_ALLOWED_ARGS[method];
|
|
2560
2914
|
for (const key of Object.keys(shape)) {
|
|
2561
|
-
if (!SHAPE_CONFIG_KEYS.has(key))
|
|
2915
|
+
if (!SHAPE_CONFIG_KEYS.has(key)) {
|
|
2562
2916
|
throw new ShapeError(`Unknown shape config key "${key}"`);
|
|
2563
|
-
|
|
2917
|
+
}
|
|
2918
|
+
if (!allowed.has(key)) {
|
|
2564
2919
|
throw new ShapeError(`Arg "${key}" not allowed for method "${method}"`);
|
|
2920
|
+
}
|
|
2565
2921
|
}
|
|
2566
2922
|
if (UNIQUE_WHERE_METHODS.has(method) && !shape.where) {
|
|
2567
2923
|
throw new ShapeError(`${method} shape must define "where"`);
|
|
2568
2924
|
}
|
|
2569
|
-
if (method === "groupBy" && !shape.by)
|
|
2925
|
+
if (method === "groupBy" && !shape.by) {
|
|
2570
2926
|
throw new ShapeError('groupBy shape must define "by"');
|
|
2927
|
+
}
|
|
2571
2928
|
if (method === "groupBy" && (shape.include || shape.select)) {
|
|
2572
2929
|
throw new ShapeError('groupBy does not support "include" or "select"');
|
|
2573
2930
|
}
|
|
2574
2931
|
if (method === "aggregate" && (shape.include || shape.select)) {
|
|
2575
2932
|
throw new ShapeError('aggregate does not support "include" or "select"');
|
|
2576
2933
|
}
|
|
2577
|
-
if (method === "count" && shape.include)
|
|
2934
|
+
if (method === "count" && shape.include) {
|
|
2578
2935
|
throw new ShapeError('count does not support "include"');
|
|
2936
|
+
}
|
|
2579
2937
|
if (method === "groupBy" && shape.orderBy && shape.orderBy !== true) {
|
|
2580
2938
|
const bySet = new Set(shape.by);
|
|
2581
2939
|
for (const fieldName of Object.keys(shape.orderBy)) {
|
|
@@ -2630,30 +2988,28 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2630
2988
|
let forcedIncludeCountWhere = {};
|
|
2631
2989
|
let forcedSelectCountWhere = {};
|
|
2632
2990
|
if (shape.where) {
|
|
2633
|
-
const
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
forcedWhere = forced;
|
|
2640
|
-
forcedOnlyWhereKeys = forcedOnlyKeys;
|
|
2991
|
+
const builtWhere = UNIQUE_WHERE_METHODS.has(method) ? whereBuilder.buildUniqueWhereSchema(model, shape.where) : whereBuilder.buildWhereSchema(model, shape.where);
|
|
2992
|
+
if (builtWhere.schema) {
|
|
2993
|
+
schemaFields.where = builtWhere.schema;
|
|
2994
|
+
}
|
|
2995
|
+
forcedWhere = builtWhere.forced;
|
|
2996
|
+
forcedOnlyWhereKeys = builtWhere.forcedOnlyKeys;
|
|
2641
2997
|
}
|
|
2642
2998
|
if (shape.include) {
|
|
2643
2999
|
const result = projectionBuilder.buildIncludeSchema(model, shape.include);
|
|
2644
|
-
schemaFields
|
|
3000
|
+
schemaFields.include = result.schema;
|
|
2645
3001
|
forcedIncludeTree = result.forcedTree;
|
|
2646
3002
|
forcedIncludeCountWhere = result.forcedCountWhere;
|
|
2647
3003
|
}
|
|
2648
3004
|
if (shape.select) {
|
|
2649
3005
|
if (method === "count") {
|
|
2650
|
-
schemaFields
|
|
3006
|
+
schemaFields.select = argsBuilder.buildCountSelectSchema(
|
|
2651
3007
|
model,
|
|
2652
3008
|
shape.select
|
|
2653
3009
|
);
|
|
2654
3010
|
} else {
|
|
2655
3011
|
const result = projectionBuilder.buildSelectSchema(model, shape.select);
|
|
2656
|
-
schemaFields
|
|
3012
|
+
schemaFields.select = result.schema;
|
|
2657
3013
|
forcedSelectTree = result.forcedTree;
|
|
2658
3014
|
forcedSelectCountWhere = result.forcedCountWhere;
|
|
2659
3015
|
}
|
|
@@ -2667,7 +3023,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2667
3023
|
for (const field of shape.by) {
|
|
2668
3024
|
groupByOrderFields[field] = sortEnum.optional();
|
|
2669
3025
|
}
|
|
2670
|
-
groupByOrderFields
|
|
3026
|
+
groupByOrderFields._count = sortEnum.optional();
|
|
2671
3027
|
const fieldKeys = Object.keys(groupByOrderFields);
|
|
2672
3028
|
const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
|
|
2673
3029
|
(v) => fieldKeys.some(
|
|
@@ -2675,13 +3031,16 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2675
3031
|
),
|
|
2676
3032
|
{ message: "orderBy must specify at least one field" }
|
|
2677
3033
|
);
|
|
2678
|
-
schemaFields
|
|
3034
|
+
schemaFields.orderBy = import_zod7.z.union([
|
|
3035
|
+
singleSchema,
|
|
3036
|
+
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3037
|
+
]).optional();
|
|
2679
3038
|
} else {
|
|
2680
3039
|
const groupByOrderFields = {};
|
|
2681
3040
|
for (const [fieldName, config] of Object.entries(shape.orderBy)) {
|
|
2682
3041
|
if (fieldName === "_count") {
|
|
2683
3042
|
if (config === true) {
|
|
2684
|
-
groupByOrderFields
|
|
3043
|
+
groupByOrderFields._count = sortEnum.optional();
|
|
2685
3044
|
} else if (typeof config === "object" && config !== null) {
|
|
2686
3045
|
const countFields = {};
|
|
2687
3046
|
for (const countField of Object.keys(config)) {
|
|
@@ -2693,7 +3052,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2693
3052
|
countFields[countField] = sortEnum.optional();
|
|
2694
3053
|
}
|
|
2695
3054
|
const countKeys = Object.keys(countFields);
|
|
2696
|
-
groupByOrderFields
|
|
3055
|
+
groupByOrderFields._count = import_zod7.z.object(countFields).strict().refine(
|
|
2697
3056
|
(v) => countKeys.some(
|
|
2698
3057
|
(k) => v[k] !== void 0
|
|
2699
3058
|
),
|
|
@@ -2718,70 +3077,83 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2718
3077
|
),
|
|
2719
3078
|
{ message: "orderBy must specify at least one field" }
|
|
2720
3079
|
);
|
|
2721
|
-
schemaFields
|
|
3080
|
+
schemaFields.orderBy = import_zod7.z.union([
|
|
3081
|
+
singleSchema,
|
|
3082
|
+
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3083
|
+
]).optional();
|
|
2722
3084
|
}
|
|
2723
3085
|
} else {
|
|
2724
|
-
schemaFields
|
|
3086
|
+
schemaFields.orderBy = argsBuilder.buildOrderBySchema(
|
|
2725
3087
|
model,
|
|
2726
3088
|
shape.orderBy
|
|
2727
3089
|
);
|
|
2728
3090
|
}
|
|
2729
3091
|
}
|
|
2730
|
-
if (shape.cursor)
|
|
2731
|
-
schemaFields
|
|
3092
|
+
if (shape.cursor) {
|
|
3093
|
+
schemaFields.cursor = argsBuilder.buildCursorSchema(
|
|
2732
3094
|
model,
|
|
2733
3095
|
shape.cursor
|
|
2734
3096
|
);
|
|
2735
|
-
|
|
2736
|
-
|
|
3097
|
+
}
|
|
3098
|
+
if (shape.take) {
|
|
3099
|
+
schemaFields.take = argsBuilder.buildTakeSchema(shape.take);
|
|
3100
|
+
}
|
|
2737
3101
|
if (shape.skip !== void 0) {
|
|
2738
3102
|
if (shape.skip !== true) {
|
|
2739
3103
|
throw new ShapeError('Shape config "skip" must be true');
|
|
2740
3104
|
}
|
|
2741
|
-
schemaFields
|
|
3105
|
+
schemaFields.skip = import_zod7.z.number().int().min(0).optional();
|
|
2742
3106
|
}
|
|
2743
|
-
if (shape.distinct)
|
|
2744
|
-
schemaFields
|
|
3107
|
+
if (shape.distinct) {
|
|
3108
|
+
schemaFields.distinct = argsBuilder.buildDistinctSchema(
|
|
2745
3109
|
model,
|
|
2746
3110
|
shape.distinct
|
|
2747
3111
|
);
|
|
2748
|
-
|
|
2749
|
-
|
|
3112
|
+
}
|
|
3113
|
+
if (shape._count) {
|
|
3114
|
+
schemaFields._count = argsBuilder.buildCountFieldSchema(
|
|
2750
3115
|
model,
|
|
2751
3116
|
shape._count,
|
|
2752
3117
|
"_count"
|
|
2753
3118
|
);
|
|
2754
|
-
|
|
2755
|
-
|
|
3119
|
+
}
|
|
3120
|
+
if (shape._avg) {
|
|
3121
|
+
schemaFields._avg = argsBuilder.buildAggregateFieldSchema(
|
|
2756
3122
|
model,
|
|
2757
3123
|
"_avg",
|
|
2758
3124
|
shape._avg
|
|
2759
3125
|
);
|
|
2760
|
-
|
|
2761
|
-
|
|
3126
|
+
}
|
|
3127
|
+
if (shape._sum) {
|
|
3128
|
+
schemaFields._sum = argsBuilder.buildAggregateFieldSchema(
|
|
2762
3129
|
model,
|
|
2763
3130
|
"_sum",
|
|
2764
3131
|
shape._sum
|
|
2765
3132
|
);
|
|
2766
|
-
|
|
2767
|
-
|
|
3133
|
+
}
|
|
3134
|
+
if (shape._min) {
|
|
3135
|
+
schemaFields._min = argsBuilder.buildAggregateFieldSchema(
|
|
2768
3136
|
model,
|
|
2769
3137
|
"_min",
|
|
2770
3138
|
shape._min
|
|
2771
3139
|
);
|
|
2772
|
-
|
|
2773
|
-
|
|
3140
|
+
}
|
|
3141
|
+
if (shape._max) {
|
|
3142
|
+
schemaFields._max = argsBuilder.buildAggregateFieldSchema(
|
|
2774
3143
|
model,
|
|
2775
3144
|
"_max",
|
|
2776
3145
|
shape._max
|
|
2777
3146
|
);
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
3147
|
+
}
|
|
3148
|
+
if (shape.by) {
|
|
3149
|
+
schemaFields.by = argsBuilder.buildBySchema(model, shape.by);
|
|
3150
|
+
}
|
|
3151
|
+
if (shape.having) {
|
|
3152
|
+
schemaFields.having = argsBuilder.buildHavingSchema(
|
|
2782
3153
|
model,
|
|
2783
3154
|
shape.having
|
|
2784
3155
|
);
|
|
3156
|
+
}
|
|
2785
3157
|
return {
|
|
2786
3158
|
zodSchema: import_zod7.z.object(schemaFields).strict(),
|
|
2787
3159
|
forcedWhere,
|
|
@@ -2799,7 +3171,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2799
3171
|
return { key: matched, shape: shapes[matched] };
|
|
2800
3172
|
}
|
|
2801
3173
|
function resolveDefaultShape(config, model, method, normalizedBody, opts, builtCache, isUnique) {
|
|
2802
|
-
const shapeOrFn = config
|
|
3174
|
+
const shapeOrFn = config.default;
|
|
2803
3175
|
let built;
|
|
2804
3176
|
if (typeof shapeOrFn === "function") {
|
|
2805
3177
|
const resolved = resolveAndValidateShape(shapeOrFn, opts?.ctx);
|
|
@@ -2853,8 +3225,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2853
3225
|
built = builtCache.get("_default");
|
|
2854
3226
|
}
|
|
2855
3227
|
} else {
|
|
2856
|
-
if (!isPlainObject(normalizedBody))
|
|
3228
|
+
if (!isPlainObject(normalizedBody)) {
|
|
2857
3229
|
throw new ShapeError("Request body must be an object");
|
|
3230
|
+
}
|
|
2858
3231
|
if ("caller" in normalizedBody) {
|
|
2859
3232
|
throw new CallerError(
|
|
2860
3233
|
"Pass caller via opts.caller, not in the request body."
|
|
@@ -4184,8 +4557,9 @@ function buildDefaultSelectInput(config) {
|
|
|
4184
4557
|
const nested = {};
|
|
4185
4558
|
if (value.select)
|
|
4186
4559
|
nested.select = buildDefaultSelectInput(value.select);
|
|
4187
|
-
if (value.include)
|
|
4560
|
+
if (value.include) {
|
|
4188
4561
|
nested.include = buildDefaultIncludeInput(value.include);
|
|
4562
|
+
}
|
|
4189
4563
|
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
4190
4564
|
}
|
|
4191
4565
|
}
|
|
@@ -4204,8 +4578,9 @@ function buildDefaultIncludeInput(config) {
|
|
|
4204
4578
|
result[key] = true;
|
|
4205
4579
|
} else {
|
|
4206
4580
|
const nested = {};
|
|
4207
|
-
if (value.include)
|
|
4581
|
+
if (value.include) {
|
|
4208
4582
|
nested.include = buildDefaultIncludeInput(value.include);
|
|
4583
|
+
}
|
|
4209
4584
|
if (value.select)
|
|
4210
4585
|
nested.select = buildDefaultSelectInput(value.select);
|
|
4211
4586
|
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
@@ -4216,8 +4591,9 @@ function buildDefaultIncludeInput(config) {
|
|
|
4216
4591
|
function buildDefaultCountInput(config) {
|
|
4217
4592
|
if (config === true)
|
|
4218
4593
|
return true;
|
|
4219
|
-
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select))
|
|
4594
|
+
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select)) {
|
|
4220
4595
|
return true;
|
|
4596
|
+
}
|
|
4221
4597
|
const selectObj = config.select;
|
|
4222
4598
|
const result = {};
|
|
4223
4599
|
for (const key of Object.keys(selectObj)) {
|
|
@@ -4299,8 +4675,9 @@ function checkIncludeForClientArgs(config) {
|
|
|
4299
4675
|
continue;
|
|
4300
4676
|
if (value.orderBy || value.cursor || value.take || value.skip)
|
|
4301
4677
|
return true;
|
|
4302
|
-
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where))
|
|
4678
|
+
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where)) {
|
|
4303
4679
|
return true;
|
|
4680
|
+
}
|
|
4304
4681
|
if (value.include && checkIncludeForClientArgs(value.include))
|
|
4305
4682
|
return true;
|
|
4306
4683
|
if (value.select && checkSelectForClientArgs(value.select))
|
|
@@ -4327,8 +4704,9 @@ function checkSelectForClientArgs(config) {
|
|
|
4327
4704
|
continue;
|
|
4328
4705
|
if (value.orderBy || value.cursor || value.take || value.skip)
|
|
4329
4706
|
return true;
|
|
4330
|
-
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where))
|
|
4707
|
+
if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where)) {
|
|
4331
4708
|
return true;
|
|
4709
|
+
}
|
|
4332
4710
|
if (value.select && checkSelectForClientArgs(value.select))
|
|
4333
4711
|
return true;
|
|
4334
4712
|
if (value.include && checkIncludeForClientArgs(value.include))
|
|
@@ -4389,36 +4767,7 @@ function createModelGuardExtension(config) {
|
|
|
4389
4767
|
validateUniqueEquality(modelName, shape.where, method, uniqueMap, typeMap);
|
|
4390
4768
|
}
|
|
4391
4769
|
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
|
-
}
|
|
4770
|
+
validateUniqueEquality(modelName, where, method, uniqueMap, typeMap);
|
|
4422
4771
|
}
|
|
4423
4772
|
function createGuardedMethods(modelName, modelDelegate, input, explicitCaller) {
|
|
4424
4773
|
function callDelegate(method, args) {
|
|
@@ -4692,10 +5041,10 @@ function createModelGuardExtension(config) {
|
|
|
4692
5041
|
`Invalid "where" on model "${modelName}": unique where must be a plain object`
|
|
4693
5042
|
);
|
|
4694
5043
|
}
|
|
4695
|
-
const sanitized =
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
}
|
|
5044
|
+
const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(
|
|
5045
|
+
bodyWhere,
|
|
5046
|
+
built.forced
|
|
5047
|
+
) : { ...bodyWhere };
|
|
4699
5048
|
try {
|
|
4700
5049
|
result = built.schema.parse(sanitized);
|
|
4701
5050
|
} catch (err) {
|
|
@@ -4708,16 +5057,23 @@ function createModelGuardExtension(config) {
|
|
|
4708
5057
|
}
|
|
4709
5058
|
} else if (bodyWhere !== void 0 && bodyWhere !== null) {
|
|
4710
5059
|
if (isPlainObject(bodyWhere)) {
|
|
4711
|
-
const
|
|
4712
|
-
|
|
5060
|
+
const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(
|
|
5061
|
+
bodyWhere,
|
|
5062
|
+
built.forced
|
|
5063
|
+
) : { ...bodyWhere };
|
|
5064
|
+
if (Object.keys(sanitized).length > 0) {
|
|
4713
5065
|
throw new ShapeError(
|
|
4714
5066
|
`Unique where on model "${modelName}" contains only forced values. Client where input is not accepted.`
|
|
4715
5067
|
);
|
|
4716
5068
|
}
|
|
5069
|
+
} else {
|
|
5070
|
+
throw new ShapeError(
|
|
5071
|
+
`Invalid "where" on model "${modelName}": unique where must be a plain object`
|
|
5072
|
+
);
|
|
4717
5073
|
}
|
|
4718
5074
|
}
|
|
4719
|
-
|
|
4720
|
-
result
|
|
5075
|
+
if (hasWhereForced(built.forced)) {
|
|
5076
|
+
result = mergeUniqueWhereForced(result, built.forced);
|
|
4721
5077
|
}
|
|
4722
5078
|
return result;
|
|
4723
5079
|
}
|
|
@@ -4730,7 +5086,9 @@ function createModelGuardExtension(config) {
|
|
|
4730
5086
|
);
|
|
4731
5087
|
if (Object.keys(where).length === 0) {
|
|
4732
5088
|
const constraints = uniqueMap[modelName];
|
|
4733
|
-
const constraintDesc = constraints ? constraints.map(
|
|
5089
|
+
const constraintDesc = constraints ? constraints.map(
|
|
5090
|
+
(constraint) => constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`
|
|
5091
|
+
).join(" | ") : "unknown";
|
|
4734
5092
|
const expectedFields = shape.where ? Object.keys(shape.where).join(", ") : "none defined";
|
|
4735
5093
|
throw new ShapeError(
|
|
4736
5094
|
`${method} on model "${modelName}" requires a unique where condition. Unique constraints: ${constraintDesc}. Shape allows: ${expectedFields}`
|
|
@@ -4806,8 +5164,9 @@ function createModelGuardExtension(config) {
|
|
|
4806
5164
|
return (body) => {
|
|
4807
5165
|
const caller = resolveCaller();
|
|
4808
5166
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
4809
|
-
if (!resolved.shape.data)
|
|
5167
|
+
if (!resolved.shape.data) {
|
|
4810
5168
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5169
|
+
}
|
|
4811
5170
|
validateMutationShapeKeys(
|
|
4812
5171
|
resolved.shape,
|
|
4813
5172
|
allowedShapeKeys,
|
|
@@ -4838,10 +5197,12 @@ function createModelGuardExtension(config) {
|
|
|
4838
5197
|
);
|
|
4839
5198
|
args = { data };
|
|
4840
5199
|
} else {
|
|
4841
|
-
if (!Array.isArray(resolved.body.data))
|
|
5200
|
+
if (!Array.isArray(resolved.body.data)) {
|
|
4842
5201
|
throw new ShapeError(`${method} expects data to be an array`);
|
|
4843
|
-
|
|
5202
|
+
}
|
|
5203
|
+
if (resolved.body.data.length === 0) {
|
|
4844
5204
|
throw new ShapeError(`${method} received empty data array`);
|
|
5205
|
+
}
|
|
4845
5206
|
const data = resolved.body.data.map(
|
|
4846
5207
|
(item) => validateAndMergeData(item, dataSchema, method, modelName)
|
|
4847
5208
|
);
|
|
@@ -4875,8 +5236,9 @@ function createModelGuardExtension(config) {
|
|
|
4875
5236
|
return (body) => {
|
|
4876
5237
|
const caller = resolveCaller();
|
|
4877
5238
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
4878
|
-
if (!resolved.shape.data)
|
|
5239
|
+
if (!resolved.shape.data) {
|
|
4879
5240
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5241
|
+
}
|
|
4880
5242
|
validateMutationShapeKeys(
|
|
4881
5243
|
resolved.shape,
|
|
4882
5244
|
allowedShapeKeys,
|
|
@@ -4955,8 +5317,9 @@ function createModelGuardExtension(config) {
|
|
|
4955
5317
|
return (body) => {
|
|
4956
5318
|
const caller = resolveCaller();
|
|
4957
5319
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
4958
|
-
if (resolved.shape.data)
|
|
5320
|
+
if (resolved.shape.data) {
|
|
4959
5321
|
throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
|
|
5322
|
+
}
|
|
4960
5323
|
validateMutationShapeKeys(
|
|
4961
5324
|
resolved.shape,
|
|
4962
5325
|
allowedShapeKeys,
|