prisma-guard 1.24.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ );
1325
+ }
1326
+ }
1327
+ if (isForcedValue(value))
1328
+ return;
1329
+ if (isPlainObject(value)) {
1330
+ const keys = Object.keys(value);
1331
+ throw new ShapeError(
1332
+ `Invalid unique where shape for "${model ?? "unknown"}.${field}". Prisma WhereUniqueInput does not accept filter operator objects${keys.length ? `: ${keys.join(", ")}` : ""}. Use { ${field}: true } in guard shape and { ${field}: value } in request args.`
1333
+ );
1334
+ }
1335
+ if (value === null || value === void 0) {
1336
+ throw new ShapeError(
1337
+ `Invalid unique where shape for "${model ?? "unknown"}.${field}". Unique fields must use true or a forced value.`
1338
+ );
1339
+ }
1340
+ }
1341
+ function shapeCoversConstraint(where, constraint, model, typeMap) {
1342
+ if (constraint.fields.length === 1) {
1343
+ const field = constraint.fields[0];
1344
+ if (!(field in where))
1345
+ return false;
1346
+ assertDirectUniqueShapeValue(model, field, where[field], typeMap);
1347
+ return true;
1348
+ }
1349
+ if (!(constraint.selector in where))
1350
+ return false;
1351
+ const selectorValue = where[constraint.selector];
1352
+ if (isForcedValue(selectorValue))
1353
+ return true;
1354
+ if (!isPlainObject(selectorValue)) {
1355
+ throw new ShapeError(
1356
+ `Compound unique selector "${model}.${constraint.selector}" must be an object with fields: ${constraint.fields.join(", ")}`
1357
+ );
1358
+ }
1359
+ const allowed = new Set(constraint.fields);
1360
+ for (const key of Object.keys(selectorValue)) {
1361
+ if (!allowed.has(key)) {
1362
+ throw new ShapeError(
1363
+ `Unknown field "${key}" in compound unique selector "${model}.${constraint.selector}". Allowed fields: ${constraint.fields.join(", ")}`
1364
+ );
1273
1365
  }
1274
1366
  }
1275
- return fields;
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) {
@@ -1462,6 +1582,18 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1462
1582
  scalarConditions
1463
1583
  );
1464
1584
  }
1585
+ for (const key of Object.keys(scalarConditions)) {
1586
+ if (COMBINATOR_KEYS.has(key))
1587
+ continue;
1588
+ if (!(key in fieldSchemas)) {
1589
+ fieldSchemas[key] = import_zod4.z.object({}).strict().optional();
1590
+ }
1591
+ }
1592
+ for (const key of Object.keys(relationForced)) {
1593
+ if (!(key in fieldSchemas)) {
1594
+ fieldSchemas[key] = import_zod4.z.object({}).strict().optional();
1595
+ }
1596
+ }
1465
1597
  const schema = Object.keys(fieldSchemas).length > 0 ? import_zod4.z.object(fieldSchemas).strict().optional() : null;
1466
1598
  const forcedOnlyKeys = /* @__PURE__ */ new Set();
1467
1599
  for (const key of Object.keys(whereConfig)) {
@@ -1685,7 +1817,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1685
1817
  );
1686
1818
  }
1687
1819
  if (modeConfigValue === true) {
1688
- opSchemas["mode"] = import_zod4.z.enum(["default", "insensitive"]).optional();
1820
+ opSchemas.mode = import_zod4.z.enum(["default", "insensitive"]).optional();
1689
1821
  } else {
1690
1822
  const actualModeValue = isForcedValue(modeConfigValue) ? modeConfigValue.value : modeConfigValue;
1691
1823
  const modeSchema = import_zod4.z.enum(["default", "insensitive"]);
@@ -1697,10 +1829,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1697
1829
  `Invalid forced value for "${model}.${fieldName}.mode": ${err.message}`
1698
1830
  );
1699
1831
  }
1700
- fieldForced["mode"] = parsed;
1832
+ fieldForced.mode = parsed;
1701
1833
  }
1702
1834
  } else if (hasModeCompatibleOp) {
1703
- opSchemas["mode"] = import_zod4.z.enum(["default", "insensitive"]).optional();
1835
+ opSchemas.mode = import_zod4.z.enum(["default", "insensitive"]).optional();
1704
1836
  }
1705
1837
  if (hasClientOps) {
1706
1838
  const opObj = import_zod4.z.object(opSchemas).strict();
@@ -1728,12 +1860,60 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1728
1860
  scalarConditions[fieldName] = fieldForced;
1729
1861
  }
1730
1862
  }
1863
+ function getUniqueConstraint(model, selector) {
1864
+ return (uniqueMap[model] ?? []).find(
1865
+ (constraint) => constraint.selector === selector
1866
+ ) ?? null;
1867
+ }
1868
+ function buildDirectUniqueSchema(fieldMeta) {
1869
+ const base = createBaseType(fieldMeta, enumMap, scalarBase);
1870
+ if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
1871
+ return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
1872
+ }
1873
+ return base;
1874
+ }
1875
+ function parseForcedUniqueValue(model, fieldName, fieldMeta, value) {
1876
+ const schema = buildDirectUniqueSchema(fieldMeta);
1877
+ const actual = isForcedValue(value) ? value.value : value;
1878
+ try {
1879
+ return schema.parse(actual);
1880
+ } catch (err) {
1881
+ throw new ShapeError(
1882
+ `Invalid forced value for unique where "${model}.${fieldName}": ${err.message}`
1883
+ );
1884
+ }
1885
+ }
1886
+ function assertCompoundSelectorConfig(model, selector, constraint, value) {
1887
+ const actual = isForcedValue(value) ? value.value : value;
1888
+ if (!isPlainObject(actual)) {
1889
+ throw new ShapeError(
1890
+ `Compound unique selector "${model}.${selector}" must be an object with fields: ${constraint.fields.join(", ")}`
1891
+ );
1892
+ }
1893
+ const allowed = new Set(constraint.fields);
1894
+ const keys = Object.keys(actual);
1895
+ for (const key of keys) {
1896
+ if (!allowed.has(key)) {
1897
+ throw new ShapeError(
1898
+ `Unknown field "${key}" in compound unique selector "${model}.${selector}". Allowed fields: ${constraint.fields.join(", ")}`
1899
+ );
1900
+ }
1901
+ }
1902
+ for (const field of constraint.fields) {
1903
+ if (!(field in actual)) {
1904
+ throw new ShapeError(
1905
+ `Missing field "${field}" in compound unique selector "${model}.${selector}"`
1906
+ );
1907
+ }
1908
+ }
1909
+ return actual;
1910
+ }
1731
1911
  function buildUniqueWhereSchema(model, whereConfig) {
1732
1912
  const modelFields = typeMap[model];
1733
1913
  if (!modelFields)
1734
1914
  throw new ShapeError(`Unknown model: ${model}`);
1735
1915
  const fieldSchemas = {};
1736
- const forced = {};
1916
+ const forcedConditions = {};
1737
1917
  const forcedOnlyKeys = /* @__PURE__ */ new Set();
1738
1918
  for (const [key, value] of Object.entries(whereConfig)) {
1739
1919
  if (COMBINATOR_KEYS.has(key)) {
@@ -1741,65 +1921,102 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1741
1921
  `Combinator "${key}" is not supported in unique where for model "${model}"`
1742
1922
  );
1743
1923
  }
1924
+ const constraint = getUniqueConstraint(model, key);
1925
+ if (constraint && constraint.fields.length > 1) {
1926
+ const compoundConfig = assertCompoundSelectorConfig(
1927
+ model,
1928
+ key,
1929
+ constraint,
1930
+ value
1931
+ );
1932
+ const nestedSchemas = {};
1933
+ const forcedCompound = {};
1934
+ for (const fieldName of constraint.fields) {
1935
+ const fieldMeta2 = modelFields[fieldName];
1936
+ if (!fieldMeta2) {
1937
+ throw new ShapeError(
1938
+ `Unknown field "${fieldName}" in compound unique selector "${model}.${key}"`
1939
+ );
1940
+ }
1941
+ if (fieldMeta2.isRelation) {
1942
+ throw new ShapeError(
1943
+ `Relation field "${fieldName}" cannot be used in compound unique selector "${model}.${key}"`
1944
+ );
1945
+ }
1946
+ const fieldValue = compoundConfig[fieldName];
1947
+ const forced2 = isForcedValue(fieldValue);
1948
+ if (!forced2 && isPlainObject(fieldValue)) {
1949
+ const operators = Object.keys(fieldValue);
1950
+ throw new ShapeError(
1951
+ `Invalid compound unique where shape for "${model}.${key}.${fieldName}". Prisma compound unique selectors do not accept filter operator objects${operators.length ? `: ${operators.join(", ")}` : ""}. Use direct values only.`
1952
+ );
1953
+ }
1954
+ const directSchema2 = buildDirectUniqueSchema(fieldMeta2);
1955
+ if (fieldValue === true) {
1956
+ nestedSchemas[fieldName] = directSchema2;
1957
+ } else {
1958
+ forcedCompound[fieldName] = parseForcedUniqueValue(
1959
+ model,
1960
+ fieldName,
1961
+ fieldMeta2,
1962
+ fieldValue
1963
+ );
1964
+ }
1965
+ }
1966
+ if (Object.keys(nestedSchemas).length > 0) {
1967
+ fieldSchemas[key] = import_zod4.z.object(nestedSchemas).strict();
1968
+ }
1969
+ if (Object.keys(forcedCompound).length > 0) {
1970
+ forcedConditions[key] = forcedCompound;
1971
+ }
1972
+ if (Object.keys(nestedSchemas).length === 0) {
1973
+ forcedOnlyKeys.add(key);
1974
+ }
1975
+ continue;
1976
+ }
1744
1977
  const fieldMeta = modelFields[key];
1745
- if (!fieldMeta)
1746
- throw new ShapeError(`Unknown field "${key}" on model "${model}"`);
1747
- if (fieldMeta.isRelation)
1978
+ if (!fieldMeta) {
1979
+ const selectors = (uniqueMap[model] ?? []).map((constraint2) => constraint2.selector).join(", ");
1748
1980
  throw new ShapeError(
1749
- `Relation field "${key}" cannot be used in unique where for model "${model}"`
1981
+ `Unknown unique field or selector "${key}" on model "${model}"${selectors ? `. Unique selectors: ${selectors}` : ""}`
1750
1982
  );
1751
- const base = createBaseType(fieldMeta, enumMap, scalarBase);
1752
- let directSchema;
1753
- if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
1754
- directSchema = wrapWithInputCoercion(
1755
- fieldMeta.type,
1756
- fieldMeta.isList,
1757
- base
1758
- );
1759
- } else {
1760
- directSchema = base;
1761
1983
  }
1762
- 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;
1984
+ if (fieldMeta.isRelation) {
1985
+ throw new ShapeError(
1986
+ `Relation field "${key}" cannot be used in unique where for model "${model}"`
1987
+ );
1766
1988
  }
1767
- if (isPlainObject(value)) {
1989
+ const forced = isForcedValue(value);
1990
+ if (!forced && isPlainObject(value)) {
1768
1991
  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;
1992
+ if (keys.includes("equals")) {
1993
+ throw new ShapeError(
1994
+ `Invalid unique where shape for "${model}.${key}". Prisma WhereUniqueInput does not accept filter operator objects. Use { ${key}: true } instead of { ${key}: { equals: true } }.`
1995
+ );
1785
1996
  }
1786
1997
  throw new ShapeError(
1787
- `Unique where field "${key}" on model "${model}" only accepts true or { equals: true/value }. Got operators: ${keys.join(", ")}`
1998
+ `Invalid unique where shape for "${model}.${key}". Prisma WhereUniqueInput does not accept operators: ${keys.join(", ")}. Use a direct unique value shape, for example { ${key}: true }.`
1788
1999
  );
1789
2000
  }
1790
- const 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
- );
2001
+ const directSchema = buildDirectUniqueSchema(fieldMeta);
2002
+ if (value === true) {
2003
+ fieldSchemas[key] = directSchema;
2004
+ continue;
1797
2005
  }
2006
+ forcedConditions[key] = parseForcedUniqueValue(
2007
+ model,
2008
+ key,
2009
+ fieldMeta,
2010
+ value
2011
+ );
1798
2012
  forcedOnlyKeys.add(key);
1799
2013
  }
1800
2014
  return {
1801
2015
  schema: Object.keys(fieldSchemas).length > 0 ? import_zod4.z.object(fieldSchemas).strict() : null,
1802
- forced,
2016
+ forced: {
2017
+ conditions: forcedConditions,
2018
+ relations: {}
2019
+ },
1803
2020
  forcedOnlyKeys
1804
2021
  };
1805
2022
  }
@@ -1818,6 +2035,15 @@ function requireConfigTrue(config, context) {
1818
2035
  }
1819
2036
  }
1820
2037
  }
2038
+ function isPlainRecord(value) {
2039
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2040
+ }
2041
+ function formatUniqueConstraint2(constraint) {
2042
+ return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
2043
+ }
2044
+ function formatUniqueConstraints2(constraints) {
2045
+ return constraints.map(formatUniqueConstraint2).join(" | ");
2046
+ }
1821
2047
  function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
1822
2048
  const sortEnum = import_zod5.z.enum(["asc", "desc"]);
1823
2049
  const nullsEnum = import_zod5.z.enum(["first", "last"]);
@@ -1828,11 +2054,17 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
1828
2054
  if (!fieldMeta)
1829
2055
  throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
1830
2056
  if (fieldMeta.isRelation)
1831
- throw new ShapeError(`Relation field "${fieldName}" in orderBy requires a nested config object, not true`);
2057
+ throw new ShapeError(
2058
+ `Relation field "${fieldName}" in orderBy requires a nested config object, not true`
2059
+ );
1832
2060
  if (fieldMeta.type === "Json")
1833
- throw new ShapeError(`Json field "${fieldName}" cannot be used in orderBy`);
2061
+ throw new ShapeError(
2062
+ `Json field "${fieldName}" cannot be used in orderBy`
2063
+ );
1834
2064
  if (fieldMeta.isList)
1835
- throw new ShapeError(`List field "${fieldName}" cannot be used in orderBy`);
2065
+ throw new ShapeError(
2066
+ `List field "${fieldName}" cannot be used in orderBy`
2067
+ );
1836
2068
  }
1837
2069
  function buildOrderBySchema(model, orderByConfig) {
1838
2070
  const modelFields = typeMap[model];
@@ -1842,158 +2074,274 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
1842
2074
  for (const [fieldName, config] of Object.entries(orderByConfig)) {
1843
2075
  const fieldMeta = modelFields[fieldName];
1844
2076
  if (!fieldMeta)
1845
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
2077
+ throw new ShapeError(
2078
+ `Unknown field "${fieldName}" on model "${model}"`
2079
+ );
1846
2080
  if (config === true) {
1847
2081
  validateScalarOrderByField(fieldName, model, modelFields);
1848
2082
  fieldSchemas[fieldName] = scalarOrderSchema.optional();
1849
2083
  continue;
1850
2084
  }
1851
- if (typeof config !== "object" || config === null) {
1852
- throw new ShapeError(`Invalid orderBy config for "${fieldName}" on model "${model}": expected true or a nested config object`);
2085
+ if (!isPlainRecord(config)) {
2086
+ throw new ShapeError(
2087
+ `orderBy config for "${fieldName}" on model "${model}" must be true or a relation aggregate object`
2088
+ );
1853
2089
  }
1854
2090
  if (!fieldMeta.isRelation) {
1855
- 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.`);
2091
+ const allowedOps = getSupportedOperators(
2092
+ fieldMeta.type,
2093
+ fieldMeta.isList
2094
+ );
2095
+ const opSchemas = {};
2096
+ for (const [op, enabled] of Object.entries(config)) {
2097
+ if (enabled !== true) {
2098
+ throw new ShapeError(
2099
+ `orderBy operator config for "${model}.${fieldName}.${op}" must be true`
2100
+ );
2101
+ }
2102
+ if (!allowedOps.includes(op)) {
2103
+ throw new ShapeError(
2104
+ `Operator "${op}" not supported for orderBy field "${model}.${fieldName}"`
2105
+ );
2106
+ }
2107
+ opSchemas[op] = scalarOrderSchema.optional();
2108
+ }
2109
+ const opKeys = Object.keys(opSchemas);
2110
+ fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
2111
+ (v) => opKeys.some(
2112
+ (k) => v[k] !== void 0
2113
+ ),
2114
+ {
2115
+ message: `orderBy field "${fieldName}" must specify at least one operator`
2116
+ }
2117
+ ).optional();
2118
+ continue;
1859
2119
  }
1860
2120
  if (fieldMeta.isList) {
1861
- 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 }`);
2121
+ if (!("_count" in config)) {
2122
+ throw new ShapeError(
2123
+ `To-many relation orderBy "${fieldName}" only supports _count`
2124
+ );
1864
2125
  }
1865
2126
  if (config._count !== true) {
1866
- throw new ShapeError(`_count in orderBy for "${fieldName}" must be true`);
2127
+ throw new ShapeError(
2128
+ `orderBy relation aggregate "${fieldName}._count" must be true`
2129
+ );
1867
2130
  }
1868
- fieldSchemas[fieldName] = import_zod5.z.object({ _count: sortEnum }).strict().optional();
2131
+ fieldSchemas[fieldName] = import_zod5.z.object({
2132
+ _count: sortEnum.optional()
2133
+ }).strict().optional();
1869
2134
  continue;
1870
2135
  }
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();
2136
+ const nested = buildOrderBySchema(
2137
+ fieldMeta.type,
2138
+ config
2139
+ );
2140
+ fieldSchemas[fieldName] = nested;
1896
2141
  }
1897
2142
  const fieldKeys = Object.keys(fieldSchemas);
1898
2143
  const singleSchema = import_zod5.z.object(fieldSchemas).strict().refine(
1899
- (v) => fieldKeys.some((k) => v[k] !== void 0),
2144
+ (v) => fieldKeys.some(
2145
+ (k) => v[k] !== void 0
2146
+ ),
1900
2147
  { message: "orderBy must specify at least one field" }
1901
2148
  );
1902
- return import_zod5.z.union([singleSchema, import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))]).optional();
2149
+ return import_zod5.z.union([
2150
+ singleSchema,
2151
+ import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))
2152
+ ]).optional();
1903
2153
  }
1904
2154
  function buildTakeSchema(config) {
1905
- 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}`);
2155
+ if (typeof config === "number") {
2156
+ if (!Number.isFinite(config) || !Number.isInteger(config)) {
2157
+ throw new ShapeError(`take must be a finite integer, got ${config}`);
2158
+ }
2159
+ if (config <= 0) {
2160
+ throw new ShapeError("take must be a positive integer");
2161
+ }
2162
+ return import_zod5.z.literal(config).optional();
2163
+ }
2164
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
2165
+ throw new ShapeError("take config must be a number or { max, default? }");
2166
+ }
2167
+ if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
2168
+ throw new ShapeError(
2169
+ `take.max must be a finite integer, got ${config.max}`
2170
+ );
1908
2171
  }
1909
- if (normalized.max < 1) {
1910
- throw new ShapeError(`take max must be at least 1, got ${normalized.max}`);
2172
+ if (config.max <= 0) {
2173
+ throw new ShapeError("take.max must be a positive integer");
1911
2174
  }
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}`);
2175
+ if (config.default !== void 0) {
2176
+ if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
2177
+ throw new ShapeError(
2178
+ `take.default must be a finite integer, got ${config.default}`
2179
+ );
1915
2180
  }
1916
- if (normalized.default < 1) {
1917
- throw new ShapeError(`take default must be at least 1, got ${normalized.default}`);
2181
+ if (config.default <= 0) {
2182
+ throw new ShapeError("take.default must be a positive integer");
1918
2183
  }
1919
- if (normalized.default > normalized.max) {
1920
- throw new ShapeError("take default cannot exceed max");
2184
+ if (config.default > config.max) {
2185
+ throw new ShapeError("take.default cannot exceed take.max");
1921
2186
  }
1922
- return import_zod5.z.number().int().min(1).max(normalized.max).default(normalized.default);
2187
+ return import_zod5.z.number().int().min(1).max(config.max).default(config.default);
1923
2188
  }
1924
- return import_zod5.z.number().int().min(1).max(normalized.max).optional();
2189
+ return import_zod5.z.number().int().min(1).max(config.max).optional();
1925
2190
  }
1926
- function buildCursorSchema(model, cursorConfig) {
2191
+ function buildCursorFieldSchema(model, fieldName) {
1927
2192
  const modelFields = typeMap[model];
1928
2193
  if (!modelFields)
1929
2194
  throw new ShapeError(`Unknown model: ${model}`);
1930
- requireConfigTrue(cursorConfig, `cursor on model "${model}"`);
1931
- const cursorFields = new Set(Object.keys(cursorConfig));
2195
+ const fieldMeta = modelFields[fieldName];
2196
+ if (!fieldMeta) {
2197
+ throw new ShapeError(
2198
+ `Unknown field "${fieldName}" on model "${model}" in cursor`
2199
+ );
2200
+ }
2201
+ if (fieldMeta.isRelation) {
2202
+ throw new ShapeError(
2203
+ `Relation field "${fieldName}" cannot be used in cursor`
2204
+ );
2205
+ }
2206
+ if (fieldMeta.isList) {
2207
+ throw new ShapeError(
2208
+ `List field "${fieldName}" cannot be used in cursor`
2209
+ );
2210
+ }
2211
+ const base = createBaseType(fieldMeta, enumMap, scalarBase);
2212
+ if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
2213
+ return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
2214
+ }
2215
+ return base;
2216
+ }
2217
+ function cursorConfigMatchesConstraint(cursorConfig, constraint) {
2218
+ if (!(constraint.selector in cursorConfig))
2219
+ return false;
2220
+ const value = cursorConfig[constraint.selector];
2221
+ if (constraint.fields.length === 1) {
2222
+ return value === true;
2223
+ }
2224
+ if (!isPlainRecord(value))
2225
+ return false;
2226
+ const keys = Object.keys(value);
2227
+ if (keys.length !== constraint.fields.length)
2228
+ return false;
2229
+ return constraint.fields.every((field) => value[field] === true);
2230
+ }
2231
+ function getUniqueConstraints(model) {
1932
2232
  const constraints = uniqueMap[model];
1933
2233
  if (constraints && constraints.length > 0) {
1934
- 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
- );
2234
+ return constraints;
2235
+ }
2236
+ const modelFields = typeMap[model];
2237
+ if (!modelFields) {
2238
+ throw new ShapeError(`Unknown model: ${model}`);
2239
+ }
2240
+ const inferred = [];
2241
+ for (const [fieldName, fieldMeta] of Object.entries(modelFields)) {
2242
+ if (fieldMeta.isRelation)
2243
+ continue;
2244
+ if (fieldMeta.isId || fieldMeta.isUnique) {
2245
+ inferred.push({
2246
+ selector: fieldName,
2247
+ fields: [fieldName]
2248
+ });
1942
2249
  }
1943
2250
  }
2251
+ return inferred;
2252
+ }
2253
+ function buildCursorSchema(model, cursorConfig) {
2254
+ const constraints = getUniqueConstraints(model);
2255
+ if (constraints.length === 0) {
2256
+ throw new ShapeError(
2257
+ `cursor on model "${model}" requires at least one unique constraint`
2258
+ );
2259
+ }
2260
+ const matching = constraints.find(
2261
+ (constraint) => cursorConfigMatchesConstraint(cursorConfig, constraint)
2262
+ );
2263
+ if (!matching) {
2264
+ throw new ShapeError(
2265
+ `cursor on model "${model}" must exactly match a unique selector: ${formatUniqueConstraints2(constraints)}`
2266
+ );
2267
+ }
1944
2268
  const fieldSchemas = {};
1945
- 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);
2269
+ if (matching.fields.length === 1) {
2270
+ fieldSchemas[matching.selector] = buildCursorFieldSchema(
2271
+ model,
2272
+ matching.fields[0]
2273
+ ).optional();
2274
+ } else {
2275
+ const nestedSchemas = {};
2276
+ for (const field of matching.fields) {
2277
+ nestedSchemas[field] = buildCursorFieldSchema(model, field);
2278
+ }
2279
+ fieldSchemas[matching.selector] = import_zod5.z.object(nestedSchemas).strict().optional();
1954
2280
  }
1955
- return import_zod5.z.object(fieldSchemas).strict().optional();
2281
+ return import_zod5.z.object(fieldSchemas).strict().refine(
2282
+ (v) => v[matching.selector] !== void 0,
2283
+ { message: `cursor must specify "${matching.selector}"` }
2284
+ ).optional();
1956
2285
  }
1957
2286
  function buildDistinctSchema(model, distinctConfig) {
1958
- if (distinctConfig.length === 0) {
1959
- throw new ShapeError("distinct must contain at least one field");
1960
- }
1961
2287
  const modelFields = typeMap[model];
1962
2288
  if (!modelFields)
1963
2289
  throw new ShapeError(`Unknown model: ${model}`);
2290
+ if (!Array.isArray(distinctConfig) || distinctConfig.length === 0) {
2291
+ throw new ShapeError(
2292
+ `distinct on model "${model}" must be a non-empty array of scalar fields`
2293
+ );
2294
+ }
2295
+ const allowedFields = /* @__PURE__ */ new Set();
1964
2296
  for (const fieldName of distinctConfig) {
1965
2297
  const fieldMeta = modelFields[fieldName];
1966
2298
  if (!fieldMeta)
1967
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in distinct`);
2299
+ throw new ShapeError(
2300
+ `Unknown field "${fieldName}" on model "${model}" in distinct`
2301
+ );
1968
2302
  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`);
2303
+ throw new ShapeError(
2304
+ `Relation field "${fieldName}" cannot be used in distinct`
2305
+ );
2306
+ allowedFields.add(fieldName);
1972
2307
  }
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();
2308
+ return import_zod5.z.union([
2309
+ import_zod5.z.enum([...allowedFields]),
2310
+ import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1)
2311
+ ]).optional();
1975
2312
  }
1976
2313
  function buildBySchema(model, byConfig) {
1977
- if (byConfig.length === 0) {
1978
- throw new ShapeError('groupBy "by" must contain at least one field');
1979
- }
1980
2314
  const modelFields = typeMap[model];
1981
2315
  if (!modelFields)
1982
2316
  throw new ShapeError(`Unknown model: ${model}`);
2317
+ if (!Array.isArray(byConfig) || byConfig.length === 0) {
2318
+ throw new ShapeError(
2319
+ `groupBy "by" on model "${model}" must be a non-empty array`
2320
+ );
2321
+ }
2322
+ const allowedFields = /* @__PURE__ */ new Set();
1983
2323
  for (const fieldName of byConfig) {
1984
2324
  const fieldMeta = modelFields[fieldName];
1985
2325
  if (!fieldMeta)
1986
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in by`);
2326
+ throw new ShapeError(
2327
+ `Unknown field "${fieldName}" on model "${model}" in groupBy by`
2328
+ );
1987
2329
  if (fieldMeta.isRelation)
1988
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in by`);
2330
+ throw new ShapeError(
2331
+ `Relation field "${fieldName}" cannot be used in groupBy by`
2332
+ );
2333
+ if (fieldMeta.isList)
2334
+ throw new ShapeError(
2335
+ `List field "${fieldName}" cannot be used in groupBy by`
2336
+ );
1989
2337
  if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
1990
- throw new ShapeError(`${fieldMeta.type} field "${fieldName}" cannot be used in by`);
2338
+ throw new ShapeError(
2339
+ `${fieldMeta.type} field "${fieldName}" cannot be used in groupBy by`
2340
+ );
1991
2341
  }
1992
- if (fieldMeta.isList)
1993
- throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
2342
+ allowedFields.add(fieldName);
1994
2343
  }
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))]);
2344
+ return import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1);
1997
2345
  }
1998
2346
  function buildHavingSchema(model, havingConfig) {
1999
2347
  const modelFields = typeMap[model];
@@ -2004,82 +2352,88 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2004
2352
  for (const fieldName of Object.keys(havingConfig)) {
2005
2353
  const fieldMeta = modelFields[fieldName];
2006
2354
  if (!fieldMeta)
2007
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in having`);
2355
+ throw new ShapeError(
2356
+ `Unknown field "${fieldName}" on model "${model}" in having`
2357
+ );
2008
2358
  if (fieldMeta.isRelation)
2009
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in having`);
2359
+ throw new ShapeError(
2360
+ `Relation field "${fieldName}" cannot be used in having`
2361
+ );
2010
2362
  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`);
2363
+ throw new ShapeError(
2364
+ `List field "${fieldName}" cannot be used in having`
2365
+ );
2366
+ if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
2367
+ throw new ShapeError(
2368
+ `${fieldMeta.type} field "${fieldName}" cannot be used in having`
2369
+ );
2015
2370
  }
2371
+ const allowedOps = getSupportedOperators(
2372
+ fieldMeta.type,
2373
+ fieldMeta.isList
2374
+ );
2016
2375
  const opSchemas = {};
2017
- const opKeys = [];
2018
- for (const op of ops) {
2019
- opSchemas[op] = createOperatorSchema(fieldMeta, op, enumMap, scalarBase).optional();
2020
- opKeys.push(op);
2376
+ for (const op of allowedOps) {
2377
+ opSchemas[op] = createOperatorSchema(
2378
+ fieldMeta,
2379
+ op,
2380
+ enumMap,
2381
+ scalarBase
2382
+ ).optional();
2021
2383
  }
2022
- if (fieldMeta.type === "String" && !fieldMeta.isList) {
2023
- opSchemas["mode"] = import_zod5.z.enum(["default", "insensitive"]).optional();
2384
+ if (fieldMeta.type === "String") {
2385
+ opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
2024
2386
  }
2387
+ const opKeys = Object.keys(opSchemas).filter((key) => key !== "mode");
2025
2388
  fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
2026
2389
  (v) => opKeys.some((k) => v[k] !== void 0),
2027
- { message: `At least one operator required for having field "${fieldName}"` }
2390
+ {
2391
+ message: `having field "${fieldName}" must specify at least one operator`
2392
+ }
2028
2393
  ).optional();
2029
2394
  }
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();
2395
+ const fieldKeys = Object.keys(fieldSchemas);
2396
+ return import_zod5.z.object(fieldSchemas).strict().refine(
2397
+ (v) => fieldKeys.some(
2398
+ (k) => v[k] !== void 0
2399
+ ),
2400
+ { message: "having must specify at least one field" }
2401
+ ).optional();
2046
2402
  }
2047
- function buildAggregateFieldSchema(model, opName, fieldConfig) {
2403
+ function buildAggregateFieldSchema(model, op, config) {
2048
2404
  const modelFields = typeMap[model];
2049
2405
  if (!modelFields)
2050
2406
  throw new ShapeError(`Unknown model: ${model}`);
2051
- requireConfigTrue(fieldConfig, `${opName} on model "${model}"`);
2052
- const isNumericOnly = opName === "_avg" || opName === "_sum";
2053
- const isComparableOnly = opName === "_min" || opName === "_max";
2407
+ requireConfigTrue(config, `${op} on model "${model}"`);
2408
+ const allowedTypes = op === "_avg" || op === "_sum" ? NUMERIC_TYPES : COMPARABLE_TYPES;
2054
2409
  const fieldSchemas = {};
2055
- for (const fieldName of Object.keys(fieldConfig)) {
2056
- if (fieldName === "_all" && opName === "_count") {
2057
- fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
2058
- continue;
2059
- }
2410
+ for (const fieldName of Object.keys(config)) {
2060
2411
  const fieldMeta = modelFields[fieldName];
2061
2412
  if (!fieldMeta)
2062
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in ${opName}`);
2413
+ throw new ShapeError(
2414
+ `Unknown field "${fieldName}" on model "${model}" in ${op}`
2415
+ );
2063
2416
  if (fieldMeta.isRelation)
2064
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in ${opName}`);
2417
+ throw new ShapeError(
2418
+ `Relation field "${fieldName}" cannot be used in ${op}`
2419
+ );
2065
2420
  if (fieldMeta.isList)
2066
- throw new ShapeError(`List field "${fieldName}" cannot be used in ${opName}`);
2067
- if (isNumericOnly && !NUMERIC_TYPES.has(fieldMeta.type)) {
2068
2421
  throw new ShapeError(
2069
- `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only numeric types (Int, Float, Decimal, BigInt) are supported.`
2422
+ `List field "${fieldName}" cannot be used in ${op}`
2070
2423
  );
2071
- }
2072
- if (isComparableOnly && !COMPARABLE_TYPES.has(fieldMeta.type)) {
2424
+ if (!allowedTypes.has(fieldMeta.type)) {
2073
2425
  throw new ShapeError(
2074
- `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only comparable types (Int, Float, Decimal, BigInt, String, DateTime) are supported.`
2426
+ `Field "${fieldName}" of type "${fieldMeta.type}" cannot be used in ${op}`
2075
2427
  );
2076
2428
  }
2077
2429
  fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
2078
2430
  }
2079
- const aggFieldKeys = Object.keys(fieldSchemas);
2431
+ const aggregateFieldKeys = Object.keys(fieldSchemas);
2080
2432
  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` }
2433
+ (v) => aggregateFieldKeys.some(
2434
+ (k) => v[k] !== void 0
2435
+ ),
2436
+ { message: `${op} must specify at least one field` }
2083
2437
  ).optional();
2084
2438
  }
2085
2439
  function buildCountFieldSchema(model, config, context) {
@@ -2095,15 +2449,21 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2095
2449
  if (fieldName !== "_all") {
2096
2450
  const fieldMeta = modelFields[fieldName];
2097
2451
  if (!fieldMeta)
2098
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in ${context}`);
2452
+ throw new ShapeError(
2453
+ `Unknown field "${fieldName}" on model "${model}" in ${context}`
2454
+ );
2099
2455
  if (fieldMeta.isRelation)
2100
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in ${context}`);
2456
+ throw new ShapeError(
2457
+ `Relation field "${fieldName}" cannot be used in ${context}`
2458
+ );
2101
2459
  }
2102
2460
  fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
2103
2461
  }
2104
2462
  const countFieldKeys = Object.keys(fieldSchemas);
2105
2463
  return import_zod5.z.object(fieldSchemas).strict().refine(
2106
- (v) => countFieldKeys.some((k) => v[k] !== void 0),
2464
+ (v) => countFieldKeys.some(
2465
+ (k) => v[k] !== void 0
2466
+ ),
2107
2467
  { message: `${context} must specify at least one field` }
2108
2468
  ).optional();
2109
2469
  }
@@ -2115,19 +2475,25 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2115
2475
  const fieldSchemas = {};
2116
2476
  for (const fieldName of Object.keys(selectConfig)) {
2117
2477
  if (fieldName === "_all") {
2118
- fieldSchemas["_all"] = import_zod5.z.literal(true).optional();
2478
+ fieldSchemas._all = import_zod5.z.literal(true).optional();
2119
2479
  continue;
2120
2480
  }
2121
2481
  const fieldMeta = modelFields[fieldName];
2122
2482
  if (!fieldMeta)
2123
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in count select`);
2483
+ throw new ShapeError(
2484
+ `Unknown field "${fieldName}" on model "${model}" in count select`
2485
+ );
2124
2486
  if (fieldMeta.isRelation)
2125
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in count select`);
2487
+ throw new ShapeError(
2488
+ `Relation field "${fieldName}" cannot be used in count select`
2489
+ );
2126
2490
  fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
2127
2491
  }
2128
2492
  const countSelectKeys = Object.keys(fieldSchemas);
2129
2493
  return import_zod5.z.object(fieldSchemas).strict().refine(
2130
- (v) => countSelectKeys.some((k) => v[k] !== void 0),
2494
+ (v) => countSelectKeys.some(
2495
+ (k) => v[k] !== void 0
2496
+ ),
2131
2497
  { message: "count select must specify at least one field" }
2132
2498
  ).optional();
2133
2499
  }
@@ -2536,7 +2902,12 @@ var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
2536
2902
  "findUniqueOrThrow"
2537
2903
  ]);
2538
2904
  function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2539
- const whereBuilder = createWhereBuilder(typeMap, enumMap, scalarBase);
2905
+ const whereBuilder = createWhereBuilder(
2906
+ typeMap,
2907
+ enumMap,
2908
+ scalarBase,
2909
+ uniqueMap
2910
+ );
2540
2911
  const argsBuilder = createArgsBuilder(
2541
2912
  typeMap,
2542
2913
  enumMap,
@@ -2558,24 +2929,28 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2558
2929
  function validateShapeArgs(method, shape) {
2559
2930
  const allowed = METHOD_ALLOWED_ARGS[method];
2560
2931
  for (const key of Object.keys(shape)) {
2561
- if (!SHAPE_CONFIG_KEYS.has(key))
2932
+ if (!SHAPE_CONFIG_KEYS.has(key)) {
2562
2933
  throw new ShapeError(`Unknown shape config key "${key}"`);
2563
- if (!allowed.has(key))
2934
+ }
2935
+ if (!allowed.has(key)) {
2564
2936
  throw new ShapeError(`Arg "${key}" not allowed for method "${method}"`);
2937
+ }
2565
2938
  }
2566
2939
  if (UNIQUE_WHERE_METHODS.has(method) && !shape.where) {
2567
2940
  throw new ShapeError(`${method} shape must define "where"`);
2568
2941
  }
2569
- if (method === "groupBy" && !shape.by)
2942
+ if (method === "groupBy" && !shape.by) {
2570
2943
  throw new ShapeError('groupBy shape must define "by"');
2944
+ }
2571
2945
  if (method === "groupBy" && (shape.include || shape.select)) {
2572
2946
  throw new ShapeError('groupBy does not support "include" or "select"');
2573
2947
  }
2574
2948
  if (method === "aggregate" && (shape.include || shape.select)) {
2575
2949
  throw new ShapeError('aggregate does not support "include" or "select"');
2576
2950
  }
2577
- if (method === "count" && shape.include)
2951
+ if (method === "count" && shape.include) {
2578
2952
  throw new ShapeError('count does not support "include"');
2953
+ }
2579
2954
  if (method === "groupBy" && shape.orderBy && shape.orderBy !== true) {
2580
2955
  const bySet = new Set(shape.by);
2581
2956
  for (const fieldName of Object.keys(shape.orderBy)) {
@@ -2630,30 +3005,28 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2630
3005
  let forcedIncludeCountWhere = {};
2631
3006
  let forcedSelectCountWhere = {};
2632
3007
  if (shape.where) {
2633
- const { schema, forced, forcedOnlyKeys } = whereBuilder.buildWhereSchema(
2634
- model,
2635
- shape.where
2636
- );
2637
- if (schema)
2638
- schemaFields["where"] = schema;
2639
- forcedWhere = forced;
2640
- forcedOnlyWhereKeys = forcedOnlyKeys;
3008
+ const builtWhere = UNIQUE_WHERE_METHODS.has(method) ? whereBuilder.buildUniqueWhereSchema(model, shape.where) : whereBuilder.buildWhereSchema(model, shape.where);
3009
+ if (builtWhere.schema) {
3010
+ schemaFields.where = builtWhere.schema;
3011
+ }
3012
+ forcedWhere = builtWhere.forced;
3013
+ forcedOnlyWhereKeys = builtWhere.forcedOnlyKeys;
2641
3014
  }
2642
3015
  if (shape.include) {
2643
3016
  const result = projectionBuilder.buildIncludeSchema(model, shape.include);
2644
- schemaFields["include"] = result.schema;
3017
+ schemaFields.include = result.schema;
2645
3018
  forcedIncludeTree = result.forcedTree;
2646
3019
  forcedIncludeCountWhere = result.forcedCountWhere;
2647
3020
  }
2648
3021
  if (shape.select) {
2649
3022
  if (method === "count") {
2650
- schemaFields["select"] = argsBuilder.buildCountSelectSchema(
3023
+ schemaFields.select = argsBuilder.buildCountSelectSchema(
2651
3024
  model,
2652
3025
  shape.select
2653
3026
  );
2654
3027
  } else {
2655
3028
  const result = projectionBuilder.buildSelectSchema(model, shape.select);
2656
- schemaFields["select"] = result.schema;
3029
+ schemaFields.select = result.schema;
2657
3030
  forcedSelectTree = result.forcedTree;
2658
3031
  forcedSelectCountWhere = result.forcedCountWhere;
2659
3032
  }
@@ -2667,7 +3040,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2667
3040
  for (const field of shape.by) {
2668
3041
  groupByOrderFields[field] = sortEnum.optional();
2669
3042
  }
2670
- groupByOrderFields["_count"] = sortEnum.optional();
3043
+ groupByOrderFields._count = sortEnum.optional();
2671
3044
  const fieldKeys = Object.keys(groupByOrderFields);
2672
3045
  const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
2673
3046
  (v) => fieldKeys.some(
@@ -2675,13 +3048,16 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2675
3048
  ),
2676
3049
  { message: "orderBy must specify at least one field" }
2677
3050
  );
2678
- schemaFields["orderBy"] = import_zod7.z.union([singleSchema, import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))]).optional();
3051
+ schemaFields.orderBy = import_zod7.z.union([
3052
+ singleSchema,
3053
+ import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
3054
+ ]).optional();
2679
3055
  } else {
2680
3056
  const groupByOrderFields = {};
2681
3057
  for (const [fieldName, config] of Object.entries(shape.orderBy)) {
2682
3058
  if (fieldName === "_count") {
2683
3059
  if (config === true) {
2684
- groupByOrderFields["_count"] = sortEnum.optional();
3060
+ groupByOrderFields._count = sortEnum.optional();
2685
3061
  } else if (typeof config === "object" && config !== null) {
2686
3062
  const countFields = {};
2687
3063
  for (const countField of Object.keys(config)) {
@@ -2693,7 +3069,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2693
3069
  countFields[countField] = sortEnum.optional();
2694
3070
  }
2695
3071
  const countKeys = Object.keys(countFields);
2696
- groupByOrderFields["_count"] = import_zod7.z.object(countFields).strict().refine(
3072
+ groupByOrderFields._count = import_zod7.z.object(countFields).strict().refine(
2697
3073
  (v) => countKeys.some(
2698
3074
  (k) => v[k] !== void 0
2699
3075
  ),
@@ -2718,70 +3094,83 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2718
3094
  ),
2719
3095
  { message: "orderBy must specify at least one field" }
2720
3096
  );
2721
- schemaFields["orderBy"] = import_zod7.z.union([singleSchema, import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))]).optional();
3097
+ schemaFields.orderBy = import_zod7.z.union([
3098
+ singleSchema,
3099
+ import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
3100
+ ]).optional();
2722
3101
  }
2723
3102
  } else {
2724
- schemaFields["orderBy"] = argsBuilder.buildOrderBySchema(
3103
+ schemaFields.orderBy = argsBuilder.buildOrderBySchema(
2725
3104
  model,
2726
3105
  shape.orderBy
2727
3106
  );
2728
3107
  }
2729
3108
  }
2730
- if (shape.cursor)
2731
- schemaFields["cursor"] = argsBuilder.buildCursorSchema(
3109
+ if (shape.cursor) {
3110
+ schemaFields.cursor = argsBuilder.buildCursorSchema(
2732
3111
  model,
2733
3112
  shape.cursor
2734
3113
  );
2735
- if (shape.take)
2736
- schemaFields["take"] = argsBuilder.buildTakeSchema(shape.take);
3114
+ }
3115
+ if (shape.take) {
3116
+ schemaFields.take = argsBuilder.buildTakeSchema(shape.take);
3117
+ }
2737
3118
  if (shape.skip !== void 0) {
2738
3119
  if (shape.skip !== true) {
2739
3120
  throw new ShapeError('Shape config "skip" must be true');
2740
3121
  }
2741
- schemaFields["skip"] = import_zod7.z.number().int().min(0).optional();
3122
+ schemaFields.skip = import_zod7.z.number().int().min(0).optional();
2742
3123
  }
2743
- if (shape.distinct)
2744
- schemaFields["distinct"] = argsBuilder.buildDistinctSchema(
3124
+ if (shape.distinct) {
3125
+ schemaFields.distinct = argsBuilder.buildDistinctSchema(
2745
3126
  model,
2746
3127
  shape.distinct
2747
3128
  );
2748
- if (shape._count)
2749
- schemaFields["_count"] = argsBuilder.buildCountFieldSchema(
3129
+ }
3130
+ if (shape._count) {
3131
+ schemaFields._count = argsBuilder.buildCountFieldSchema(
2750
3132
  model,
2751
3133
  shape._count,
2752
3134
  "_count"
2753
3135
  );
2754
- if (shape._avg)
2755
- schemaFields["_avg"] = argsBuilder.buildAggregateFieldSchema(
3136
+ }
3137
+ if (shape._avg) {
3138
+ schemaFields._avg = argsBuilder.buildAggregateFieldSchema(
2756
3139
  model,
2757
3140
  "_avg",
2758
3141
  shape._avg
2759
3142
  );
2760
- if (shape._sum)
2761
- schemaFields["_sum"] = argsBuilder.buildAggregateFieldSchema(
3143
+ }
3144
+ if (shape._sum) {
3145
+ schemaFields._sum = argsBuilder.buildAggregateFieldSchema(
2762
3146
  model,
2763
3147
  "_sum",
2764
3148
  shape._sum
2765
3149
  );
2766
- if (shape._min)
2767
- schemaFields["_min"] = argsBuilder.buildAggregateFieldSchema(
3150
+ }
3151
+ if (shape._min) {
3152
+ schemaFields._min = argsBuilder.buildAggregateFieldSchema(
2768
3153
  model,
2769
3154
  "_min",
2770
3155
  shape._min
2771
3156
  );
2772
- if (shape._max)
2773
- schemaFields["_max"] = argsBuilder.buildAggregateFieldSchema(
3157
+ }
3158
+ if (shape._max) {
3159
+ schemaFields._max = argsBuilder.buildAggregateFieldSchema(
2774
3160
  model,
2775
3161
  "_max",
2776
3162
  shape._max
2777
3163
  );
2778
- if (shape.by)
2779
- schemaFields["by"] = argsBuilder.buildBySchema(model, shape.by);
2780
- if (shape.having)
2781
- schemaFields["having"] = argsBuilder.buildHavingSchema(
3164
+ }
3165
+ if (shape.by) {
3166
+ schemaFields.by = argsBuilder.buildBySchema(model, shape.by);
3167
+ }
3168
+ if (shape.having) {
3169
+ schemaFields.having = argsBuilder.buildHavingSchema(
2782
3170
  model,
2783
3171
  shape.having
2784
3172
  );
3173
+ }
2785
3174
  return {
2786
3175
  zodSchema: import_zod7.z.object(schemaFields).strict(),
2787
3176
  forcedWhere,
@@ -2799,7 +3188,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2799
3188
  return { key: matched, shape: shapes[matched] };
2800
3189
  }
2801
3190
  function resolveDefaultShape(config, model, method, normalizedBody, opts, builtCache, isUnique) {
2802
- const shapeOrFn = config["default"];
3191
+ const shapeOrFn = config.default;
2803
3192
  let built;
2804
3193
  if (typeof shapeOrFn === "function") {
2805
3194
  const resolved = resolveAndValidateShape(shapeOrFn, opts?.ctx);
@@ -2853,8 +3242,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2853
3242
  built = builtCache.get("_default");
2854
3243
  }
2855
3244
  } else {
2856
- if (!isPlainObject(normalizedBody))
3245
+ if (!isPlainObject(normalizedBody)) {
2857
3246
  throw new ShapeError("Request body must be an object");
3247
+ }
2858
3248
  if ("caller" in normalizedBody) {
2859
3249
  throw new CallerError(
2860
3250
  "Pass caller via opts.caller, not in the request body."
@@ -4184,8 +4574,9 @@ function buildDefaultSelectInput(config) {
4184
4574
  const nested = {};
4185
4575
  if (value.select)
4186
4576
  nested.select = buildDefaultSelectInput(value.select);
4187
- if (value.include)
4577
+ if (value.include) {
4188
4578
  nested.include = buildDefaultIncludeInput(value.include);
4579
+ }
4189
4580
  result[key] = Object.keys(nested).length > 0 ? nested : true;
4190
4581
  }
4191
4582
  }
@@ -4204,8 +4595,9 @@ function buildDefaultIncludeInput(config) {
4204
4595
  result[key] = true;
4205
4596
  } else {
4206
4597
  const nested = {};
4207
- if (value.include)
4598
+ if (value.include) {
4208
4599
  nested.include = buildDefaultIncludeInput(value.include);
4600
+ }
4209
4601
  if (value.select)
4210
4602
  nested.select = buildDefaultSelectInput(value.select);
4211
4603
  result[key] = Object.keys(nested).length > 0 ? nested : true;
@@ -4216,8 +4608,9 @@ function buildDefaultIncludeInput(config) {
4216
4608
  function buildDefaultCountInput(config) {
4217
4609
  if (config === true)
4218
4610
  return true;
4219
- if (!isPlainObject(config) || !config.select || !isPlainObject(config.select))
4611
+ if (!isPlainObject(config) || !config.select || !isPlainObject(config.select)) {
4220
4612
  return true;
4613
+ }
4221
4614
  const selectObj = config.select;
4222
4615
  const result = {};
4223
4616
  for (const key of Object.keys(selectObj)) {
@@ -4299,8 +4692,9 @@ function checkIncludeForClientArgs(config) {
4299
4692
  continue;
4300
4693
  if (value.orderBy || value.cursor || value.take || value.skip)
4301
4694
  return true;
4302
- if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where))
4695
+ if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where)) {
4303
4696
  return true;
4697
+ }
4304
4698
  if (value.include && checkIncludeForClientArgs(value.include))
4305
4699
  return true;
4306
4700
  if (value.select && checkSelectForClientArgs(value.select))
@@ -4327,8 +4721,9 @@ function checkSelectForClientArgs(config) {
4327
4721
  continue;
4328
4722
  if (value.orderBy || value.cursor || value.take || value.skip)
4329
4723
  return true;
4330
- if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where))
4724
+ if (value.where && isPlainObject(value.where) && hasClientControlledValues(value.where)) {
4331
4725
  return true;
4726
+ }
4332
4727
  if (value.select && checkSelectForClientArgs(value.select))
4333
4728
  return true;
4334
4729
  if (value.include && checkIncludeForClientArgs(value.include))
@@ -4389,36 +4784,7 @@ function createModelGuardExtension(config) {
4389
4784
  validateUniqueEquality(modelName, shape.where, method, uniqueMap, typeMap);
4390
4785
  }
4391
4786
  function validateUniqueWhereShapeConfig(modelName, where, method) {
4392
- 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
- }
4787
+ validateUniqueEquality(modelName, where, method, uniqueMap, typeMap);
4422
4788
  }
4423
4789
  function createGuardedMethods(modelName, modelDelegate, input, explicitCaller) {
4424
4790
  function callDelegate(method, args) {
@@ -4692,10 +5058,10 @@ function createModelGuardExtension(config) {
4692
5058
  `Invalid "where" on model "${modelName}": unique where must be a plain object`
4693
5059
  );
4694
5060
  }
4695
- const sanitized = { ...bodyWhere };
4696
- for (const key of built.forcedOnlyKeys) {
4697
- delete sanitized[key];
4698
- }
5061
+ const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(
5062
+ bodyWhere,
5063
+ built.forced
5064
+ ) : { ...bodyWhere };
4699
5065
  try {
4700
5066
  result = built.schema.parse(sanitized);
4701
5067
  } catch (err) {
@@ -4708,16 +5074,23 @@ function createModelGuardExtension(config) {
4708
5074
  }
4709
5075
  } else if (bodyWhere !== void 0 && bodyWhere !== null) {
4710
5076
  if (isPlainObject(bodyWhere)) {
4711
- const hasOnlyForcedKeys = built.forcedOnlyKeys.size > 0 && Object.keys(bodyWhere).every((k) => built.forcedOnlyKeys.has(k));
4712
- if (!hasOnlyForcedKeys && Object.keys(bodyWhere).length > 0) {
5077
+ const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(
5078
+ bodyWhere,
5079
+ built.forced
5080
+ ) : { ...bodyWhere };
5081
+ if (Object.keys(sanitized).length > 0) {
4713
5082
  throw new ShapeError(
4714
5083
  `Unique where on model "${modelName}" contains only forced values. Client where input is not accepted.`
4715
5084
  );
4716
5085
  }
5086
+ } else {
5087
+ throw new ShapeError(
5088
+ `Invalid "where" on model "${modelName}": unique where must be a plain object`
5089
+ );
4717
5090
  }
4718
5091
  }
4719
- for (const [key, value] of Object.entries(built.forced)) {
4720
- result[key] = value;
5092
+ if (hasWhereForced(built.forced)) {
5093
+ result = mergeUniqueWhereForced(result, built.forced);
4721
5094
  }
4722
5095
  return result;
4723
5096
  }
@@ -4730,7 +5103,9 @@ function createModelGuardExtension(config) {
4730
5103
  );
4731
5104
  if (Object.keys(where).length === 0) {
4732
5105
  const constraints = uniqueMap[modelName];
4733
- const constraintDesc = constraints ? constraints.map((c) => `(${c.join(", ")})`).join(" | ") : "unknown";
5106
+ const constraintDesc = constraints ? constraints.map(
5107
+ (constraint) => constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`
5108
+ ).join(" | ") : "unknown";
4734
5109
  const expectedFields = shape.where ? Object.keys(shape.where).join(", ") : "none defined";
4735
5110
  throw new ShapeError(
4736
5111
  `${method} on model "${modelName}" requires a unique where condition. Unique constraints: ${constraintDesc}. Shape allows: ${expectedFields}`
@@ -4806,8 +5181,9 @@ function createModelGuardExtension(config) {
4806
5181
  return (body) => {
4807
5182
  const caller = resolveCaller();
4808
5183
  const resolved = resolveShape(input, body, contextFn, caller);
4809
- if (!resolved.shape.data)
5184
+ if (!resolved.shape.data) {
4810
5185
  throw new ShapeError(`Guard shape requires "data" for ${method}`);
5186
+ }
4811
5187
  validateMutationShapeKeys(
4812
5188
  resolved.shape,
4813
5189
  allowedShapeKeys,
@@ -4838,10 +5214,12 @@ function createModelGuardExtension(config) {
4838
5214
  );
4839
5215
  args = { data };
4840
5216
  } else {
4841
- if (!Array.isArray(resolved.body.data))
5217
+ if (!Array.isArray(resolved.body.data)) {
4842
5218
  throw new ShapeError(`${method} expects data to be an array`);
4843
- if (resolved.body.data.length === 0)
5219
+ }
5220
+ if (resolved.body.data.length === 0) {
4844
5221
  throw new ShapeError(`${method} received empty data array`);
5222
+ }
4845
5223
  const data = resolved.body.data.map(
4846
5224
  (item) => validateAndMergeData(item, dataSchema, method, modelName)
4847
5225
  );
@@ -4875,8 +5253,9 @@ function createModelGuardExtension(config) {
4875
5253
  return (body) => {
4876
5254
  const caller = resolveCaller();
4877
5255
  const resolved = resolveShape(input, body, contextFn, caller);
4878
- if (!resolved.shape.data)
5256
+ if (!resolved.shape.data) {
4879
5257
  throw new ShapeError(`Guard shape requires "data" for ${method}`);
5258
+ }
4880
5259
  validateMutationShapeKeys(
4881
5260
  resolved.shape,
4882
5261
  allowedShapeKeys,
@@ -4955,8 +5334,9 @@ function createModelGuardExtension(config) {
4955
5334
  return (body) => {
4956
5335
  const caller = resolveCaller();
4957
5336
  const resolved = resolveShape(input, body, contextFn, caller);
4958
- if (resolved.shape.data)
5337
+ if (resolved.shape.data) {
4959
5338
  throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
5339
+ }
4960
5340
  validateMutationShapeKeys(
4961
5341
  resolved.shape,
4962
5342
  allowedShapeKeys,