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.
@@ -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(fieldMeta) {
377
- if (fieldMeta.isList)
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 (fieldMeta.isEnum)
391
+ if (enumField)
380
392
  return [...ENUM_OPERATORS];
381
- const ops = SCALAR_OPERATORS[fieldMeta.type];
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((o) => o !== "not");
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
- (v) => nestedKeys.some(
463
- (k) => v[k] !== void 0
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(fieldMeta, scalarSchema, enumMap, scalarBase);
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(fieldMeta, scalarSchema, enumMap, scalarBase);
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
- let result = where ? { ...where } : {};
1006
- for (const [relName, opMap] of Object.entries(forced.relations)) {
1007
- if (!result[relName] || typeof result[relName] !== "object") {
1008
- result[relName] = {};
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
- if (Object.keys(forced.conditions).length > 0) {
1019
- const conditions = [deepClone(forced.conditions)];
1020
- const existing = result.AND;
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
- if (forced.select)
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 collectWhereFieldKeys(where) {
1222
- const keys = /* @__PURE__ */ new Set();
1223
- for (const [key, value] of Object.entries(where)) {
1224
- if (key === "AND") {
1225
- const items = Array.isArray(value) ? value : [value];
1226
- for (const item of items) {
1227
- if (isPlainObject(item)) {
1228
- for (const k of collectWhereFieldKeys(item))
1229
- keys.add(k);
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
- return keys;
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) => constraint.every((field) => fieldKeys.has(field))
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: ${constraintDesc}`
1311
+ `${method} on model "${model}" requires resolved where to cover a unique constraint: ${formatUniqueConstraints(constraints)}`
1250
1312
  );
1251
1313
  }
1252
1314
  }
1253
- function collectEqualityFields(where, model, typeMap) {
1254
- const combinators = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
1255
- const fields = /* @__PURE__ */ new Set();
1256
- for (const [key, value] of Object.entries(where)) {
1257
- if (key === "AND") {
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 (combinators.has(key))
1266
- continue;
1267
- if (typeMap && model && typeMap[model]?.[key]?.isRelation)
1268
- continue;
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
- return fields;
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) => constraint.every((field) => equalityFields.has(field))
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 with equality operators only: ${constraintDesc}`
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["mode"] = import_zod4.z.enum(["default", "insensitive"]).optional();
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["mode"] = parsed;
1820
+ fieldForced.mode = parsed;
1701
1821
  }
1702
1822
  } else if (hasModeCompatibleOp) {
1703
- opSchemas["mode"] = import_zod4.z.enum(["default", "insensitive"]).optional();
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 forced = {};
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
- throw new ShapeError(`Unknown field "${key}" on model "${model}"`);
1747
- if (fieldMeta.isRelation)
1966
+ if (!fieldMeta) {
1967
+ const selectors = (uniqueMap[model] ?? []).map((constraint2) => constraint2.selector).join(", ");
1748
1968
  throw new ShapeError(
1749
- `Relation field "${key}" cannot be used in unique where for model "${model}"`
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
- const equalsWrapper = import_zod4.z.object({ equals: directSchema }).strict().transform((v) => v.equals);
1763
- if (value === true) {
1764
- fieldSchemas[key] = import_zod4.z.union([directSchema, equalsWrapper]);
1765
- continue;
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
- if (isPlainObject(value)) {
1977
+ const forced = isForcedValue(value);
1978
+ if (!forced && isPlainObject(value)) {
1768
1979
  const keys = Object.keys(value);
1769
- if (keys.length === 1 && keys[0] === "equals") {
1770
- const equalsVal = value.equals;
1771
- if (equalsVal === true) {
1772
- fieldSchemas[key] = import_zod4.z.union([directSchema, equalsWrapper]);
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
- `Unique where field "${key}" on model "${model}" only accepts true or { equals: true/value }. Got operators: ${keys.join(", ")}`
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 actual = isForcedValue(value) ? value.value : value;
1791
- try {
1792
- forced[key] = directSchema.parse(actual);
1793
- } catch (err) {
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(`Relation field "${fieldName}" in orderBy requires a nested config object, not true`);
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(`Json field "${fieldName}" cannot be used in orderBy`);
2044
+ throw new ShapeError(
2045
+ `Json field "${fieldName}" cannot be used in orderBy`
2046
+ );
1834
2047
  if (fieldMeta.isList)
1835
- throw new ShapeError(`List field "${fieldName}" cannot be used in orderBy`);
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(`Unknown field "${fieldName}" on model "${model}"`);
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 (typeof config !== "object" || config === null) {
1852
- throw new ShapeError(`Invalid orderBy config for "${fieldName}" on model "${model}": expected true or a nested config object`);
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
- throw new ShapeError(`Scalar field "${fieldName}" in orderBy does not accept nested config`);
1856
- }
1857
- if (Object.keys(config).length === 0) {
1858
- throw new ShapeError(`Empty orderBy config for relation "${fieldName}" on model "${model}". Define at least one nested field.`);
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
- const relKeys = Object.keys(config);
1862
- if (relKeys.length !== 1 || relKeys[0] !== "_count") {
1863
- throw new ShapeError(`To-many relation "${fieldName}" in orderBy only supports { _count: true }`);
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(`_count in orderBy for "${fieldName}" must be true`);
2110
+ throw new ShapeError(
2111
+ `orderBy relation aggregate "${fieldName}._count" must be true`
2112
+ );
1867
2113
  }
1868
- fieldSchemas[fieldName] = import_zod5.z.object({ _count: sortEnum }).strict().optional();
2114
+ fieldSchemas[fieldName] = import_zod5.z.object({
2115
+ _count: sortEnum.optional()
2116
+ }).strict().optional();
1869
2117
  continue;
1870
2118
  }
1871
- const relatedModel = fieldMeta.type;
1872
- const relatedFields = typeMap[relatedModel];
1873
- if (!relatedFields)
1874
- throw new ShapeError(`Related model "${relatedModel}" not found in type map`);
1875
- const nestedSchemas = {};
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((k) => v[k] !== void 0),
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([singleSchema, import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))]).optional();
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
- const normalized = typeof config === "number" ? { max: config, default: config } : config;
1906
- if (!Number.isFinite(normalized.max) || !Number.isInteger(normalized.max)) {
1907
- throw new ShapeError(`take max must be a finite integer, got ${normalized.max}`);
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 (normalized.max < 1) {
1910
- throw new ShapeError(`take max must be at least 1, got ${normalized.max}`);
2155
+ if (config.max <= 0) {
2156
+ throw new ShapeError("take.max must be a positive integer");
1911
2157
  }
1912
- if (normalized.default !== void 0) {
1913
- if (!Number.isFinite(normalized.default) || !Number.isInteger(normalized.default)) {
1914
- throw new ShapeError(`take default must be a finite integer, got ${normalized.default}`);
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 (normalized.default < 1) {
1917
- throw new ShapeError(`take default must be at least 1, got ${normalized.default}`);
2164
+ if (config.default <= 0) {
2165
+ throw new ShapeError("take.default must be a positive integer");
1918
2166
  }
1919
- if (normalized.default > normalized.max) {
1920
- throw new ShapeError("take default cannot exceed max");
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(normalized.max).default(normalized.default);
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(normalized.max).optional();
2172
+ return import_zod5.z.number().int().min(1).max(config.max).optional();
1925
2173
  }
1926
- function buildCursorSchema(model, cursorConfig) {
2174
+ function buildCursorFieldSchema(model, fieldName) {
1927
2175
  const modelFields = typeMap[model];
1928
2176
  if (!modelFields)
1929
2177
  throw new ShapeError(`Unknown model: ${model}`);
1930
- requireConfigTrue(cursorConfig, `cursor on model "${model}"`);
1931
- const cursorFields = new Set(Object.keys(cursorConfig));
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
- const covered = constraints.some(
1935
- (constraint) => constraint.length === cursorFields.size && constraint.every((field) => cursorFields.has(field))
1936
- );
1937
- if (!covered) {
1938
- const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
1939
- throw new ShapeError(
1940
- `cursor on model "${model}" must exactly match a unique constraint: ${constraintDesc}`
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
- for (const fieldName of Object.keys(cursorConfig)) {
1946
- const fieldMeta = modelFields[fieldName];
1947
- if (!fieldMeta)
1948
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in cursor`);
1949
- if (fieldMeta.isRelation)
1950
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in cursor`);
1951
- if (fieldMeta.isList)
1952
- throw new ShapeError(`List field "${fieldName}" cannot be used in cursor`);
1953
- fieldSchemas[fieldName] = createBaseType(fieldMeta, enumMap, scalarBase);
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().optional();
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(`Unknown field "${fieldName}" on model "${model}" in distinct`);
2282
+ throw new ShapeError(
2283
+ `Unknown field "${fieldName}" on model "${model}" in distinct`
2284
+ );
1968
2285
  if (fieldMeta.isRelation)
1969
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in distinct`);
1970
- if (fieldMeta.isList)
1971
- throw new ShapeError(`List field "${fieldName}" cannot be used in distinct`);
2286
+ throw new ShapeError(
2287
+ `Relation field "${fieldName}" cannot be used in distinct`
2288
+ );
2289
+ allowedFields.add(fieldName);
1972
2290
  }
1973
- const enumSchema = import_zod5.z.enum(distinctConfig);
1974
- return import_zod5.z.union([enumSchema, import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(enumSchema).min(1))]).optional();
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(`Unknown field "${fieldName}" on model "${model}" in by`);
2309
+ throw new ShapeError(
2310
+ `Unknown field "${fieldName}" on model "${model}" in groupBy by`
2311
+ );
1987
2312
  if (fieldMeta.isRelation)
1988
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in by`);
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(`${fieldMeta.type} field "${fieldName}" cannot be used in by`);
2321
+ throw new ShapeError(
2322
+ `${fieldMeta.type} field "${fieldName}" cannot be used in groupBy by`
2323
+ );
1991
2324
  }
1992
- if (fieldMeta.isList)
1993
- throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
2325
+ allowedFields.add(fieldName);
1994
2326
  }
1995
- const enumSchema = import_zod5.z.enum(byConfig);
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(`Unknown field "${fieldName}" on model "${model}" in having`);
2338
+ throw new ShapeError(
2339
+ `Unknown field "${fieldName}" on model "${model}" in having`
2340
+ );
2008
2341
  if (fieldMeta.isRelation)
2009
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in having`);
2342
+ throw new ShapeError(
2343
+ `Relation field "${fieldName}" cannot be used in having`
2344
+ );
2010
2345
  if (fieldMeta.isList)
2011
- throw new ShapeError(`List field "${fieldName}" cannot be used in having`);
2012
- const ops = getSupportedOperators(fieldMeta);
2013
- if (ops.length === 0) {
2014
- throw new ShapeError(`${fieldMeta.type} field "${fieldName}" cannot be used in having filters`);
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 opKeys = [];
2018
- for (const op of ops) {
2019
- opSchemas[op] = createOperatorSchema(fieldMeta, op, enumMap, scalarBase).optional();
2020
- opKeys.push(op);
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" && !fieldMeta.isList) {
2023
- opSchemas["mode"] = import_zod5.z.enum(["default", "insensitive"]).optional();
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
- { message: `At least one operator required for having field "${fieldName}"` }
2373
+ {
2374
+ message: `having field "${fieldName}" must specify at least one operator`
2375
+ }
2028
2376
  ).optional();
2029
2377
  }
2030
- const havingFieldKeys = Object.keys(fieldSchemas);
2031
- const havingSchema = import_zod5.z.lazy(() => {
2032
- const allSchemas = { ...fieldSchemas };
2033
- allSchemas["AND"] = import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(havingSchema).min(1)).optional();
2034
- allSchemas["OR"] = import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(havingSchema).min(1)).optional();
2035
- allSchemas["NOT"] = import_zod5.z.union([
2036
- havingSchema,
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, opName, fieldConfig) {
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(fieldConfig, `${opName} on model "${model}"`);
2052
- const isNumericOnly = opName === "_avg" || opName === "_sum";
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(fieldConfig)) {
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(`Unknown field "${fieldName}" on model "${model}" in ${opName}`);
2396
+ throw new ShapeError(
2397
+ `Unknown field "${fieldName}" on model "${model}" in ${op}`
2398
+ );
2063
2399
  if (fieldMeta.isRelation)
2064
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in ${opName}`);
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
- `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only numeric types (Int, Float, Decimal, BigInt) are supported.`
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}" (${fieldMeta.type}) cannot be used in ${opName}. Only comparable types (Int, Float, Decimal, BigInt, String, DateTime) are supported.`
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 aggFieldKeys = Object.keys(fieldSchemas);
2414
+ const aggregateFieldKeys = Object.keys(fieldSchemas);
2080
2415
  return import_zod5.z.object(fieldSchemas).strict().refine(
2081
- (v) => aggFieldKeys.some((k) => v[k] !== void 0),
2082
- { message: `${opName} must specify at least one field` }
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(`Unknown field "${fieldName}" on model "${model}" in ${context}`);
2435
+ throw new ShapeError(
2436
+ `Unknown field "${fieldName}" on model "${model}" in ${context}`
2437
+ );
2099
2438
  if (fieldMeta.isRelation)
2100
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in ${context}`);
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((k) => v[k] !== void 0),
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["_all"] = import_zod5.z.literal(true).optional();
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(`Unknown field "${fieldName}" on model "${model}" in count select`);
2466
+ throw new ShapeError(
2467
+ `Unknown field "${fieldName}" on model "${model}" in count select`
2468
+ );
2124
2469
  if (fieldMeta.isRelation)
2125
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in count select`);
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((k) => v[k] !== void 0),
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(typeMap, enumMap, scalarBase);
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
- if (!allowed.has(key))
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 { schema, forced, forcedOnlyKeys } = whereBuilder.buildWhereSchema(
2634
- model,
2635
- shape.where
2636
- );
2637
- if (schema)
2638
- schemaFields["where"] = schema;
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["include"] = result.schema;
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["select"] = argsBuilder.buildCountSelectSchema(
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["select"] = result.schema;
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["_count"] = sortEnum.optional();
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["orderBy"] = import_zod7.z.union([singleSchema, import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))]).optional();
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["_count"] = sortEnum.optional();
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["_count"] = import_zod7.z.object(countFields).strict().refine(
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["orderBy"] = import_zod7.z.union([singleSchema, import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))]).optional();
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["orderBy"] = argsBuilder.buildOrderBySchema(
3086
+ schemaFields.orderBy = argsBuilder.buildOrderBySchema(
2725
3087
  model,
2726
3088
  shape.orderBy
2727
3089
  );
2728
3090
  }
2729
3091
  }
2730
- if (shape.cursor)
2731
- schemaFields["cursor"] = argsBuilder.buildCursorSchema(
3092
+ if (shape.cursor) {
3093
+ schemaFields.cursor = argsBuilder.buildCursorSchema(
2732
3094
  model,
2733
3095
  shape.cursor
2734
3096
  );
2735
- if (shape.take)
2736
- schemaFields["take"] = argsBuilder.buildTakeSchema(shape.take);
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["skip"] = import_zod7.z.number().int().min(0).optional();
3105
+ schemaFields.skip = import_zod7.z.number().int().min(0).optional();
2742
3106
  }
2743
- if (shape.distinct)
2744
- schemaFields["distinct"] = argsBuilder.buildDistinctSchema(
3107
+ if (shape.distinct) {
3108
+ schemaFields.distinct = argsBuilder.buildDistinctSchema(
2745
3109
  model,
2746
3110
  shape.distinct
2747
3111
  );
2748
- if (shape._count)
2749
- schemaFields["_count"] = argsBuilder.buildCountFieldSchema(
3112
+ }
3113
+ if (shape._count) {
3114
+ schemaFields._count = argsBuilder.buildCountFieldSchema(
2750
3115
  model,
2751
3116
  shape._count,
2752
3117
  "_count"
2753
3118
  );
2754
- if (shape._avg)
2755
- schemaFields["_avg"] = argsBuilder.buildAggregateFieldSchema(
3119
+ }
3120
+ if (shape._avg) {
3121
+ schemaFields._avg = argsBuilder.buildAggregateFieldSchema(
2756
3122
  model,
2757
3123
  "_avg",
2758
3124
  shape._avg
2759
3125
  );
2760
- if (shape._sum)
2761
- schemaFields["_sum"] = argsBuilder.buildAggregateFieldSchema(
3126
+ }
3127
+ if (shape._sum) {
3128
+ schemaFields._sum = argsBuilder.buildAggregateFieldSchema(
2762
3129
  model,
2763
3130
  "_sum",
2764
3131
  shape._sum
2765
3132
  );
2766
- if (shape._min)
2767
- schemaFields["_min"] = argsBuilder.buildAggregateFieldSchema(
3133
+ }
3134
+ if (shape._min) {
3135
+ schemaFields._min = argsBuilder.buildAggregateFieldSchema(
2768
3136
  model,
2769
3137
  "_min",
2770
3138
  shape._min
2771
3139
  );
2772
- if (shape._max)
2773
- schemaFields["_max"] = argsBuilder.buildAggregateFieldSchema(
3140
+ }
3141
+ if (shape._max) {
3142
+ schemaFields._max = argsBuilder.buildAggregateFieldSchema(
2774
3143
  model,
2775
3144
  "_max",
2776
3145
  shape._max
2777
3146
  );
2778
- if (shape.by)
2779
- schemaFields["by"] = argsBuilder.buildBySchema(model, shape.by);
2780
- if (shape.having)
2781
- schemaFields["having"] = argsBuilder.buildHavingSchema(
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["default"];
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
- const constraints = uniqueMap[modelName];
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 = { ...bodyWhere };
4696
- for (const key of built.forcedOnlyKeys) {
4697
- delete sanitized[key];
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 hasOnlyForcedKeys = built.forcedOnlyKeys.size > 0 && Object.keys(bodyWhere).every((k) => built.forcedOnlyKeys.has(k));
4712
- if (!hasOnlyForcedKeys && Object.keys(bodyWhere).length > 0) {
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
- for (const [key, value] of Object.entries(built.forced)) {
4720
- result[key] = value;
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((c) => `(${c.join(", ")})`).join(" | ") : "unknown";
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
- if (resolved.body.data.length === 0)
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,