prisma-guard 1.27.1 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -33
- package/dist/generator/index.js +244 -209
- package/dist/generator/index.js.map +1 -1
- package/dist/runtime/index.cjs +1655 -1660
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +68 -35
- package/dist/runtime/index.d.ts +68 -35
- package/dist/runtime/index.js +1655 -1660
- package/dist/runtime/index.js.map +1 -1
- package/package.json +3 -2
package/dist/runtime/index.cjs
CHANGED
|
@@ -29,9 +29,6 @@ __export(runtime_exports, {
|
|
|
29
29
|
});
|
|
30
30
|
module.exports = __toCommonJS(runtime_exports);
|
|
31
31
|
|
|
32
|
-
// src/runtime/guard.ts
|
|
33
|
-
var import_zod10 = require("zod");
|
|
34
|
-
|
|
35
32
|
// src/shared/errors.ts
|
|
36
33
|
var PolicyError = class extends Error {
|
|
37
34
|
status = 403;
|
|
@@ -61,10 +58,16 @@ function formatIssue(issue) {
|
|
|
61
58
|
const path = issue.path.length > 0 ? `${issue.path.join(".")}: ` : "";
|
|
62
59
|
const code = issue.code;
|
|
63
60
|
if (code === "invalid_union") {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
const raw = issue;
|
|
62
|
+
let branchIssues = null;
|
|
63
|
+
if (Array.isArray(raw.errors) && raw.errors.length > 0) {
|
|
64
|
+
branchIssues = raw.errors;
|
|
65
|
+
} else if (Array.isArray(raw.unionErrors) && raw.unionErrors.length > 0) {
|
|
66
|
+
branchIssues = raw.unionErrors.map((ue) => ue.issues);
|
|
67
|
+
}
|
|
68
|
+
if (branchIssues) {
|
|
69
|
+
const branches = branchIssues.map((issues, i) => {
|
|
70
|
+
const nested = issues.map(formatIssue).join(", ");
|
|
68
71
|
return `branch ${i + 1}: [${nested}]`;
|
|
69
72
|
}).join(" | ");
|
|
70
73
|
return `${path}No matching variant (${branches})`;
|
|
@@ -83,6 +86,9 @@ function formatIssue(issue) {
|
|
|
83
86
|
if (expected && received) {
|
|
84
87
|
return `${path}Expected ${expected}, received ${received}`;
|
|
85
88
|
}
|
|
89
|
+
if (expected) {
|
|
90
|
+
return `${path}Expected ${expected}`;
|
|
91
|
+
}
|
|
86
92
|
}
|
|
87
93
|
if (code === "invalid_enum_value") {
|
|
88
94
|
const options = issue.options;
|
|
@@ -92,28 +98,28 @@ function formatIssue(issue) {
|
|
|
92
98
|
}
|
|
93
99
|
if (code === "too_small") {
|
|
94
100
|
const minimum = issue.minimum;
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
101
|
+
const origin = issue.origin ?? issue.type;
|
|
102
|
+
if (origin === "string" && minimum !== void 0) {
|
|
97
103
|
return `${path}String must contain at least ${minimum} character(s)`;
|
|
98
104
|
}
|
|
99
|
-
if (
|
|
105
|
+
if (origin === "array" && minimum !== void 0) {
|
|
100
106
|
return `${path}Array must contain at least ${minimum} element(s)`;
|
|
101
107
|
}
|
|
102
|
-
if (
|
|
108
|
+
if (origin === "number" && minimum !== void 0) {
|
|
103
109
|
return `${path}Number must be >= ${minimum}`;
|
|
104
110
|
}
|
|
105
111
|
return `${path}${issue.message}`;
|
|
106
112
|
}
|
|
107
113
|
if (code === "too_big") {
|
|
108
114
|
const maximum = issue.maximum;
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
115
|
+
const origin = issue.origin ?? issue.type;
|
|
116
|
+
if (origin === "string" && maximum !== void 0) {
|
|
111
117
|
return `${path}String must contain at most ${maximum} character(s)`;
|
|
112
118
|
}
|
|
113
|
-
if (
|
|
119
|
+
if (origin === "array" && maximum !== void 0) {
|
|
114
120
|
return `${path}Array must contain at most ${maximum} element(s)`;
|
|
115
121
|
}
|
|
116
|
-
if (
|
|
122
|
+
if (origin === "number" && maximum !== void 0) {
|
|
117
123
|
return `${path}Number must be <= ${maximum}`;
|
|
118
124
|
}
|
|
119
125
|
return `${path}${issue.message}`;
|
|
@@ -135,18 +141,42 @@ function formatIssue(issue) {
|
|
|
135
141
|
function formatZodError(err) {
|
|
136
142
|
return err.issues.map(formatIssue).join("; ");
|
|
137
143
|
}
|
|
138
|
-
function
|
|
144
|
+
function isZodErrorLike(err) {
|
|
145
|
+
return !!err && typeof err === "object" && "issues" in err;
|
|
146
|
+
}
|
|
147
|
+
function wrapZod(err, context) {
|
|
139
148
|
if (err instanceof ShapeError) {
|
|
140
149
|
throw new ShapeError(`${context}: ${err.message}`, { cause: err });
|
|
141
150
|
}
|
|
142
|
-
if (err
|
|
151
|
+
if (isZodErrorLike(err)) {
|
|
143
152
|
throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
|
|
144
153
|
}
|
|
145
154
|
throw err;
|
|
146
155
|
}
|
|
156
|
+
function wrapParseError(err, context) {
|
|
157
|
+
return wrapZod(err, context);
|
|
158
|
+
}
|
|
159
|
+
function toShapeError(err, prefix = "Validation failed") {
|
|
160
|
+
if (isZodErrorLike(err)) {
|
|
161
|
+
return new ShapeError(`${prefix}: ${formatZodError(err)}`, { cause: err });
|
|
162
|
+
}
|
|
163
|
+
return err;
|
|
164
|
+
}
|
|
147
165
|
|
|
148
166
|
// src/shared/scalar-base.ts
|
|
149
167
|
var import_zod = require("zod");
|
|
168
|
+
function isPrismaNullSentinel(value) {
|
|
169
|
+
if (value === null || typeof value !== "object")
|
|
170
|
+
return false;
|
|
171
|
+
const tag = value._tag;
|
|
172
|
+
if (tag === "DbNull" || tag === "JsonNull" || tag === "AnyNull")
|
|
173
|
+
return true;
|
|
174
|
+
const constructorName = value.constructor?.name;
|
|
175
|
+
if (constructorName === "DbNull" || constructorName === "JsonNull" || constructorName === "AnyNull") {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
150
180
|
function isJsonSafe(value) {
|
|
151
181
|
const stack = [{ tag: "visit", value }];
|
|
152
182
|
const ancestors = /* @__PURE__ */ new Set();
|
|
@@ -161,6 +191,8 @@ function isJsonSafe(value) {
|
|
|
161
191
|
return false;
|
|
162
192
|
if (current === null)
|
|
163
193
|
continue;
|
|
194
|
+
if (isPrismaNullSentinel(current))
|
|
195
|
+
continue;
|
|
164
196
|
switch (typeof current) {
|
|
165
197
|
case "string":
|
|
166
198
|
case "boolean":
|
|
@@ -245,8 +277,8 @@ function wrapWithInputCoercion(fieldType, isList, schema) {
|
|
|
245
277
|
break;
|
|
246
278
|
case "Int":
|
|
247
279
|
itemCoercion = import_zod.z.union([
|
|
248
|
-
import_zod.z.number().
|
|
249
|
-
import_zod.z.string().regex(/^-?\d
|
|
280
|
+
import_zod.z.number().int(),
|
|
281
|
+
import_zod.z.string().regex(/^-?\d+$/).transform((v) => Number(v))
|
|
250
282
|
]);
|
|
251
283
|
break;
|
|
252
284
|
case "Float":
|
|
@@ -263,10 +295,10 @@ function wrapWithInputCoercion(fieldType, isList, schema) {
|
|
|
263
295
|
}
|
|
264
296
|
|
|
265
297
|
// src/runtime/schema-builder.ts
|
|
266
|
-
var
|
|
298
|
+
var import_zod4 = require("zod");
|
|
267
299
|
|
|
268
300
|
// src/runtime/zod-type-map.ts
|
|
269
|
-
var
|
|
301
|
+
var import_zod3 = require("zod");
|
|
270
302
|
|
|
271
303
|
// src/shared/utils.ts
|
|
272
304
|
function isPlainObject(v) {
|
|
@@ -295,7 +327,7 @@ function coerceToArray(value) {
|
|
|
295
327
|
const keys = Object.keys(value);
|
|
296
328
|
if (keys.length === 0)
|
|
297
329
|
return value;
|
|
298
|
-
const allNumeric = keys.every((k) => /^\d+$/.test(k));
|
|
330
|
+
const allNumeric = keys.every((k) => /^\d+$/.test(k) && String(Number(k)) === k);
|
|
299
331
|
if (!allNumeric)
|
|
300
332
|
return value;
|
|
301
333
|
const indices = keys.map(Number).sort((a, b) => a - b);
|
|
@@ -311,6 +343,48 @@ function coerceToArray(value) {
|
|
|
311
343
|
return result;
|
|
312
344
|
}
|
|
313
345
|
|
|
346
|
+
// src/shared/zod-helpers.ts
|
|
347
|
+
var import_zod2 = require("zod");
|
|
348
|
+
function strictObjectRequiringOne(shape, message) {
|
|
349
|
+
const keys = Object.keys(shape);
|
|
350
|
+
return import_zod2.z.object(shape).strict().refine(
|
|
351
|
+
(v) => keys.some((k) => v[k] !== void 0),
|
|
352
|
+
{ message }
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
function singleOrArraySchema(single) {
|
|
356
|
+
return import_zod2.z.union([
|
|
357
|
+
single,
|
|
358
|
+
import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(single).min(1))
|
|
359
|
+
]);
|
|
360
|
+
}
|
|
361
|
+
function optionalOneOrMany(single) {
|
|
362
|
+
return import_zod2.z.union([single, import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(single))]).optional();
|
|
363
|
+
}
|
|
364
|
+
function wrapRelationOp(isList, single) {
|
|
365
|
+
if (!isList)
|
|
366
|
+
return single.optional();
|
|
367
|
+
return optionalOneOrMany(single);
|
|
368
|
+
}
|
|
369
|
+
function buildLiteralTrueSchema(fieldNames, message, validate) {
|
|
370
|
+
const fieldSchemas = {};
|
|
371
|
+
for (const fieldName of fieldNames) {
|
|
372
|
+
if (validate)
|
|
373
|
+
validate(fieldName);
|
|
374
|
+
fieldSchemas[fieldName] = import_zod2.z.literal(true).optional();
|
|
375
|
+
}
|
|
376
|
+
return strictObjectRequiringOne(fieldSchemas, message).optional();
|
|
377
|
+
}
|
|
378
|
+
function requireConfigTrue(config, context) {
|
|
379
|
+
for (const [key, value] of Object.entries(config)) {
|
|
380
|
+
if (value !== true) {
|
|
381
|
+
throw new ShapeError(
|
|
382
|
+
`Config value for "${key}" in ${context} must be true, got ${typeof value}`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
314
388
|
// src/runtime/zod-type-map.ts
|
|
315
389
|
var SCALAR_OPERATORS = {
|
|
316
390
|
String: /* @__PURE__ */ new Set([
|
|
@@ -398,13 +472,13 @@ function getSupportedOperators(input, isList = false, isEnum = false) {
|
|
|
398
472
|
function createBaseType(fieldMeta, enumMap, scalarBase) {
|
|
399
473
|
let base;
|
|
400
474
|
if (fieldMeta.isUnsupported) {
|
|
401
|
-
base =
|
|
475
|
+
base = import_zod3.z.unknown();
|
|
402
476
|
} else if (fieldMeta.isEnum) {
|
|
403
477
|
const values = enumMap[fieldMeta.type];
|
|
404
478
|
if (!values || values.length === 0) {
|
|
405
479
|
throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
|
|
406
480
|
}
|
|
407
|
-
base =
|
|
481
|
+
base = import_zod3.z.enum(values);
|
|
408
482
|
} else {
|
|
409
483
|
const factory = scalarBase[fieldMeta.type];
|
|
410
484
|
if (!factory) {
|
|
@@ -413,7 +487,7 @@ function createBaseType(fieldMeta, enumMap, scalarBase) {
|
|
|
413
487
|
base = factory();
|
|
414
488
|
}
|
|
415
489
|
if (fieldMeta.isList) {
|
|
416
|
-
base =
|
|
490
|
+
base = import_zod3.z.array(base);
|
|
417
491
|
}
|
|
418
492
|
return base;
|
|
419
493
|
}
|
|
@@ -424,35 +498,38 @@ function createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase
|
|
|
424
498
|
);
|
|
425
499
|
}
|
|
426
500
|
if (operator === "isEmpty") {
|
|
427
|
-
return
|
|
501
|
+
return import_zod3.z.boolean();
|
|
428
502
|
}
|
|
429
503
|
const itemMeta = { ...fieldMeta, isList: false };
|
|
430
504
|
const itemBase = createBaseType(itemMeta, enumMap, scalarBase);
|
|
431
505
|
if (operator === "has") {
|
|
432
|
-
return !fieldMeta.isRequired ?
|
|
506
|
+
return !fieldMeta.isRequired ? import_zod3.z.union([itemBase, import_zod3.z.null()]) : itemBase;
|
|
433
507
|
}
|
|
434
508
|
if (operator === "equals") {
|
|
435
|
-
const arrSchema =
|
|
436
|
-
return fieldMeta.isRequired ?
|
|
509
|
+
const arrSchema = import_zod3.z.array(itemBase);
|
|
510
|
+
return fieldMeta.isRequired ? import_zod3.z.preprocess(coerceToArray, arrSchema) : import_zod3.z.union([import_zod3.z.preprocess(coerceToArray, arrSchema), import_zod3.z.null()]);
|
|
437
511
|
}
|
|
438
|
-
return
|
|
512
|
+
return import_zod3.z.preprocess(coerceToArray, import_zod3.z.array(itemBase));
|
|
439
513
|
}
|
|
440
514
|
function createJsonOperatorSchema(fieldMeta, operator) {
|
|
441
|
-
const jsonValue =
|
|
515
|
+
const jsonValue = import_zod3.z.unknown();
|
|
442
516
|
if (operator === "equals") {
|
|
443
|
-
return !fieldMeta.isRequired ?
|
|
517
|
+
return !fieldMeta.isRequired ? import_zod3.z.union([jsonValue, import_zod3.z.null()]) : jsonValue;
|
|
444
518
|
}
|
|
445
519
|
if (operator === "path") {
|
|
446
|
-
return
|
|
520
|
+
return import_zod3.z.preprocess(coerceToArray, import_zod3.z.array(import_zod3.z.string()).min(1));
|
|
447
521
|
}
|
|
448
522
|
if (JSON_STRING_OPERATORS.has(operator)) {
|
|
449
|
-
return
|
|
523
|
+
return import_zod3.z.string();
|
|
450
524
|
}
|
|
451
525
|
if (JSON_ARRAY_OPERATORS.has(operator)) {
|
|
452
526
|
return jsonValue;
|
|
453
527
|
}
|
|
454
528
|
throw new ShapeError(`Operator "${operator}" not supported for Json fields`);
|
|
455
529
|
}
|
|
530
|
+
function nullableIfOptional(fieldMeta, base) {
|
|
531
|
+
return !fieldMeta.isRequired ? import_zod3.z.union([base, import_zod3.z.null()]) : base;
|
|
532
|
+
}
|
|
456
533
|
function buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase) {
|
|
457
534
|
const allOps = getSupportedOperators(fieldMeta);
|
|
458
535
|
const nestedOps = allOps.filter((op) => op !== "not");
|
|
@@ -468,14 +545,15 @@ function buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase) {
|
|
|
468
545
|
scalarBase
|
|
469
546
|
).optional();
|
|
470
547
|
}
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
(key) => value[key] !== void 0
|
|
475
|
-
),
|
|
476
|
-
{ message: "not filter must specify at least one operator" }
|
|
548
|
+
const nestedObj = strictObjectRequiringOne(
|
|
549
|
+
nestedSchemas,
|
|
550
|
+
"not filter must specify at least one operator"
|
|
477
551
|
);
|
|
478
|
-
return
|
|
552
|
+
return import_zod3.z.union([scalarSchema, nestedObj]);
|
|
553
|
+
}
|
|
554
|
+
function buildNotOperator(fieldMeta, scalarBaseSchema, enumMap, scalarBase) {
|
|
555
|
+
const scalarSchema = nullableIfOptional(fieldMeta, scalarBaseSchema);
|
|
556
|
+
return buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase);
|
|
479
557
|
}
|
|
480
558
|
function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
|
|
481
559
|
const allowedOps = getSupportedOperators(fieldMeta);
|
|
@@ -512,32 +590,19 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
|
|
|
512
590
|
if (!values || values.length === 0) {
|
|
513
591
|
throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
|
|
514
592
|
}
|
|
515
|
-
const enumSchema =
|
|
593
|
+
const enumSchema = import_zod3.z.enum(values);
|
|
516
594
|
if (operator === "equals") {
|
|
517
|
-
return
|
|
595
|
+
return nullableIfOptional(fieldMeta, enumSchema);
|
|
518
596
|
}
|
|
519
597
|
if (operator === "not") {
|
|
520
|
-
|
|
521
|
-
return buildNotFilterSchema(
|
|
522
|
-
fieldMeta,
|
|
523
|
-
scalarSchema,
|
|
524
|
-
enumMap,
|
|
525
|
-
scalarBase
|
|
526
|
-
);
|
|
598
|
+
return buildNotOperator(fieldMeta, enumSchema, enumMap, scalarBase);
|
|
527
599
|
}
|
|
528
|
-
const itemSchema =
|
|
529
|
-
return
|
|
600
|
+
const itemSchema = nullableIfOptional(fieldMeta, enumSchema);
|
|
601
|
+
return import_zod3.z.preprocess(coerceToArray, import_zod3.z.array(itemSchema));
|
|
530
602
|
}
|
|
531
603
|
if (fieldMeta.type === "Json") {
|
|
532
604
|
if (operator === "not") {
|
|
533
|
-
|
|
534
|
-
const scalarSchema = !fieldMeta.isRequired ? import_zod2.z.union([jsonValue, import_zod2.z.null()]) : jsonValue;
|
|
535
|
-
return buildNotFilterSchema(
|
|
536
|
-
fieldMeta,
|
|
537
|
-
scalarSchema,
|
|
538
|
-
enumMap,
|
|
539
|
-
scalarBase
|
|
540
|
-
);
|
|
605
|
+
return buildNotOperator(fieldMeta, import_zod3.z.unknown(), enumMap, scalarBase);
|
|
541
606
|
}
|
|
542
607
|
return createJsonOperatorSchema(fieldMeta, operator);
|
|
543
608
|
}
|
|
@@ -548,15 +613,14 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
|
|
|
548
613
|
const scalar = factory();
|
|
549
614
|
const coerced = wrapWithInputCoercion(fieldMeta.type, false, scalar);
|
|
550
615
|
if (operator === "equals") {
|
|
551
|
-
return
|
|
616
|
+
return nullableIfOptional(fieldMeta, coerced);
|
|
552
617
|
}
|
|
553
618
|
if (operator === "not") {
|
|
554
|
-
|
|
555
|
-
return buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase);
|
|
619
|
+
return buildNotOperator(fieldMeta, coerced, enumMap, scalarBase);
|
|
556
620
|
}
|
|
557
621
|
if (operator === "in" || operator === "notIn") {
|
|
558
|
-
const itemSchema =
|
|
559
|
-
return
|
|
622
|
+
const itemSchema = nullableIfOptional(fieldMeta, coerced);
|
|
623
|
+
return import_zod3.z.preprocess(coerceToArray, import_zod3.z.array(itemSchema));
|
|
560
624
|
}
|
|
561
625
|
return coerced;
|
|
562
626
|
}
|
|
@@ -582,6 +646,26 @@ function lruSet(cache, key, value, maxSize) {
|
|
|
582
646
|
cache.delete(oldest);
|
|
583
647
|
}
|
|
584
648
|
}
|
|
649
|
+
function applyCreateUpdateNullability(fieldMeta, fieldSchema, options) {
|
|
650
|
+
const { mode, handlesUndefined } = options;
|
|
651
|
+
const allowNull = options.allowNull ?? true;
|
|
652
|
+
if (mode === "create") {
|
|
653
|
+
if (!fieldMeta.isRequired) {
|
|
654
|
+
if (handlesUndefined) {
|
|
655
|
+
return allowNull ? fieldSchema.nullable() : fieldSchema;
|
|
656
|
+
}
|
|
657
|
+
return allowNull ? fieldSchema.nullable().optional() : fieldSchema.optional();
|
|
658
|
+
}
|
|
659
|
+
if (fieldMeta.hasDefault) {
|
|
660
|
+
return handlesUndefined ? fieldSchema : fieldSchema.optional();
|
|
661
|
+
}
|
|
662
|
+
return fieldSchema;
|
|
663
|
+
}
|
|
664
|
+
if (!fieldMeta.isRequired && allowNull) {
|
|
665
|
+
return fieldSchema.nullable().optional();
|
|
666
|
+
}
|
|
667
|
+
return fieldSchema.optional();
|
|
668
|
+
}
|
|
585
669
|
function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefaults) {
|
|
586
670
|
const chainCache = /* @__PURE__ */ new Map();
|
|
587
671
|
function buildFieldSchema(model, field) {
|
|
@@ -636,20 +720,25 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
636
720
|
const zodDefaultSet = zodDefaultFields ? new Set(zodDefaultFields) : void 0;
|
|
637
721
|
let fieldNames = Object.keys(modelFields).filter((name) => {
|
|
638
722
|
const meta = modelFields[name];
|
|
639
|
-
return !meta.isRelation && !meta.isUpdatedAt;
|
|
723
|
+
return !meta.isRelation && !meta.isUpdatedAt && !meta.isUnsupported;
|
|
640
724
|
});
|
|
641
725
|
if (opts.pick) {
|
|
642
726
|
for (const name of opts.pick) {
|
|
643
|
-
|
|
727
|
+
const meta = modelFields[name];
|
|
728
|
+
if (!meta)
|
|
644
729
|
throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
|
|
645
|
-
if (
|
|
730
|
+
if (meta.isRelation)
|
|
646
731
|
throw new ShapeError(
|
|
647
732
|
`Field "${name}" cannot be used in input schema (relation field)`
|
|
648
733
|
);
|
|
649
|
-
if (
|
|
734
|
+
if (meta.isUpdatedAt)
|
|
650
735
|
throw new ShapeError(
|
|
651
736
|
`Field "${name}" cannot be used in input schema (updatedAt field)`
|
|
652
737
|
);
|
|
738
|
+
if (meta.isUnsupported)
|
|
739
|
+
throw new ShapeError(
|
|
740
|
+
`Field "${name}" on model "${model}" has an Unsupported type and cannot be used in input schema`
|
|
741
|
+
);
|
|
653
742
|
}
|
|
654
743
|
fieldNames = fieldNames.filter((n) => opts.pick.includes(n));
|
|
655
744
|
} else if (opts.omit) {
|
|
@@ -662,7 +751,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
662
751
|
const schemaMap = {};
|
|
663
752
|
for (const name of fieldNames) {
|
|
664
753
|
const fieldMeta = modelFields[name];
|
|
665
|
-
let
|
|
754
|
+
let baseSchema;
|
|
666
755
|
let handlesUndefined;
|
|
667
756
|
if (opts.refine?.[name]) {
|
|
668
757
|
let refined;
|
|
@@ -679,34 +768,19 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
679
768
|
`Refine function for "${model}.${name}" must return a Zod schema`
|
|
680
769
|
);
|
|
681
770
|
}
|
|
682
|
-
|
|
683
|
-
handlesUndefined = schemaProducesValueForUndefined(
|
|
771
|
+
baseSchema = refined;
|
|
772
|
+
handlesUndefined = schemaProducesValueForUndefined(baseSchema);
|
|
684
773
|
} else {
|
|
685
|
-
|
|
774
|
+
baseSchema = buildFieldSchema(model, name);
|
|
686
775
|
handlesUndefined = zodDefaultSet !== void 0 && zodDefaultSet.has(name);
|
|
687
776
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
fieldSchema = allowNull ? fieldSchema.nullable().optional() : fieldSchema.optional();
|
|
694
|
-
}
|
|
695
|
-
} else if (fieldMeta.hasDefault) {
|
|
696
|
-
if (!handlesUndefined) {
|
|
697
|
-
fieldSchema = fieldSchema.optional();
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
} else {
|
|
701
|
-
if (!fieldMeta.isRequired && allowNull) {
|
|
702
|
-
fieldSchema = fieldSchema.nullable().optional();
|
|
703
|
-
} else {
|
|
704
|
-
fieldSchema = fieldSchema.optional();
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
schemaMap[name] = fieldSchema;
|
|
777
|
+
schemaMap[name] = applyCreateUpdateNullability(fieldMeta, baseSchema, {
|
|
778
|
+
mode,
|
|
779
|
+
handlesUndefined,
|
|
780
|
+
allowNull
|
|
781
|
+
});
|
|
708
782
|
}
|
|
709
|
-
let schema =
|
|
783
|
+
let schema = import_zod4.z.object(schemaMap).strict();
|
|
710
784
|
if (opts.partial) {
|
|
711
785
|
schema = schema.partial();
|
|
712
786
|
}
|
|
@@ -733,13 +807,18 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
733
807
|
const includeKeys = new Set(Object.keys(opts.include ?? {}));
|
|
734
808
|
if (opts.pick) {
|
|
735
809
|
for (const name of opts.pick) {
|
|
736
|
-
|
|
810
|
+
const meta = modelFields[name];
|
|
811
|
+
if (!meta)
|
|
737
812
|
throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
|
|
738
|
-
if (
|
|
813
|
+
if (meta.isRelation && !includeKeys.has(name)) {
|
|
739
814
|
throw new ShapeError(
|
|
740
815
|
`Field "${name}" is a relation on model "${model}". Use include: { ${name}: ... } instead of pick.`
|
|
741
816
|
);
|
|
742
817
|
}
|
|
818
|
+
if (meta.isUnsupported)
|
|
819
|
+
throw new ShapeError(
|
|
820
|
+
`Field "${name}" on model "${model}" has an Unsupported type and cannot be used in output schema`
|
|
821
|
+
);
|
|
743
822
|
}
|
|
744
823
|
}
|
|
745
824
|
if (opts.omit) {
|
|
@@ -750,7 +829,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
750
829
|
}
|
|
751
830
|
let scalarNames = Object.keys(modelFields).filter((name) => {
|
|
752
831
|
const meta = modelFields[name];
|
|
753
|
-
return !meta.isRelation;
|
|
832
|
+
return !meta.isRelation && !meta.isUnsupported;
|
|
754
833
|
});
|
|
755
834
|
if (opts.pick) {
|
|
756
835
|
scalarNames = scalarNames.filter((n) => opts.pick.includes(n));
|
|
@@ -787,7 +866,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
787
866
|
effectiveMaxDepth
|
|
788
867
|
);
|
|
789
868
|
if (fieldMeta.isList) {
|
|
790
|
-
relSchema =
|
|
869
|
+
relSchema = import_zod4.z.array(relSchema);
|
|
791
870
|
} else if (!fieldMeta.isRequired) {
|
|
792
871
|
relSchema = relSchema.nullable();
|
|
793
872
|
}
|
|
@@ -800,9 +879,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
800
879
|
if (opts._count === true) {
|
|
801
880
|
const countFields = {};
|
|
802
881
|
for (const relName of listRelationNames) {
|
|
803
|
-
countFields[relName] =
|
|
882
|
+
countFields[relName] = import_zod4.z.number().int().min(0);
|
|
804
883
|
}
|
|
805
|
-
schemaMap["_count"] =
|
|
884
|
+
schemaMap["_count"] = import_zod4.z.object(countFields);
|
|
806
885
|
} else {
|
|
807
886
|
const countFields = {};
|
|
808
887
|
for (const relName of Object.keys(opts._count)) {
|
|
@@ -818,12 +897,12 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
818
897
|
throw new ShapeError(
|
|
819
898
|
`Field "${relName}" is a to-one relation on model "${model}" in _count. Only to-many relations support _count.`
|
|
820
899
|
);
|
|
821
|
-
countFields[relName] =
|
|
900
|
+
countFields[relName] = import_zod4.z.number().int().min(0);
|
|
822
901
|
}
|
|
823
|
-
schemaMap["_count"] =
|
|
902
|
+
schemaMap["_count"] = import_zod4.z.object(countFields);
|
|
824
903
|
}
|
|
825
904
|
}
|
|
826
|
-
let schema =
|
|
905
|
+
let schema = import_zod4.z.object(schemaMap);
|
|
827
906
|
if (opts.strict) {
|
|
828
907
|
schema = schema.strict();
|
|
829
908
|
}
|
|
@@ -838,7 +917,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
838
917
|
}
|
|
839
918
|
|
|
840
919
|
// src/runtime/query-builder.ts
|
|
841
|
-
var
|
|
920
|
+
var import_zod8 = require("zod");
|
|
842
921
|
|
|
843
922
|
// src/shared/constants.ts
|
|
844
923
|
var SHAPE_CONFIG_KEY_LIST = [
|
|
@@ -894,6 +973,8 @@ function unsupported() {
|
|
|
894
973
|
|
|
895
974
|
// src/shared/match-caller.ts
|
|
896
975
|
function matchCallerPattern(patterns, caller) {
|
|
976
|
+
if (typeof caller !== "string" || caller.trim().length === 0)
|
|
977
|
+
return null;
|
|
897
978
|
if (patterns.includes(caller))
|
|
898
979
|
return caller;
|
|
899
980
|
const matches = [];
|
|
@@ -947,7 +1028,7 @@ function validateContext(ctx) {
|
|
|
947
1028
|
}
|
|
948
1029
|
|
|
949
1030
|
// src/runtime/query-builder-where.ts
|
|
950
|
-
var
|
|
1031
|
+
var import_zod5 = require("zod");
|
|
951
1032
|
|
|
952
1033
|
// src/shared/deep-clone.ts
|
|
953
1034
|
function deepClone(value) {
|
|
@@ -982,44 +1063,75 @@ function deepClone(value) {
|
|
|
982
1063
|
}
|
|
983
1064
|
}
|
|
984
1065
|
|
|
985
|
-
// src/
|
|
986
|
-
|
|
987
|
-
conditions: {},
|
|
988
|
-
relations: {}
|
|
989
|
-
};
|
|
990
|
-
function hasWhereForced(f) {
|
|
991
|
-
return Object.keys(f.conditions).length > 0 || Object.keys(f.relations).length > 0;
|
|
992
|
-
}
|
|
993
|
-
function forcedScalarsEqual(a, b) {
|
|
1066
|
+
// src/shared/deep-equal.ts
|
|
1067
|
+
function deepEqual(a, b) {
|
|
994
1068
|
if (a === b)
|
|
995
1069
|
return true;
|
|
996
1070
|
if (a === null || b === null)
|
|
997
1071
|
return false;
|
|
998
|
-
if (
|
|
1072
|
+
if (a === void 0 || b === void 0)
|
|
1073
|
+
return false;
|
|
1074
|
+
const ta = typeof a;
|
|
1075
|
+
const tb = typeof b;
|
|
1076
|
+
if (ta !== tb)
|
|
1077
|
+
return false;
|
|
1078
|
+
if (ta === "bigint")
|
|
1079
|
+
return a === b;
|
|
1080
|
+
if (ta !== "object")
|
|
999
1081
|
return false;
|
|
1000
1082
|
if (a instanceof Date && b instanceof Date) {
|
|
1001
1083
|
return a.getTime() === b.getTime();
|
|
1002
1084
|
}
|
|
1085
|
+
if (a instanceof Date || b instanceof Date)
|
|
1086
|
+
return false;
|
|
1003
1087
|
if (a instanceof RegExp && b instanceof RegExp) {
|
|
1004
1088
|
return a.source === b.source && a.flags === b.flags;
|
|
1005
1089
|
}
|
|
1090
|
+
if (a instanceof RegExp || b instanceof RegExp)
|
|
1091
|
+
return false;
|
|
1006
1092
|
if (Array.isArray(a)) {
|
|
1007
1093
|
if (!Array.isArray(b))
|
|
1008
1094
|
return false;
|
|
1009
1095
|
if (a.length !== b.length)
|
|
1010
1096
|
return false;
|
|
1011
|
-
|
|
1097
|
+
for (let i = 0; i < a.length; i++) {
|
|
1098
|
+
if (!deepEqual(a[i], b[i]))
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
return true;
|
|
1012
1102
|
}
|
|
1013
|
-
if (
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1103
|
+
if (Array.isArray(b))
|
|
1104
|
+
return false;
|
|
1105
|
+
if (!isPlainObject(a) || !isPlainObject(b))
|
|
1106
|
+
return false;
|
|
1107
|
+
const aKeys = Object.keys(a);
|
|
1108
|
+
const bKeys = Object.keys(b);
|
|
1109
|
+
if (aKeys.length !== bKeys.length)
|
|
1110
|
+
return false;
|
|
1111
|
+
for (const key of aKeys) {
|
|
1112
|
+
if (!(key in b))
|
|
1113
|
+
return false;
|
|
1114
|
+
if (!deepEqual(a[key], b[key]))
|
|
1017
1115
|
return false;
|
|
1018
|
-
return aKeys.every(
|
|
1019
|
-
(k) => k in b && forcedScalarsEqual(a[k], b[k])
|
|
1020
|
-
);
|
|
1021
1116
|
}
|
|
1022
|
-
return
|
|
1117
|
+
return true;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// src/shared/unique-constraints.ts
|
|
1121
|
+
function formatUniqueConstraint(constraint) {
|
|
1122
|
+
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
1123
|
+
}
|
|
1124
|
+
function formatUniqueConstraints(constraints) {
|
|
1125
|
+
return constraints.map(formatUniqueConstraint).join(" | ");
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// src/runtime/query-builder-forced.ts
|
|
1129
|
+
var EMPTY_WHERE_FORCED = {
|
|
1130
|
+
conditions: {},
|
|
1131
|
+
relations: {}
|
|
1132
|
+
};
|
|
1133
|
+
function hasWhereForced(f) {
|
|
1134
|
+
return Object.keys(f.conditions).length > 0 || Object.keys(f.relations).length > 0;
|
|
1023
1135
|
}
|
|
1024
1136
|
function tryInlineForcedField(result, field, forcedValue) {
|
|
1025
1137
|
if (!(field in result))
|
|
@@ -1038,7 +1150,7 @@ function tryInlineForcedField(result, field, forcedValue) {
|
|
|
1038
1150
|
const merged = { ...existing };
|
|
1039
1151
|
for (const [op, value] of Object.entries(forcedValue)) {
|
|
1040
1152
|
if (op in merged) {
|
|
1041
|
-
if (!
|
|
1153
|
+
if (!deepEqual(merged[op], value)) {
|
|
1042
1154
|
throw new ShapeError(
|
|
1043
1155
|
`Conflicting where values for "${field}.${op}": client provided a different value than the forced shape`
|
|
1044
1156
|
);
|
|
@@ -1069,6 +1181,17 @@ function mergeWhereForced(where, forced) {
|
|
|
1069
1181
|
if (Object.keys(forced.conditions).length > 0) {
|
|
1070
1182
|
const remaining = {};
|
|
1071
1183
|
for (const [field, forcedValue] of Object.entries(forced.conditions)) {
|
|
1184
|
+
if (field === "NOT") {
|
|
1185
|
+
const existing = result[field];
|
|
1186
|
+
const forcedArr = Array.isArray(forcedValue) ? forcedValue.map(deepClone) : [deepClone(forcedValue)];
|
|
1187
|
+
if (existing === void 0) {
|
|
1188
|
+
result[field] = forcedArr.length === 1 ? forcedArr[0] : forcedArr;
|
|
1189
|
+
} else {
|
|
1190
|
+
const existingArr = Array.isArray(existing) ? existing : [existing];
|
|
1191
|
+
result[field] = [...existingArr, ...forcedArr];
|
|
1192
|
+
}
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1072
1195
|
const inlined = tryInlineForcedField(result, field, forcedValue);
|
|
1073
1196
|
if (!inlined) {
|
|
1074
1197
|
remaining[field] = deepClone(forcedValue);
|
|
@@ -1084,32 +1207,6 @@ function mergeWhereForced(where, forced) {
|
|
|
1084
1207
|
}
|
|
1085
1208
|
return result;
|
|
1086
1209
|
}
|
|
1087
|
-
function uniqueValuesEqual(a, b) {
|
|
1088
|
-
if (a === b)
|
|
1089
|
-
return true;
|
|
1090
|
-
if (a === null || b === null)
|
|
1091
|
-
return false;
|
|
1092
|
-
if (typeof a !== typeof b)
|
|
1093
|
-
return false;
|
|
1094
|
-
if (a instanceof Date && b instanceof Date) {
|
|
1095
|
-
return a.getTime() === b.getTime();
|
|
1096
|
-
}
|
|
1097
|
-
if (Array.isArray(a)) {
|
|
1098
|
-
if (!Array.isArray(b))
|
|
1099
|
-
return false;
|
|
1100
|
-
if (a.length !== b.length)
|
|
1101
|
-
return false;
|
|
1102
|
-
return a.every((v, i) => uniqueValuesEqual(v, b[i]));
|
|
1103
|
-
}
|
|
1104
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1105
|
-
const aKeys = Object.keys(a);
|
|
1106
|
-
const bKeys = Object.keys(b);
|
|
1107
|
-
if (aKeys.length !== bKeys.length)
|
|
1108
|
-
return false;
|
|
1109
|
-
return aKeys.every((key) => key in b && uniqueValuesEqual(a[key], b[key]));
|
|
1110
|
-
}
|
|
1111
|
-
return false;
|
|
1112
|
-
}
|
|
1113
1210
|
function mergeUniqueValue(target, key, value) {
|
|
1114
1211
|
const cloned = deepClone(value);
|
|
1115
1212
|
if (!(key in target)) {
|
|
@@ -1120,7 +1217,7 @@ function mergeUniqueValue(target, key, value) {
|
|
|
1120
1217
|
if (isPlainObject(existing) && isPlainObject(cloned)) {
|
|
1121
1218
|
const merged = { ...existing };
|
|
1122
1219
|
for (const [nestedKey, nestedValue] of Object.entries(cloned)) {
|
|
1123
|
-
if (nestedKey in merged && !
|
|
1220
|
+
if (nestedKey in merged && !deepEqual(merged[nestedKey], nestedValue)) {
|
|
1124
1221
|
throw new ShapeError(
|
|
1125
1222
|
`Conflicting unique where value for "${key}.${nestedKey}"`
|
|
1126
1223
|
);
|
|
@@ -1130,7 +1227,7 @@ function mergeUniqueValue(target, key, value) {
|
|
|
1130
1227
|
target[key] = merged;
|
|
1131
1228
|
return;
|
|
1132
1229
|
}
|
|
1133
|
-
if (!
|
|
1230
|
+
if (!deepEqual(existing, cloned)) {
|
|
1134
1231
|
throw new ShapeError(`Conflicting unique where value for "${key}"`);
|
|
1135
1232
|
}
|
|
1136
1233
|
}
|
|
@@ -1157,7 +1254,30 @@ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
|
|
|
1157
1254
|
throw new ShapeError('Request cannot define both "include" and "select"');
|
|
1158
1255
|
}
|
|
1159
1256
|
if ("where" in bodyObj) {
|
|
1160
|
-
if (
|
|
1257
|
+
if (bodyObj.where === void 0 || bodyObj.where === null) {
|
|
1258
|
+
const { where: _, ...rest } = bodyObj;
|
|
1259
|
+
parseable = rest;
|
|
1260
|
+
} else if (!hasWhereInSchema) {
|
|
1261
|
+
const context = modelName ? ` on model "${modelName}"` : "";
|
|
1262
|
+
if (!hasWhereForced(built.forcedWhere)) {
|
|
1263
|
+
throw new ShapeError(
|
|
1264
|
+
`Guard shape does not allow "where"${context}`
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
if (!isPlainObject(bodyObj.where)) {
|
|
1268
|
+
throw new ShapeError(
|
|
1269
|
+
`Invalid "where"${context}: must be a plain object`
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
const remaining = stripUniqueWhereForcedInput(
|
|
1273
|
+
bodyObj.where,
|
|
1274
|
+
built.forcedWhere
|
|
1275
|
+
);
|
|
1276
|
+
if (Object.keys(remaining).length > 0) {
|
|
1277
|
+
throw new ShapeError(
|
|
1278
|
+
`Guard shape where${context} contains only forced conditions. Client where input is not accepted.`
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1161
1281
|
const { where: _, ...rest } = bodyObj;
|
|
1162
1282
|
parseable = rest;
|
|
1163
1283
|
} else if (isUniqueMethod && hasWhereForced(built.forcedWhere) && isPlainObject(bodyObj.where)) {
|
|
@@ -1233,6 +1353,86 @@ function buildCountForPlacement(countWhere) {
|
|
|
1233
1353
|
}
|
|
1234
1354
|
return { _count: { select: countSelect } };
|
|
1235
1355
|
}
|
|
1356
|
+
function collectSubtree(forced) {
|
|
1357
|
+
const nested = {};
|
|
1358
|
+
if (forced.where && hasWhereForced(forced.where)) {
|
|
1359
|
+
nested.where = mergeWhereForced(void 0, forced.where);
|
|
1360
|
+
}
|
|
1361
|
+
if (forced.include) {
|
|
1362
|
+
nested.include = buildForcedOnlyContainer(forced.include);
|
|
1363
|
+
}
|
|
1364
|
+
if (forced.select) {
|
|
1365
|
+
nested.select = buildForcedOnlyContainer(forced.select);
|
|
1366
|
+
}
|
|
1367
|
+
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1368
|
+
const placement = forced._countWherePlacement ?? "include";
|
|
1369
|
+
if (!nested[placement])
|
|
1370
|
+
nested[placement] = {};
|
|
1371
|
+
const placementObj = nested[placement];
|
|
1372
|
+
Object.assign(placementObj, buildCountForPlacement(forced._countWhere));
|
|
1373
|
+
}
|
|
1374
|
+
return nested;
|
|
1375
|
+
}
|
|
1376
|
+
function applyForcedToRelValue(relName, relVal, forced) {
|
|
1377
|
+
if (relVal === true) {
|
|
1378
|
+
const expanded = collectSubtree(forced);
|
|
1379
|
+
if (forced.include) {
|
|
1380
|
+
applyForcedTree(expanded, "include", forced.include);
|
|
1381
|
+
}
|
|
1382
|
+
if (forced.select) {
|
|
1383
|
+
applyForcedTree(expanded, "select", forced.select);
|
|
1384
|
+
}
|
|
1385
|
+
if (expanded.include && expanded.select) {
|
|
1386
|
+
throw new ShapeError(
|
|
1387
|
+
`Forced tree for relation "${relName}" produces both "include" and "select". Prisma does not allow both at the same level.`
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
return Object.keys(expanded).length > 0 ? expanded : true;
|
|
1391
|
+
}
|
|
1392
|
+
if (!isPlainObject(relVal))
|
|
1393
|
+
return relVal;
|
|
1394
|
+
const relObj = relVal;
|
|
1395
|
+
if (forced.where && hasWhereForced(forced.where)) {
|
|
1396
|
+
relObj.where = mergeWhereForced(
|
|
1397
|
+
relObj.where,
|
|
1398
|
+
forced.where
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
if (forced.include) {
|
|
1402
|
+
if (!relObj.include) {
|
|
1403
|
+
relObj.include = buildForcedOnlyContainer(forced.include);
|
|
1404
|
+
}
|
|
1405
|
+
applyForcedTree(relObj, "include", forced.include);
|
|
1406
|
+
}
|
|
1407
|
+
if (forced.select) {
|
|
1408
|
+
if (!relObj.select) {
|
|
1409
|
+
relObj.select = buildForcedOnlyContainer(forced.select);
|
|
1410
|
+
}
|
|
1411
|
+
applyForcedTree(relObj, "select", forced.select);
|
|
1412
|
+
}
|
|
1413
|
+
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1414
|
+
const placement = forced._countWherePlacement ?? "include";
|
|
1415
|
+
const existing = relObj[placement];
|
|
1416
|
+
let placementObj;
|
|
1417
|
+
if (!isPlainObject(existing)) {
|
|
1418
|
+
placementObj = {};
|
|
1419
|
+
relObj[placement] = placementObj;
|
|
1420
|
+
} else {
|
|
1421
|
+
placementObj = existing;
|
|
1422
|
+
}
|
|
1423
|
+
if (!("_count" in placementObj)) {
|
|
1424
|
+
Object.assign(placementObj, buildCountForPlacement(forced._countWhere));
|
|
1425
|
+
} else {
|
|
1426
|
+
applyForcedCountWhere(placementObj, forced._countWhere);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
if (relObj.include && relObj.select) {
|
|
1430
|
+
throw new ShapeError(
|
|
1431
|
+
`Relation "${relName}" has both "include" and "select" after forced tree merge. Prisma does not allow both at the same level.`
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
return relObj;
|
|
1435
|
+
}
|
|
1236
1436
|
function applyForcedTree(validated, key, tree) {
|
|
1237
1437
|
const container = validated[key];
|
|
1238
1438
|
if (!container)
|
|
@@ -1241,89 +1441,13 @@ function applyForcedTree(validated, key, tree) {
|
|
|
1241
1441
|
const relVal = container[relName];
|
|
1242
1442
|
if (relVal === void 0)
|
|
1243
1443
|
continue;
|
|
1244
|
-
|
|
1245
|
-
const expanded = {};
|
|
1246
|
-
if (forced.where && hasWhereForced(forced.where)) {
|
|
1247
|
-
expanded.where = mergeWhereForced(void 0, forced.where);
|
|
1248
|
-
}
|
|
1249
|
-
if (forced.include) {
|
|
1250
|
-
expanded.include = buildForcedOnlyContainer(forced.include);
|
|
1251
|
-
applyForcedTree(expanded, "include", forced.include);
|
|
1252
|
-
}
|
|
1253
|
-
if (forced.select) {
|
|
1254
|
-
expanded.select = buildForcedOnlyContainer(forced.select);
|
|
1255
|
-
applyForcedTree(expanded, "select", forced.select);
|
|
1256
|
-
}
|
|
1257
|
-
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1258
|
-
const placement = forced._countWherePlacement ?? "include";
|
|
1259
|
-
if (!expanded[placement])
|
|
1260
|
-
expanded[placement] = {};
|
|
1261
|
-
const placementObj = expanded[placement];
|
|
1262
|
-
Object.assign(placementObj, buildCountForPlacement(forced._countWhere));
|
|
1263
|
-
}
|
|
1264
|
-
if (expanded.include && expanded.select) {
|
|
1265
|
-
throw new ShapeError(
|
|
1266
|
-
`Forced tree for relation "${relName}" produces both "include" and "select". Prisma does not allow both at the same level.`
|
|
1267
|
-
);
|
|
1268
|
-
}
|
|
1269
|
-
container[relName] = Object.keys(expanded).length > 0 ? expanded : true;
|
|
1270
|
-
continue;
|
|
1271
|
-
}
|
|
1272
|
-
if (isPlainObject(relVal)) {
|
|
1273
|
-
const relObj = relVal;
|
|
1274
|
-
if (forced.where && hasWhereForced(forced.where)) {
|
|
1275
|
-
relObj.where = mergeWhereForced(
|
|
1276
|
-
relObj.where,
|
|
1277
|
-
forced.where
|
|
1278
|
-
);
|
|
1279
|
-
}
|
|
1280
|
-
if (forced.include) {
|
|
1281
|
-
if (!relObj.include) {
|
|
1282
|
-
relObj.include = buildForcedOnlyContainer(forced.include);
|
|
1283
|
-
}
|
|
1284
|
-
applyForcedTree(relObj, "include", forced.include);
|
|
1285
|
-
}
|
|
1286
|
-
if (forced.select) {
|
|
1287
|
-
if (!relObj.select) {
|
|
1288
|
-
relObj.select = buildForcedOnlyContainer(forced.select);
|
|
1289
|
-
}
|
|
1290
|
-
applyForcedTree(relObj, "select", forced.select);
|
|
1291
|
-
}
|
|
1292
|
-
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1293
|
-
const placement = forced._countWherePlacement ?? "include";
|
|
1294
|
-
const projContainer = relObj[placement];
|
|
1295
|
-
if (projContainer) {
|
|
1296
|
-
applyForcedCountWhere(projContainer, forced._countWhere);
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
if (relObj.include && relObj.select) {
|
|
1300
|
-
throw new ShapeError(
|
|
1301
|
-
`Relation "${relName}" has both "include" and "select" after forced tree merge. Prisma does not allow both at the same level.`
|
|
1302
|
-
);
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1444
|
+
container[relName] = applyForcedToRelValue(relName, relVal, forced);
|
|
1305
1445
|
}
|
|
1306
1446
|
}
|
|
1307
1447
|
function buildForcedOnlyContainer(tree) {
|
|
1308
1448
|
const result = {};
|
|
1309
1449
|
for (const [relName, forced] of Object.entries(tree)) {
|
|
1310
|
-
const nested =
|
|
1311
|
-
if (forced.where && hasWhereForced(forced.where)) {
|
|
1312
|
-
nested.where = mergeWhereForced(void 0, forced.where);
|
|
1313
|
-
}
|
|
1314
|
-
if (forced.include) {
|
|
1315
|
-
nested.include = buildForcedOnlyContainer(forced.include);
|
|
1316
|
-
}
|
|
1317
|
-
if (forced.select) {
|
|
1318
|
-
nested.select = buildForcedOnlyContainer(forced.select);
|
|
1319
|
-
}
|
|
1320
|
-
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1321
|
-
const placement = forced._countWherePlacement ?? "include";
|
|
1322
|
-
if (!nested[placement])
|
|
1323
|
-
nested[placement] = {};
|
|
1324
|
-
const placementObj = nested[placement];
|
|
1325
|
-
Object.assign(placementObj, buildCountForPlacement(forced._countWhere));
|
|
1326
|
-
}
|
|
1450
|
+
const nested = collectSubtree(forced);
|
|
1327
1451
|
result[relName] = Object.keys(nested).length > 0 ? nested : true;
|
|
1328
1452
|
}
|
|
1329
1453
|
return result;
|
|
@@ -1339,11 +1463,15 @@ function applyForcedCountWhere(container, forcedCountWhere) {
|
|
|
1339
1463
|
const selectObj = selectVal;
|
|
1340
1464
|
for (const [relName, forced] of Object.entries(forcedCountWhere)) {
|
|
1341
1465
|
const relVal = selectObj[relName];
|
|
1342
|
-
if (relVal === void 0)
|
|
1466
|
+
if (relVal === void 0) {
|
|
1467
|
+
selectObj[relName] = { where: mergeWhereForced(void 0, forced) };
|
|
1343
1468
|
continue;
|
|
1469
|
+
}
|
|
1344
1470
|
if (relVal === true) {
|
|
1345
1471
|
selectObj[relName] = { where: mergeWhereForced(void 0, forced) };
|
|
1346
|
-
|
|
1472
|
+
continue;
|
|
1473
|
+
}
|
|
1474
|
+
if (isPlainObject(relVal)) {
|
|
1347
1475
|
const relObj = relVal;
|
|
1348
1476
|
relObj.where = mergeWhereForced(
|
|
1349
1477
|
relObj.where,
|
|
@@ -1352,12 +1480,6 @@ function applyForcedCountWhere(container, forcedCountWhere) {
|
|
|
1352
1480
|
}
|
|
1353
1481
|
}
|
|
1354
1482
|
}
|
|
1355
|
-
function formatUniqueConstraint(constraint) {
|
|
1356
|
-
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
1357
|
-
}
|
|
1358
|
-
function formatUniqueConstraints(constraints) {
|
|
1359
|
-
return constraints.map(formatUniqueConstraint).join(" | ");
|
|
1360
|
-
}
|
|
1361
1483
|
function resolvedWhereCoversConstraint(where, constraint) {
|
|
1362
1484
|
if (constraint.fields.length === 1) {
|
|
1363
1485
|
return constraint.fields[0] in where;
|
|
@@ -1463,7 +1585,12 @@ function stripUniqueWhereForcedInput(where, forced) {
|
|
|
1463
1585
|
const currentValue = result[key];
|
|
1464
1586
|
if (isPlainObject(currentValue) && isPlainObject(forcedValue)) {
|
|
1465
1587
|
const nested = { ...currentValue };
|
|
1466
|
-
for (const nestedKey of Object.
|
|
1588
|
+
for (const [nestedKey, nestedForcedValue] of Object.entries(forcedValue)) {
|
|
1589
|
+
if (nestedKey in nested && !deepEqual(nested[nestedKey], nestedForcedValue)) {
|
|
1590
|
+
throw new ShapeError(
|
|
1591
|
+
`Client unique where value for "${key}.${nestedKey}" conflicts with forced value`
|
|
1592
|
+
);
|
|
1593
|
+
}
|
|
1467
1594
|
delete nested[nestedKey];
|
|
1468
1595
|
}
|
|
1469
1596
|
if (Object.keys(nested).length === 0) {
|
|
@@ -1473,11 +1600,25 @@ function stripUniqueWhereForcedInput(where, forced) {
|
|
|
1473
1600
|
}
|
|
1474
1601
|
continue;
|
|
1475
1602
|
}
|
|
1603
|
+
if (!deepEqual(currentValue, forcedValue)) {
|
|
1604
|
+
throw new ShapeError(
|
|
1605
|
+
`Client unique where value for "${key}" conflicts with forced value`
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1476
1608
|
delete result[key];
|
|
1477
1609
|
}
|
|
1478
1610
|
return result;
|
|
1479
1611
|
}
|
|
1480
1612
|
|
|
1613
|
+
// src/runtime/direct-scalar-schema.ts
|
|
1614
|
+
function buildDirectScalarSchema(fieldMeta, enumMap, scalarBase) {
|
|
1615
|
+
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
1616
|
+
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
1617
|
+
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
1618
|
+
}
|
|
1619
|
+
return base;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1481
1622
|
// src/runtime/query-builder-where.ts
|
|
1482
1623
|
var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Bytes"]);
|
|
1483
1624
|
var STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
@@ -1491,47 +1632,40 @@ var JSON_STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
|
1491
1632
|
"string_starts_with",
|
|
1492
1633
|
"string_ends_with"
|
|
1493
1634
|
]);
|
|
1635
|
+
var NEGATIVE_RELATION_OPS = /* @__PURE__ */ new Set(["none", "isNot"]);
|
|
1494
1636
|
var MAX_WHERE_DEPTH = 10;
|
|
1495
|
-
function safeStringify(
|
|
1496
|
-
if (typeof
|
|
1497
|
-
return `${
|
|
1637
|
+
function safeStringify(value) {
|
|
1638
|
+
if (typeof value === "bigint")
|
|
1639
|
+
return `${value}n`;
|
|
1640
|
+
if (typeof value === "undefined")
|
|
1641
|
+
return "undefined";
|
|
1642
|
+
if (typeof value === "function")
|
|
1643
|
+
return "[function]";
|
|
1644
|
+
if (typeof value === "symbol")
|
|
1645
|
+
return value.toString();
|
|
1646
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1498
1647
|
try {
|
|
1499
|
-
|
|
1648
|
+
const json = JSON.stringify(value, (_key, current) => {
|
|
1649
|
+
if (typeof current === "bigint")
|
|
1650
|
+
return `${current}n`;
|
|
1651
|
+
if (typeof current === "undefined")
|
|
1652
|
+
return "[undefined]";
|
|
1653
|
+
if (typeof current === "function")
|
|
1654
|
+
return "[function]";
|
|
1655
|
+
if (typeof current === "symbol")
|
|
1656
|
+
return current.toString();
|
|
1657
|
+
if (current && typeof current === "object") {
|
|
1658
|
+
if (seen.has(current))
|
|
1659
|
+
return "[Circular]";
|
|
1660
|
+
seen.add(current);
|
|
1661
|
+
}
|
|
1662
|
+
return current;
|
|
1663
|
+
});
|
|
1664
|
+
return json === void 0 ? String(value) : json;
|
|
1500
1665
|
} catch {
|
|
1501
|
-
return String(
|
|
1666
|
+
return String(value);
|
|
1502
1667
|
}
|
|
1503
1668
|
}
|
|
1504
|
-
function forcedValuesEqual(a, b) {
|
|
1505
|
-
if (a === b)
|
|
1506
|
-
return true;
|
|
1507
|
-
if (a === null || b === null)
|
|
1508
|
-
return false;
|
|
1509
|
-
if (typeof a !== typeof b)
|
|
1510
|
-
return false;
|
|
1511
|
-
if (typeof a === "bigint")
|
|
1512
|
-
return a === b;
|
|
1513
|
-
if (a instanceof Date && b instanceof Date)
|
|
1514
|
-
return a.getTime() === b.getTime();
|
|
1515
|
-
if (a instanceof RegExp && b instanceof RegExp) {
|
|
1516
|
-
return a.source === b.source && a.flags === b.flags;
|
|
1517
|
-
}
|
|
1518
|
-
if (typeof a !== "object")
|
|
1519
|
-
return false;
|
|
1520
|
-
if (Array.isArray(a)) {
|
|
1521
|
-
if (!Array.isArray(b))
|
|
1522
|
-
return false;
|
|
1523
|
-
if (a.length !== b.length)
|
|
1524
|
-
return false;
|
|
1525
|
-
return a.every((v, i) => forcedValuesEqual(v, b[i]));
|
|
1526
|
-
}
|
|
1527
|
-
if (!isPlainObject(a) || !isPlainObject(b))
|
|
1528
|
-
return false;
|
|
1529
|
-
const aKeys = Object.keys(a);
|
|
1530
|
-
const bKeys = Object.keys(b);
|
|
1531
|
-
if (aKeys.length !== bKeys.length)
|
|
1532
|
-
return false;
|
|
1533
|
-
return aKeys.every((k) => k in b && forcedValuesEqual(a[k], b[k]));
|
|
1534
|
-
}
|
|
1535
1669
|
function mergeScalarConditions(target, source) {
|
|
1536
1670
|
for (const [field, ops] of Object.entries(source)) {
|
|
1537
1671
|
const existing = target[field];
|
|
@@ -1549,7 +1683,7 @@ function mergeScalarConditions(target, source) {
|
|
|
1549
1683
|
for (const [op, val] of Object.entries(ops)) {
|
|
1550
1684
|
if (op in existing) {
|
|
1551
1685
|
const existingVal = existing[op];
|
|
1552
|
-
if (!
|
|
1686
|
+
if (!deepEqual(existingVal, val)) {
|
|
1553
1687
|
throw new ShapeError(
|
|
1554
1688
|
`Conflicting forced where values for "${field}.${op}": shape defines both ${safeStringify(existingVal)} and ${safeStringify(val)}`
|
|
1555
1689
|
);
|
|
@@ -1559,7 +1693,7 @@ function mergeScalarConditions(target, source) {
|
|
|
1559
1693
|
Object.assign(existing, ops);
|
|
1560
1694
|
continue;
|
|
1561
1695
|
}
|
|
1562
|
-
if (!
|
|
1696
|
+
if (!deepEqual(existing, ops)) {
|
|
1563
1697
|
throw new ShapeError(`Conflicting forced where values for "${field}"`);
|
|
1564
1698
|
}
|
|
1565
1699
|
}
|
|
@@ -1650,27 +1784,27 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1650
1784
|
scalarConditions
|
|
1651
1785
|
);
|
|
1652
1786
|
}
|
|
1653
|
-
|
|
1787
|
+
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1788
|
+
for (const key of Object.keys(whereConfig)) {
|
|
1654
1789
|
if (COMBINATOR_KEYS.has(key))
|
|
1655
1790
|
continue;
|
|
1656
1791
|
if (!(key in fieldSchemas)) {
|
|
1657
|
-
|
|
1792
|
+
forcedOnlyKeys.add(key);
|
|
1658
1793
|
}
|
|
1659
1794
|
}
|
|
1660
|
-
for (const key of Object.keys(
|
|
1795
|
+
for (const key of Object.keys(scalarConditions)) {
|
|
1796
|
+
if (COMBINATOR_KEYS.has(key))
|
|
1797
|
+
continue;
|
|
1661
1798
|
if (!(key in fieldSchemas)) {
|
|
1662
|
-
fieldSchemas[key] =
|
|
1799
|
+
fieldSchemas[key] = import_zod5.z.object({}).strict().optional();
|
|
1663
1800
|
}
|
|
1664
1801
|
}
|
|
1665
|
-
const
|
|
1666
|
-
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1667
|
-
for (const key of Object.keys(whereConfig)) {
|
|
1668
|
-
if (COMBINATOR_KEYS.has(key))
|
|
1669
|
-
continue;
|
|
1802
|
+
for (const key of Object.keys(relationForced)) {
|
|
1670
1803
|
if (!(key in fieldSchemas)) {
|
|
1671
|
-
|
|
1804
|
+
fieldSchemas[key] = import_zod5.z.object({}).strict().optional();
|
|
1672
1805
|
}
|
|
1673
1806
|
}
|
|
1807
|
+
const schema = Object.keys(fieldSchemas).length > 0 ? import_zod5.z.object(fieldSchemas).strict().optional() : null;
|
|
1674
1808
|
return {
|
|
1675
1809
|
schema,
|
|
1676
1810
|
forced: {
|
|
@@ -1701,12 +1835,12 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1701
1835
|
);
|
|
1702
1836
|
}
|
|
1703
1837
|
if (key === "NOT") {
|
|
1704
|
-
fieldSchemas[key] =
|
|
1838
|
+
fieldSchemas[key] = import_zod5.z.union([
|
|
1705
1839
|
elementSchema,
|
|
1706
|
-
|
|
1840
|
+
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(elementSchema).min(1))
|
|
1707
1841
|
]).optional();
|
|
1708
1842
|
} else {
|
|
1709
|
-
fieldSchemas[key] =
|
|
1843
|
+
fieldSchemas[key] = import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(elementSchema).min(1)).optional();
|
|
1710
1844
|
}
|
|
1711
1845
|
}
|
|
1712
1846
|
if (hasWhereForced(result.forced)) {
|
|
@@ -1775,6 +1909,11 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1775
1909
|
`Empty nested where for relation "${key}.${op}" on model "${model}". Define at least one field.`
|
|
1776
1910
|
);
|
|
1777
1911
|
}
|
|
1912
|
+
if (NEGATIVE_RELATION_OPS.has(op) && nested.schema && hasWhereForced(nested.forced)) {
|
|
1913
|
+
throw new ShapeError(
|
|
1914
|
+
`Relation filter "${key}.${op}" on model "${model}" mixes client-controlled and forced conditions. Under negative relation operators (none, isNot), merging weakens the filter. Either move forced conditions to a separate top-level "${op}" branch, or make all conditions under this operator client-controlled or all forced.`
|
|
1915
|
+
);
|
|
1916
|
+
}
|
|
1778
1917
|
if (nested.schema) {
|
|
1779
1918
|
if (!hasWhereForced(nested.forced)) {
|
|
1780
1919
|
opSchemas[op] = nested.schema.refine(
|
|
@@ -1799,7 +1938,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1799
1938
|
}
|
|
1800
1939
|
if (hasClientOps) {
|
|
1801
1940
|
const clientOpKeys = Object.keys(opSchemas);
|
|
1802
|
-
const opObjSchema =
|
|
1941
|
+
const opObjSchema = import_zod5.z.object(opSchemas).strict();
|
|
1803
1942
|
if (Object.keys(opForced).length === 0 && !hasForcedNull) {
|
|
1804
1943
|
fieldSchemas[key] = opObjSchema.refine(
|
|
1805
1944
|
(v) => clientOpKeys.some(
|
|
@@ -1885,10 +2024,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1885
2024
|
);
|
|
1886
2025
|
}
|
|
1887
2026
|
if (modeConfigValue === true) {
|
|
1888
|
-
opSchemas.mode =
|
|
2027
|
+
opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
|
|
1889
2028
|
} else {
|
|
1890
2029
|
const actualModeValue = isForcedValue(modeConfigValue) ? modeConfigValue.value : modeConfigValue;
|
|
1891
|
-
const modeSchema =
|
|
2030
|
+
const modeSchema = import_zod5.z.enum(["default", "insensitive"]);
|
|
1892
2031
|
let parsed;
|
|
1893
2032
|
try {
|
|
1894
2033
|
parsed = modeSchema.parse(actualModeValue);
|
|
@@ -1900,10 +2039,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1900
2039
|
fieldForced.mode = parsed;
|
|
1901
2040
|
}
|
|
1902
2041
|
} else if (hasModeCompatibleOp) {
|
|
1903
|
-
opSchemas.mode =
|
|
2042
|
+
opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
|
|
1904
2043
|
}
|
|
1905
2044
|
if (hasClientOps) {
|
|
1906
|
-
const opObj =
|
|
2045
|
+
const opObj = import_zod5.z.object(opSchemas).strict();
|
|
1907
2046
|
const refined = opObj.refine(
|
|
1908
2047
|
(v) => clientOpKeys.some(
|
|
1909
2048
|
(k) => v[k] !== void 0
|
|
@@ -1919,7 +2058,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1919
2058
|
enumMap,
|
|
1920
2059
|
scalarBase
|
|
1921
2060
|
);
|
|
1922
|
-
fieldSchemas[fieldName] =
|
|
2061
|
+
fieldSchemas[fieldName] = import_zod5.z.union([refined, equalsBase]).optional();
|
|
1923
2062
|
} else {
|
|
1924
2063
|
fieldSchemas[fieldName] = refined.optional();
|
|
1925
2064
|
}
|
|
@@ -1933,15 +2072,8 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1933
2072
|
(constraint) => constraint.selector === selector
|
|
1934
2073
|
) ?? null;
|
|
1935
2074
|
}
|
|
1936
|
-
function buildDirectUniqueSchema(fieldMeta) {
|
|
1937
|
-
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
1938
|
-
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
1939
|
-
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
1940
|
-
}
|
|
1941
|
-
return base;
|
|
1942
|
-
}
|
|
1943
2075
|
function parseForcedUniqueValue(model, fieldName, fieldMeta, value) {
|
|
1944
|
-
const schema =
|
|
2076
|
+
const schema = buildDirectScalarSchema(fieldMeta, enumMap, scalarBase);
|
|
1945
2077
|
const actual = isForcedValue(value) ? value.value : value;
|
|
1946
2078
|
try {
|
|
1947
2079
|
return schema.parse(actual);
|
|
@@ -2019,7 +2151,11 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2019
2151
|
`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.`
|
|
2020
2152
|
);
|
|
2021
2153
|
}
|
|
2022
|
-
const directSchema2 =
|
|
2154
|
+
const directSchema2 = buildDirectScalarSchema(
|
|
2155
|
+
fieldMeta2,
|
|
2156
|
+
enumMap,
|
|
2157
|
+
scalarBase
|
|
2158
|
+
);
|
|
2023
2159
|
if (fieldValue === true) {
|
|
2024
2160
|
nestedSchemas[fieldName] = directSchema2;
|
|
2025
2161
|
} else {
|
|
@@ -2032,7 +2168,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2032
2168
|
}
|
|
2033
2169
|
}
|
|
2034
2170
|
if (Object.keys(nestedSchemas).length > 0) {
|
|
2035
|
-
fieldSchemas[key] =
|
|
2171
|
+
fieldSchemas[key] = import_zod5.z.object(nestedSchemas).strict();
|
|
2036
2172
|
}
|
|
2037
2173
|
if (Object.keys(forcedCompound).length > 0) {
|
|
2038
2174
|
forcedConditions[key] = forcedCompound;
|
|
@@ -2066,7 +2202,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2066
2202
|
`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 }.`
|
|
2067
2203
|
);
|
|
2068
2204
|
}
|
|
2069
|
-
const directSchema =
|
|
2205
|
+
const directSchema = buildDirectScalarSchema(fieldMeta, enumMap, scalarBase);
|
|
2070
2206
|
if (value === true) {
|
|
2071
2207
|
fieldSchemas[key] = directSchema;
|
|
2072
2208
|
continue;
|
|
@@ -2080,7 +2216,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2080
2216
|
forcedOnlyKeys.add(key);
|
|
2081
2217
|
}
|
|
2082
2218
|
return {
|
|
2083
|
-
schema: Object.keys(fieldSchemas).length > 0 ?
|
|
2219
|
+
schema: Object.keys(fieldSchemas).length > 0 ? import_zod5.z.object(fieldSchemas).strict() : null,
|
|
2084
2220
|
forced: {
|
|
2085
2221
|
conditions: forcedConditions,
|
|
2086
2222
|
relations: {}
|
|
@@ -2092,31 +2228,13 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2092
2228
|
}
|
|
2093
2229
|
|
|
2094
2230
|
// src/runtime/query-builder-args.ts
|
|
2095
|
-
var
|
|
2231
|
+
var import_zod6 = require("zod");
|
|
2096
2232
|
var UNSUPPORTED_BY_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
|
|
2097
|
-
function requireConfigTrue(config, context) {
|
|
2098
|
-
for (const [key, value] of Object.entries(config)) {
|
|
2099
|
-
if (value !== true) {
|
|
2100
|
-
throw new ShapeError(
|
|
2101
|
-
`Config value for "${key}" in ${context} must be true, got ${typeof value}`
|
|
2102
|
-
);
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
function isPlainRecord(value) {
|
|
2107
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2108
|
-
}
|
|
2109
|
-
function formatUniqueConstraint2(constraint) {
|
|
2110
|
-
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
2111
|
-
}
|
|
2112
|
-
function formatUniqueConstraints2(constraints) {
|
|
2113
|
-
return constraints.map(formatUniqueConstraint2).join(" | ");
|
|
2114
|
-
}
|
|
2115
2233
|
function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
2116
|
-
const sortEnum =
|
|
2117
|
-
const nullsEnum =
|
|
2118
|
-
const sortWithNulls =
|
|
2119
|
-
const scalarOrderSchema =
|
|
2234
|
+
const sortEnum = import_zod6.z.enum(["asc", "desc"]);
|
|
2235
|
+
const nullsEnum = import_zod6.z.enum(["first", "last"]);
|
|
2236
|
+
const sortWithNulls = import_zod6.z.object({ sort: sortEnum, nulls: nullsEnum.optional() }).strict();
|
|
2237
|
+
const scalarOrderSchema = import_zod6.z.union([sortEnum, sortWithNulls]);
|
|
2120
2238
|
function validateScalarOrderByField(fieldName, model, modelFields) {
|
|
2121
2239
|
const fieldMeta = modelFields[fieldName];
|
|
2122
2240
|
if (!fieldMeta)
|
|
@@ -2135,6 +2253,16 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2135
2253
|
);
|
|
2136
2254
|
}
|
|
2137
2255
|
function buildOrderBySchema(model, orderByConfig) {
|
|
2256
|
+
if (!isPlainObject(orderByConfig)) {
|
|
2257
|
+
throw new ShapeError(
|
|
2258
|
+
`orderBy shape config on model "${model}" must be an object of fields`
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
if (Object.keys(orderByConfig).length === 0) {
|
|
2262
|
+
throw new ShapeError(
|
|
2263
|
+
`Empty orderBy config on model "${model}". Define at least one field.`
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2138
2266
|
const modelFields = typeMap[model];
|
|
2139
2267
|
if (!modelFields)
|
|
2140
2268
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -2150,53 +2278,35 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2150
2278
|
fieldSchemas[fieldName] = scalarOrderSchema.optional();
|
|
2151
2279
|
continue;
|
|
2152
2280
|
}
|
|
2153
|
-
if (!
|
|
2281
|
+
if (!isPlainObject(config)) {
|
|
2154
2282
|
throw new ShapeError(
|
|
2155
|
-
`orderBy config for "${fieldName}" on model "${model}" must be true or a relation
|
|
2283
|
+
`orderBy config for "${fieldName}" on model "${model}" must be true or a relation config object`
|
|
2156
2284
|
);
|
|
2157
2285
|
}
|
|
2158
2286
|
if (!fieldMeta.isRelation) {
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
fieldMeta.isList
|
|
2287
|
+
throw new ShapeError(
|
|
2288
|
+
`orderBy config for scalar field "${model}.${fieldName}" must be true. Operator objects are not valid in orderBy.`
|
|
2162
2289
|
);
|
|
2163
|
-
const opSchemas = {};
|
|
2164
|
-
for (const [op, enabled] of Object.entries(config)) {
|
|
2165
|
-
if (enabled !== true) {
|
|
2166
|
-
throw new ShapeError(
|
|
2167
|
-
`orderBy operator config for "${model}.${fieldName}.${op}" must be true`
|
|
2168
|
-
);
|
|
2169
|
-
}
|
|
2170
|
-
if (!allowedOps.includes(op)) {
|
|
2171
|
-
throw new ShapeError(
|
|
2172
|
-
`Operator "${op}" not supported for orderBy field "${model}.${fieldName}"`
|
|
2173
|
-
);
|
|
2174
|
-
}
|
|
2175
|
-
opSchemas[op] = scalarOrderSchema.optional();
|
|
2176
|
-
}
|
|
2177
|
-
const opKeys = Object.keys(opSchemas);
|
|
2178
|
-
fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
|
|
2179
|
-
(v) => opKeys.some(
|
|
2180
|
-
(k) => v[k] !== void 0
|
|
2181
|
-
),
|
|
2182
|
-
{
|
|
2183
|
-
message: `orderBy field "${fieldName}" must specify at least one operator`
|
|
2184
|
-
}
|
|
2185
|
-
).optional();
|
|
2186
|
-
continue;
|
|
2187
2290
|
}
|
|
2188
2291
|
if (fieldMeta.isList) {
|
|
2189
|
-
|
|
2292
|
+
const configKeys = Object.keys(config);
|
|
2293
|
+
if (!configKeys.includes("_count")) {
|
|
2190
2294
|
throw new ShapeError(
|
|
2191
2295
|
`To-many relation orderBy "${fieldName}" only supports _count`
|
|
2192
2296
|
);
|
|
2193
2297
|
}
|
|
2298
|
+
const extraKeys = configKeys.filter((k) => k !== "_count");
|
|
2299
|
+
if (extraKeys.length > 0) {
|
|
2300
|
+
throw new ShapeError(
|
|
2301
|
+
`To-many relation orderBy "${fieldName}" only supports _count. Unexpected keys: ${extraKeys.join(", ")}`
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2194
2304
|
if (config._count !== true) {
|
|
2195
2305
|
throw new ShapeError(
|
|
2196
2306
|
`orderBy relation aggregate "${fieldName}._count" must be true`
|
|
2197
2307
|
);
|
|
2198
2308
|
}
|
|
2199
|
-
fieldSchemas[fieldName] =
|
|
2309
|
+
fieldSchemas[fieldName] = import_zod6.z.object({
|
|
2200
2310
|
_count: sortEnum.optional()
|
|
2201
2311
|
}).strict().optional();
|
|
2202
2312
|
continue;
|
|
@@ -2207,17 +2317,11 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2207
2317
|
);
|
|
2208
2318
|
fieldSchemas[fieldName] = nested;
|
|
2209
2319
|
}
|
|
2210
|
-
const
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
(k) => v[k] !== void 0
|
|
2214
|
-
),
|
|
2215
|
-
{ message: "orderBy must specify at least one field" }
|
|
2320
|
+
const singleSchema = strictObjectRequiringOne(
|
|
2321
|
+
fieldSchemas,
|
|
2322
|
+
"orderBy must specify at least one field"
|
|
2216
2323
|
);
|
|
2217
|
-
return
|
|
2218
|
-
singleSchema,
|
|
2219
|
-
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))
|
|
2220
|
-
]).optional();
|
|
2324
|
+
return singleOrArraySchema(singleSchema).optional();
|
|
2221
2325
|
}
|
|
2222
2326
|
function buildTakeSchema(config) {
|
|
2223
2327
|
if (typeof config === "number") {
|
|
@@ -2227,7 +2331,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2227
2331
|
if (config <= 0) {
|
|
2228
2332
|
throw new ShapeError("take must be a positive integer");
|
|
2229
2333
|
}
|
|
2230
|
-
return
|
|
2334
|
+
return import_zod6.z.number().int().min(1).max(config).default(config);
|
|
2231
2335
|
}
|
|
2232
2336
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
2233
2337
|
throw new ShapeError("take config must be a number or { max, default? }");
|
|
@@ -2252,9 +2356,9 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2252
2356
|
if (config.default > config.max) {
|
|
2253
2357
|
throw new ShapeError("take.default cannot exceed take.max");
|
|
2254
2358
|
}
|
|
2255
|
-
return
|
|
2359
|
+
return import_zod6.z.number().int().min(1).max(config.max).default(config.default);
|
|
2256
2360
|
}
|
|
2257
|
-
return
|
|
2361
|
+
return import_zod6.z.number().int().min(1).max(config.max).optional();
|
|
2258
2362
|
}
|
|
2259
2363
|
function buildCursorFieldSchema(model, fieldName) {
|
|
2260
2364
|
const modelFields = typeMap[model];
|
|
@@ -2276,11 +2380,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2276
2380
|
`List field "${fieldName}" cannot be used in cursor`
|
|
2277
2381
|
);
|
|
2278
2382
|
}
|
|
2279
|
-
|
|
2280
|
-
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
2281
|
-
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
2282
|
-
}
|
|
2283
|
-
return base;
|
|
2383
|
+
return buildDirectScalarSchema(fieldMeta, enumMap, scalarBase);
|
|
2284
2384
|
}
|
|
2285
2385
|
function cursorConfigMatchesConstraint(cursorConfig, constraint) {
|
|
2286
2386
|
if (!(constraint.selector in cursorConfig))
|
|
@@ -2289,66 +2389,55 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2289
2389
|
if (constraint.fields.length === 1) {
|
|
2290
2390
|
return value === true;
|
|
2291
2391
|
}
|
|
2292
|
-
if (!
|
|
2392
|
+
if (!isPlainObject(value))
|
|
2293
2393
|
return false;
|
|
2294
2394
|
const keys = Object.keys(value);
|
|
2295
2395
|
if (keys.length !== constraint.fields.length)
|
|
2296
2396
|
return false;
|
|
2297
2397
|
return constraint.fields.every((field) => value[field] === true);
|
|
2298
2398
|
}
|
|
2299
|
-
function getUniqueConstraints(model) {
|
|
2300
|
-
const constraints = uniqueMap[model];
|
|
2301
|
-
if (constraints && constraints.length > 0) {
|
|
2302
|
-
return constraints;
|
|
2303
|
-
}
|
|
2304
|
-
const modelFields = typeMap[model];
|
|
2305
|
-
if (!modelFields) {
|
|
2306
|
-
throw new ShapeError(`Unknown model: ${model}`);
|
|
2307
|
-
}
|
|
2308
|
-
const inferred = [];
|
|
2309
|
-
for (const [fieldName, fieldMeta] of Object.entries(modelFields)) {
|
|
2310
|
-
if (fieldMeta.isRelation)
|
|
2311
|
-
continue;
|
|
2312
|
-
if (fieldMeta.isId || fieldMeta.isUnique) {
|
|
2313
|
-
inferred.push({
|
|
2314
|
-
selector: fieldName,
|
|
2315
|
-
fields: [fieldName]
|
|
2316
|
-
});
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
return inferred;
|
|
2320
|
-
}
|
|
2321
2399
|
function buildCursorSchema(model, cursorConfig) {
|
|
2322
|
-
const constraints =
|
|
2400
|
+
const constraints = uniqueMap[model] ?? [];
|
|
2323
2401
|
if (constraints.length === 0) {
|
|
2324
2402
|
throw new ShapeError(
|
|
2325
2403
|
`cursor on model "${model}" requires at least one unique constraint`
|
|
2326
2404
|
);
|
|
2327
2405
|
}
|
|
2328
|
-
const matching = constraints.
|
|
2406
|
+
const matching = constraints.filter(
|
|
2329
2407
|
(constraint) => cursorConfigMatchesConstraint(cursorConfig, constraint)
|
|
2330
2408
|
);
|
|
2331
|
-
if (
|
|
2409
|
+
if (matching.length === 0) {
|
|
2332
2410
|
throw new ShapeError(
|
|
2333
|
-
`cursor on model "${model}" must
|
|
2411
|
+
`cursor on model "${model}" must match a unique selector: ${formatUniqueConstraints(constraints)}`
|
|
2334
2412
|
);
|
|
2335
2413
|
}
|
|
2414
|
+
const coveredKeys = new Set(matching.map((c) => c.selector));
|
|
2415
|
+
for (const key of Object.keys(cursorConfig)) {
|
|
2416
|
+
if (!coveredKeys.has(key)) {
|
|
2417
|
+
throw new ShapeError(
|
|
2418
|
+
`cursor field "${key}" on model "${model}" does not match any unique selector. Unique selectors: ${formatUniqueConstraints(constraints)}`
|
|
2419
|
+
);
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2336
2422
|
const fieldSchemas = {};
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2423
|
+
for (const constraint of matching) {
|
|
2424
|
+
if (constraint.fields.length === 1) {
|
|
2425
|
+
fieldSchemas[constraint.selector] = buildCursorFieldSchema(
|
|
2426
|
+
model,
|
|
2427
|
+
constraint.fields[0]
|
|
2428
|
+
).optional();
|
|
2429
|
+
} else {
|
|
2430
|
+
const nestedSchemas = {};
|
|
2431
|
+
for (const field of constraint.fields) {
|
|
2432
|
+
nestedSchemas[field] = buildCursorFieldSchema(model, field);
|
|
2433
|
+
}
|
|
2434
|
+
fieldSchemas[constraint.selector] = import_zod6.z.object(nestedSchemas).strict().optional();
|
|
2346
2435
|
}
|
|
2347
|
-
fieldSchemas[matching.selector] = import_zod5.z.object(nestedSchemas).strict().optional();
|
|
2348
2436
|
}
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2437
|
+
const selectorKeys = matching.map((c) => c.selector);
|
|
2438
|
+
return strictObjectRequiringOne(
|
|
2439
|
+
fieldSchemas,
|
|
2440
|
+
`cursor must specify one of: ${selectorKeys.join(", ")}`
|
|
2352
2441
|
).optional();
|
|
2353
2442
|
}
|
|
2354
2443
|
function buildDistinctSchema(model, distinctConfig) {
|
|
@@ -2373,10 +2462,8 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2373
2462
|
);
|
|
2374
2463
|
allowedFields.add(fieldName);
|
|
2375
2464
|
}
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1)
|
|
2379
|
-
]).optional();
|
|
2465
|
+
const fieldEnum = import_zod6.z.enum([...allowedFields]);
|
|
2466
|
+
return import_zod6.z.union([fieldEnum, import_zod6.z.array(fieldEnum).min(1)]).optional();
|
|
2380
2467
|
}
|
|
2381
2468
|
function buildBySchema(model, byConfig) {
|
|
2382
2469
|
const modelFields = typeMap[model];
|
|
@@ -2409,7 +2496,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2409
2496
|
}
|
|
2410
2497
|
allowedFields.add(fieldName);
|
|
2411
2498
|
}
|
|
2412
|
-
return
|
|
2499
|
+
return import_zod6.z.array(import_zod6.z.enum([...allowedFields])).min(1);
|
|
2413
2500
|
}
|
|
2414
2501
|
function buildHavingSchema(model, havingConfig) {
|
|
2415
2502
|
const modelFields = typeMap[model];
|
|
@@ -2450,22 +2537,21 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2450
2537
|
).optional();
|
|
2451
2538
|
}
|
|
2452
2539
|
if (fieldMeta.type === "String") {
|
|
2453
|
-
opSchemas.mode =
|
|
2540
|
+
opSchemas.mode = import_zod6.z.enum(["default", "insensitive"]).optional();
|
|
2454
2541
|
}
|
|
2455
2542
|
const opKeys = Object.keys(opSchemas).filter((key) => key !== "mode");
|
|
2456
|
-
|
|
2543
|
+
const opShape = { ...opSchemas };
|
|
2544
|
+
const opObjSchema = import_zod6.z.object(opShape).strict().refine(
|
|
2457
2545
|
(v) => opKeys.some((k) => v[k] !== void 0),
|
|
2458
2546
|
{
|
|
2459
2547
|
message: `having field "${fieldName}" must specify at least one operator`
|
|
2460
2548
|
}
|
|
2461
|
-
)
|
|
2549
|
+
);
|
|
2550
|
+
fieldSchemas[fieldName] = opObjSchema.optional();
|
|
2462
2551
|
}
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
(k) => v[k] !== void 0
|
|
2467
|
-
),
|
|
2468
|
-
{ message: "having must specify at least one field" }
|
|
2552
|
+
return strictObjectRequiringOne(
|
|
2553
|
+
fieldSchemas,
|
|
2554
|
+
"having must specify at least one field"
|
|
2469
2555
|
).optional();
|
|
2470
2556
|
}
|
|
2471
2557
|
function buildAggregateFieldSchema(model, op, config) {
|
|
@@ -2474,47 +2560,45 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2474
2560
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2475
2561
|
requireConfigTrue(config, `${op} on model "${model}"`);
|
|
2476
2562
|
const allowedTypes = op === "_avg" || op === "_sum" ? NUMERIC_TYPES : COMPARABLE_TYPES;
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2563
|
+
return buildLiteralTrueSchema(
|
|
2564
|
+
Object.keys(config),
|
|
2565
|
+
`${op} must specify at least one field`,
|
|
2566
|
+
(fieldName) => {
|
|
2567
|
+
const fieldMeta = modelFields[fieldName];
|
|
2568
|
+
if (!fieldMeta)
|
|
2569
|
+
throw new ShapeError(
|
|
2570
|
+
`Unknown field "${fieldName}" on model "${model}" in ${op}`
|
|
2571
|
+
);
|
|
2572
|
+
if (fieldMeta.isRelation)
|
|
2573
|
+
throw new ShapeError(
|
|
2574
|
+
`Relation field "${fieldName}" cannot be used in ${op}`
|
|
2575
|
+
);
|
|
2576
|
+
if (fieldMeta.isList)
|
|
2577
|
+
throw new ShapeError(
|
|
2578
|
+
`List field "${fieldName}" cannot be used in ${op}`
|
|
2579
|
+
);
|
|
2580
|
+
if (!allowedTypes.has(fieldMeta.type)) {
|
|
2581
|
+
throw new ShapeError(
|
|
2582
|
+
`Field "${fieldName}" of type "${fieldMeta.type}" cannot be used in ${op}`
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2496
2585
|
}
|
|
2497
|
-
|
|
2498
|
-
}
|
|
2499
|
-
const aggregateFieldKeys = Object.keys(fieldSchemas);
|
|
2500
|
-
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2501
|
-
(v) => aggregateFieldKeys.some(
|
|
2502
|
-
(k) => v[k] !== void 0
|
|
2503
|
-
),
|
|
2504
|
-
{ message: `${op} must specify at least one field` }
|
|
2505
|
-
).optional();
|
|
2586
|
+
);
|
|
2506
2587
|
}
|
|
2507
2588
|
function buildCountFieldSchema(model, config, context) {
|
|
2508
2589
|
if (config === true) {
|
|
2509
|
-
return
|
|
2590
|
+
return import_zod6.z.literal(true).optional();
|
|
2510
2591
|
}
|
|
2511
2592
|
const modelFields = typeMap[model];
|
|
2512
2593
|
if (!modelFields)
|
|
2513
2594
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2514
2595
|
requireConfigTrue(config, `${context} on model "${model}"`);
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2596
|
+
return buildLiteralTrueSchema(
|
|
2597
|
+
Object.keys(config),
|
|
2598
|
+
`${context} must specify at least one field`,
|
|
2599
|
+
(fieldName) => {
|
|
2600
|
+
if (fieldName === "_all")
|
|
2601
|
+
return;
|
|
2518
2602
|
const fieldMeta = modelFields[fieldName];
|
|
2519
2603
|
if (!fieldMeta)
|
|
2520
2604
|
throw new ShapeError(
|
|
@@ -2525,45 +2609,30 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2525
2609
|
`Relation field "${fieldName}" cannot be used in ${context}`
|
|
2526
2610
|
);
|
|
2527
2611
|
}
|
|
2528
|
-
|
|
2529
|
-
}
|
|
2530
|
-
const countFieldKeys = Object.keys(fieldSchemas);
|
|
2531
|
-
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2532
|
-
(v) => countFieldKeys.some(
|
|
2533
|
-
(k) => v[k] !== void 0
|
|
2534
|
-
),
|
|
2535
|
-
{ message: `${context} must specify at least one field` }
|
|
2536
|
-
).optional();
|
|
2612
|
+
);
|
|
2537
2613
|
}
|
|
2538
2614
|
function buildCountSelectSchema(model, selectConfig) {
|
|
2539
2615
|
const modelFields = typeMap[model];
|
|
2540
2616
|
if (!modelFields)
|
|
2541
2617
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2542
2618
|
requireConfigTrue(selectConfig, `count select on model "${model}"`);
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2619
|
+
return buildLiteralTrueSchema(
|
|
2620
|
+
Object.keys(selectConfig),
|
|
2621
|
+
"count select must specify at least one field",
|
|
2622
|
+
(fieldName) => {
|
|
2623
|
+
if (fieldName === "_all")
|
|
2624
|
+
return;
|
|
2625
|
+
const fieldMeta = modelFields[fieldName];
|
|
2626
|
+
if (!fieldMeta)
|
|
2627
|
+
throw new ShapeError(
|
|
2628
|
+
`Unknown field "${fieldName}" on model "${model}" in count select`
|
|
2629
|
+
);
|
|
2630
|
+
if (fieldMeta.isRelation)
|
|
2631
|
+
throw new ShapeError(
|
|
2632
|
+
`Relation field "${fieldName}" cannot be used in count select`
|
|
2633
|
+
);
|
|
2548
2634
|
}
|
|
2549
|
-
|
|
2550
|
-
if (!fieldMeta)
|
|
2551
|
-
throw new ShapeError(
|
|
2552
|
-
`Unknown field "${fieldName}" on model "${model}" in count select`
|
|
2553
|
-
);
|
|
2554
|
-
if (fieldMeta.isRelation)
|
|
2555
|
-
throw new ShapeError(
|
|
2556
|
-
`Relation field "${fieldName}" cannot be used in count select`
|
|
2557
|
-
);
|
|
2558
|
-
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2559
|
-
}
|
|
2560
|
-
const countSelectKeys = Object.keys(fieldSchemas);
|
|
2561
|
-
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2562
|
-
(v) => countSelectKeys.some(
|
|
2563
|
-
(k) => v[k] !== void 0
|
|
2564
|
-
),
|
|
2565
|
-
{ message: "count select must specify at least one field" }
|
|
2566
|
-
).optional();
|
|
2635
|
+
);
|
|
2567
2636
|
}
|
|
2568
2637
|
return {
|
|
2569
2638
|
buildOrderBySchema,
|
|
@@ -2579,25 +2648,64 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2579
2648
|
}
|
|
2580
2649
|
|
|
2581
2650
|
// src/runtime/query-builder-projection.ts
|
|
2582
|
-
var
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2651
|
+
var import_zod7 = require("zod");
|
|
2652
|
+
|
|
2653
|
+
// src/shared/projection-defaults.ts
|
|
2654
|
+
function buildDefaultProjectionInput(config) {
|
|
2655
|
+
const result = {};
|
|
2656
|
+
for (const [key, value] of Object.entries(config)) {
|
|
2657
|
+
if (key === "_count") {
|
|
2658
|
+
result[key] = buildDefaultCountInput(
|
|
2659
|
+
value
|
|
2660
|
+
);
|
|
2661
|
+
continue;
|
|
2662
|
+
}
|
|
2663
|
+
if (value === true) {
|
|
2664
|
+
result[key] = true;
|
|
2665
|
+
} else {
|
|
2666
|
+
result[key] = buildRelationArgsSkeleton(value);
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
return result;
|
|
2670
|
+
}
|
|
2671
|
+
function buildRelationArgsSkeleton(config) {
|
|
2672
|
+
const skeleton = {};
|
|
2673
|
+
if (config.select) {
|
|
2674
|
+
skeleton.select = buildDefaultProjectionInput(config.select);
|
|
2675
|
+
}
|
|
2676
|
+
if (config.include) {
|
|
2677
|
+
skeleton.include = buildDefaultProjectionInput(config.include);
|
|
2678
|
+
}
|
|
2679
|
+
return skeleton;
|
|
2680
|
+
}
|
|
2681
|
+
function buildDefaultCountInput(config) {
|
|
2682
|
+
if (config === true)
|
|
2683
|
+
return true;
|
|
2684
|
+
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select)) {
|
|
2685
|
+
return true;
|
|
2686
|
+
}
|
|
2687
|
+
const selectObj = config.select;
|
|
2688
|
+
const result = {};
|
|
2689
|
+
for (const key of Object.keys(selectObj)) {
|
|
2690
|
+
result[key] = true;
|
|
2691
|
+
}
|
|
2692
|
+
return { select: result };
|
|
2693
|
+
}
|
|
2694
|
+
function buildDefaultProjectionBody(shape) {
|
|
2695
|
+
if (shape.select) {
|
|
2696
|
+
return { select: buildDefaultProjectionInput(shape.select) };
|
|
2697
|
+
}
|
|
2698
|
+
if (shape.include) {
|
|
2699
|
+
return { include: buildDefaultProjectionInput(shape.include) };
|
|
2700
|
+
}
|
|
2701
|
+
return {};
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// src/runtime/query-builder-projection.ts
|
|
2705
|
+
var KNOWN_NESTED_KEYS = {
|
|
2706
|
+
include: /* @__PURE__ */ new Set(["where", "include", "select", "orderBy", "cursor", "take", "skip"]),
|
|
2707
|
+
select: /* @__PURE__ */ new Set(["select", "include", "where", "orderBy", "cursor", "take", "skip"])
|
|
2708
|
+
};
|
|
2601
2709
|
var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
|
|
2602
2710
|
var MAX_PROJECTION_DEPTH = 10;
|
|
2603
2711
|
function validateNestedKeys(keys, allowed, context) {
|
|
@@ -2609,13 +2717,25 @@ function validateNestedKeys(keys, allowed, context) {
|
|
|
2609
2717
|
}
|
|
2610
2718
|
}
|
|
2611
2719
|
}
|
|
2612
|
-
function
|
|
2720
|
+
function hasDefinedKeys(v) {
|
|
2721
|
+
return Object.values(v).some((value) => value !== void 0);
|
|
2722
|
+
}
|
|
2723
|
+
function wrapRelationSchema(nestedObj, skeleton) {
|
|
2724
|
+
const collapsed = nestedObj.transform(
|
|
2725
|
+
(v) => isPlainObject(v) && !hasDefinedKeys(v) ? true : v
|
|
2726
|
+
);
|
|
2727
|
+
return import_zod7.z.preprocess(
|
|
2728
|
+
(v) => v === true ? deepClone(skeleton) : v,
|
|
2729
|
+
collapsed
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
2613
2733
|
function buildIncludeCountSchema(model, config) {
|
|
2614
2734
|
const modelFields = typeMap[model];
|
|
2615
2735
|
if (!modelFields)
|
|
2616
2736
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2617
2737
|
if (config === true) {
|
|
2618
|
-
return { schema:
|
|
2738
|
+
return { schema: import_zod7.z.literal(true).optional(), forcedCountWhere: {} };
|
|
2619
2739
|
}
|
|
2620
2740
|
if (!isPlainObject(config) || !("select" in config)) {
|
|
2621
2741
|
throw new ShapeError(
|
|
@@ -2651,273 +2771,175 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
|
|
|
2651
2771
|
if (!fieldMeta.isList)
|
|
2652
2772
|
throw new ShapeError(`Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`);
|
|
2653
2773
|
if (fieldConfig === true) {
|
|
2654
|
-
countSelectFields[fieldName] =
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
`Empty config for _count.select.${fieldName} on model "${model}". Use true or { where: { ... } }.`
|
|
2659
|
-
);
|
|
2660
|
-
}
|
|
2661
|
-
validateNestedKeys(
|
|
2662
|
-
Object.keys(fieldConfig),
|
|
2663
|
-
KNOWN_COUNT_SELECT_ENTRY_KEYS,
|
|
2664
|
-
`_count.select.${fieldName} on model "${model}"`
|
|
2665
|
-
);
|
|
2666
|
-
if (fieldConfig.where) {
|
|
2667
|
-
const relatedType = fieldMeta.type;
|
|
2668
|
-
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2669
|
-
relatedType,
|
|
2670
|
-
fieldConfig.where
|
|
2671
|
-
);
|
|
2672
|
-
const nestedSchemas = {};
|
|
2673
|
-
if (whereSchema)
|
|
2674
|
-
nestedSchemas["where"] = whereSchema;
|
|
2675
|
-
const nestedObj = import_zod6.z.object(nestedSchemas).strict();
|
|
2676
|
-
countSelectFields[fieldName] = import_zod6.z.union([import_zod6.z.literal(true), nestedObj]).optional();
|
|
2677
|
-
if (hasWhereForced(forced)) {
|
|
2678
|
-
forcedCountWhere[fieldName] = forced;
|
|
2679
|
-
}
|
|
2680
|
-
} else {
|
|
2681
|
-
countSelectFields[fieldName] = import_zod6.z.literal(true).optional();
|
|
2682
|
-
}
|
|
2683
|
-
} else {
|
|
2774
|
+
countSelectFields[fieldName] = import_zod7.z.literal(true).optional();
|
|
2775
|
+
continue;
|
|
2776
|
+
}
|
|
2777
|
+
if (!isPlainObject(fieldConfig)) {
|
|
2684
2778
|
throw new ShapeError(
|
|
2685
2779
|
`Invalid config for _count.select.${fieldName} on model "${model}". Expected true or { where: { ... } }`
|
|
2686
2780
|
);
|
|
2687
2781
|
}
|
|
2782
|
+
if (Object.keys(fieldConfig).length === 0) {
|
|
2783
|
+
throw new ShapeError(
|
|
2784
|
+
`Empty config for _count.select.${fieldName} on model "${model}". Use true or { where: { ... } }.`
|
|
2785
|
+
);
|
|
2786
|
+
}
|
|
2787
|
+
validateNestedKeys(
|
|
2788
|
+
Object.keys(fieldConfig),
|
|
2789
|
+
KNOWN_COUNT_SELECT_ENTRY_KEYS,
|
|
2790
|
+
`_count.select.${fieldName} on model "${model}"`
|
|
2791
|
+
);
|
|
2792
|
+
if (fieldConfig.where) {
|
|
2793
|
+
const relatedType = fieldMeta.type;
|
|
2794
|
+
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2795
|
+
relatedType,
|
|
2796
|
+
fieldConfig.where
|
|
2797
|
+
);
|
|
2798
|
+
const nestedSchemas = {};
|
|
2799
|
+
if (whereSchema)
|
|
2800
|
+
nestedSchemas["where"] = whereSchema;
|
|
2801
|
+
const nestedObj = import_zod7.z.object(nestedSchemas).strict();
|
|
2802
|
+
countSelectFields[fieldName] = import_zod7.z.union([import_zod7.z.literal(true), nestedObj]).optional();
|
|
2803
|
+
if (hasWhereForced(forced)) {
|
|
2804
|
+
forcedCountWhere[fieldName] = forced;
|
|
2805
|
+
}
|
|
2806
|
+
} else {
|
|
2807
|
+
countSelectFields[fieldName] = import_zod7.z.literal(true).optional();
|
|
2808
|
+
}
|
|
2688
2809
|
}
|
|
2689
|
-
const
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
{ message: "_count.select must specify at least one field" }
|
|
2810
|
+
const selectSchema = strictObjectRequiringOne(
|
|
2811
|
+
countSelectFields,
|
|
2812
|
+
"_count.select must specify at least one field"
|
|
2693
2813
|
);
|
|
2694
2814
|
return {
|
|
2695
|
-
schema:
|
|
2815
|
+
schema: import_zod7.z.object({ select: selectSchema }).strict().optional(),
|
|
2696
2816
|
forcedCountWhere
|
|
2697
2817
|
};
|
|
2698
2818
|
}
|
|
2699
|
-
function
|
|
2819
|
+
function buildNestedRelSchemas(relatedType, config, depth) {
|
|
2820
|
+
const nestedSchemas = {};
|
|
2821
|
+
const relForced = {};
|
|
2822
|
+
if (config.where) {
|
|
2823
|
+
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2824
|
+
relatedType,
|
|
2825
|
+
config.where
|
|
2826
|
+
);
|
|
2827
|
+
if (whereSchema)
|
|
2828
|
+
nestedSchemas["where"] = whereSchema;
|
|
2829
|
+
if (hasWhereForced(forced))
|
|
2830
|
+
relForced.where = forced;
|
|
2831
|
+
}
|
|
2832
|
+
if (config.include) {
|
|
2833
|
+
const nested = buildProjectionSchema("include", relatedType, config.include, depth + 1);
|
|
2834
|
+
nestedSchemas["include"] = nested.schema;
|
|
2835
|
+
if (Object.keys(nested.forcedTree).length > 0)
|
|
2836
|
+
relForced.include = nested.forcedTree;
|
|
2837
|
+
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2838
|
+
relForced._countWhere = nested.forcedCountWhere;
|
|
2839
|
+
relForced._countWherePlacement = "include";
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
if (config.select) {
|
|
2843
|
+
const nested = buildProjectionSchema("select", relatedType, config.select, depth + 1);
|
|
2844
|
+
nestedSchemas["select"] = nested.schema;
|
|
2845
|
+
if (Object.keys(nested.forcedTree).length > 0)
|
|
2846
|
+
relForced.select = nested.forcedTree;
|
|
2847
|
+
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2848
|
+
relForced._countWhere = nested.forcedCountWhere;
|
|
2849
|
+
relForced._countWherePlacement = "select";
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
if (config.orderBy) {
|
|
2853
|
+
nestedSchemas["orderBy"] = deps.buildOrderBySchema(relatedType, config.orderBy);
|
|
2854
|
+
}
|
|
2855
|
+
if (config.cursor) {
|
|
2856
|
+
nestedSchemas["cursor"] = deps.buildCursorSchema(relatedType, config.cursor);
|
|
2857
|
+
}
|
|
2858
|
+
if (config.take) {
|
|
2859
|
+
nestedSchemas["take"] = deps.buildTakeSchema(config.take);
|
|
2860
|
+
}
|
|
2861
|
+
if (config.skip) {
|
|
2862
|
+
nestedSchemas["skip"] = import_zod7.z.number().int().min(0).optional();
|
|
2863
|
+
}
|
|
2864
|
+
return { nestedSchemas, relForced };
|
|
2865
|
+
}
|
|
2866
|
+
function buildProjectionSchema(mode, model, projectionConfig, depth) {
|
|
2700
2867
|
const currentDepth = depth ?? 0;
|
|
2701
2868
|
if (currentDepth > MAX_PROJECTION_DEPTH) {
|
|
2702
2869
|
throw new ShapeError(
|
|
2703
|
-
|
|
2870
|
+
`${mode === "include" ? "Include" : "Select"} schema for model "${model}" exceeds maximum nesting depth (${MAX_PROJECTION_DEPTH}). Check for circular relation references in the shape.`
|
|
2704
2871
|
);
|
|
2705
2872
|
}
|
|
2706
|
-
if (Object.keys(
|
|
2873
|
+
if (Object.keys(projectionConfig).length === 0) {
|
|
2707
2874
|
throw new ShapeError(
|
|
2708
|
-
`Empty
|
|
2875
|
+
`Empty ${mode} config on model "${model}". Define at least one ${mode === "include" ? "relation" : "field"}.`
|
|
2709
2876
|
);
|
|
2710
2877
|
}
|
|
2711
2878
|
const modelFields = typeMap[model];
|
|
2712
2879
|
if (!modelFields)
|
|
2713
2880
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2881
|
+
const allowedNestedKeys = KNOWN_NESTED_KEYS[mode];
|
|
2714
2882
|
const fieldSchemas = {};
|
|
2715
2883
|
const forcedTree = {};
|
|
2716
2884
|
let topLevelForcedCountWhere = {};
|
|
2717
|
-
for (const [
|
|
2718
|
-
if (
|
|
2885
|
+
for (const [fieldName, config] of Object.entries(projectionConfig)) {
|
|
2886
|
+
if (fieldName === "_count") {
|
|
2719
2887
|
const countResult = buildIncludeCountSchema(model, config);
|
|
2720
2888
|
fieldSchemas["_count"] = countResult.schema;
|
|
2721
2889
|
topLevelForcedCountWhere = countResult.forcedCountWhere;
|
|
2722
2890
|
continue;
|
|
2723
2891
|
}
|
|
2724
|
-
const fieldMeta = modelFields[
|
|
2892
|
+
const fieldMeta = modelFields[fieldName];
|
|
2725
2893
|
if (!fieldMeta)
|
|
2726
|
-
throw new ShapeError(`Unknown field "${
|
|
2727
|
-
if (!fieldMeta.isRelation)
|
|
2728
|
-
throw new ShapeError(`Field "${
|
|
2894
|
+
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
2895
|
+
if (mode === "include" && !fieldMeta.isRelation) {
|
|
2896
|
+
throw new ShapeError(`Field "${fieldName}" is not a relation on model "${model}"`);
|
|
2897
|
+
}
|
|
2729
2898
|
if (config === true) {
|
|
2730
|
-
fieldSchemas[
|
|
2731
|
-
} else {
|
|
2732
|
-
validateNestedKeys(
|
|
2733
|
-
Object.keys(config),
|
|
2734
|
-
KNOWN_NESTED_INCLUDE_KEYS,
|
|
2735
|
-
`nested include for "${relName}" on model "${model}"`
|
|
2736
|
-
);
|
|
2737
|
-
if (config.select && config.include) {
|
|
2738
|
-
throw new ShapeError(`Nested include for "${relName}" cannot define both "select" and "include".`);
|
|
2739
|
-
}
|
|
2740
|
-
if (!fieldMeta.isList) {
|
|
2741
|
-
if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
|
|
2742
|
-
throw new ShapeError(
|
|
2743
|
-
`Relation "${relName}" on model "${model}" is to-one. Only "include" and "select" are supported for to-one nested reads, not where/orderBy/cursor/take/skip.`
|
|
2744
|
-
);
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
const nestedSchemas = {};
|
|
2748
|
-
const relForced = {};
|
|
2749
|
-
if (config.where) {
|
|
2750
|
-
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2751
|
-
fieldMeta.type,
|
|
2752
|
-
config.where
|
|
2753
|
-
);
|
|
2754
|
-
if (whereSchema)
|
|
2755
|
-
nestedSchemas["where"] = whereSchema;
|
|
2756
|
-
if (hasWhereForced(forced))
|
|
2757
|
-
relForced.where = forced;
|
|
2758
|
-
}
|
|
2759
|
-
if (config.include) {
|
|
2760
|
-
const nested = buildIncludeSchema(fieldMeta.type, config.include, currentDepth + 1);
|
|
2761
|
-
nestedSchemas["include"] = nested.schema;
|
|
2762
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2763
|
-
relForced.include = nested.forcedTree;
|
|
2764
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2765
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2766
|
-
relForced._countWherePlacement = "include";
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
if (config.select) {
|
|
2770
|
-
const nested = buildSelectSchema(fieldMeta.type, config.select, currentDepth + 1);
|
|
2771
|
-
nestedSchemas["select"] = nested.schema;
|
|
2772
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2773
|
-
relForced.select = nested.forcedTree;
|
|
2774
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2775
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2776
|
-
relForced._countWherePlacement = "select";
|
|
2777
|
-
}
|
|
2778
|
-
}
|
|
2779
|
-
if (config.orderBy) {
|
|
2780
|
-
nestedSchemas["orderBy"] = deps.buildOrderBySchema(fieldMeta.type, config.orderBy);
|
|
2781
|
-
}
|
|
2782
|
-
if (config.cursor) {
|
|
2783
|
-
nestedSchemas["cursor"] = deps.buildCursorSchema(fieldMeta.type, config.cursor);
|
|
2784
|
-
}
|
|
2785
|
-
if (config.take) {
|
|
2786
|
-
nestedSchemas["take"] = deps.buildTakeSchema(config.take);
|
|
2787
|
-
}
|
|
2788
|
-
if (config.skip) {
|
|
2789
|
-
nestedSchemas["skip"] = import_zod6.z.number().int().min(0).optional();
|
|
2790
|
-
}
|
|
2791
|
-
const nestedObj = import_zod6.z.object(nestedSchemas).strict();
|
|
2792
|
-
fieldSchemas[relName] = import_zod6.z.union([import_zod6.z.literal(true), nestedObj]).optional();
|
|
2793
|
-
if (Object.keys(relForced).length > 0)
|
|
2794
|
-
forcedTree[relName] = relForced;
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
const includeFieldKeys = Object.keys(fieldSchemas);
|
|
2798
|
-
const baseSchema = import_zod6.z.object(fieldSchemas).strict();
|
|
2799
|
-
const schema = includeFieldKeys.length > 0 ? baseSchema.refine(
|
|
2800
|
-
(v) => includeFieldKeys.some((k) => v[k] !== void 0),
|
|
2801
|
-
{ message: "include must specify at least one field" }
|
|
2802
|
-
).optional() : baseSchema.optional();
|
|
2803
|
-
return {
|
|
2804
|
-
schema,
|
|
2805
|
-
forcedTree,
|
|
2806
|
-
forcedCountWhere: topLevelForcedCountWhere
|
|
2807
|
-
};
|
|
2808
|
-
}
|
|
2809
|
-
function buildSelectSchema(model, selectConfig, depth) {
|
|
2810
|
-
const currentDepth = depth ?? 0;
|
|
2811
|
-
if (currentDepth > MAX_PROJECTION_DEPTH) {
|
|
2812
|
-
throw new ShapeError(
|
|
2813
|
-
`Select schema for model "${model}" exceeds maximum nesting depth (${MAX_PROJECTION_DEPTH}). Check for circular relation references in the shape.`
|
|
2814
|
-
);
|
|
2815
|
-
}
|
|
2816
|
-
if (Object.keys(selectConfig).length === 0) {
|
|
2817
|
-
throw new ShapeError(
|
|
2818
|
-
`Empty select config on model "${model}". Define at least one field.`
|
|
2819
|
-
);
|
|
2820
|
-
}
|
|
2821
|
-
const modelFields = typeMap[model];
|
|
2822
|
-
if (!modelFields)
|
|
2823
|
-
throw new ShapeError(`Unknown model: ${model}`);
|
|
2824
|
-
const fieldSchemas = {};
|
|
2825
|
-
const forcedTree = {};
|
|
2826
|
-
let topLevelForcedCountWhere = {};
|
|
2827
|
-
for (const [fieldName, config] of Object.entries(selectConfig)) {
|
|
2828
|
-
if (fieldName === "_count") {
|
|
2829
|
-
const countResult = buildIncludeCountSchema(model, config);
|
|
2830
|
-
fieldSchemas["_count"] = countResult.schema;
|
|
2831
|
-
topLevelForcedCountWhere = countResult.forcedCountWhere;
|
|
2899
|
+
fieldSchemas[fieldName] = import_zod7.z.literal(true).optional();
|
|
2832
2900
|
continue;
|
|
2833
2901
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
`nested select for "${fieldName}" on model "${model}"`
|
|
2847
|
-
);
|
|
2848
|
-
if (config.select && config.include) {
|
|
2849
|
-
throw new ShapeError(`Nested select for "${fieldName}" cannot define both "select" and "include".`);
|
|
2850
|
-
}
|
|
2851
|
-
if (!fieldMeta.isList) {
|
|
2852
|
-
if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
|
|
2853
|
-
throw new ShapeError(
|
|
2854
|
-
`Relation "${fieldName}" on model "${model}" is to-one. Only "select" and "include" are supported for to-one nested reads, not where/orderBy/cursor/take/skip.`
|
|
2855
|
-
);
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
const nestedSchemas = {};
|
|
2859
|
-
const relForced = {};
|
|
2860
|
-
if (config.select) {
|
|
2861
|
-
const nested = buildSelectSchema(fieldMeta.type, config.select, currentDepth + 1);
|
|
2862
|
-
nestedSchemas["select"] = nested.schema;
|
|
2863
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2864
|
-
relForced.select = nested.forcedTree;
|
|
2865
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2866
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2867
|
-
relForced._countWherePlacement = "select";
|
|
2868
|
-
}
|
|
2869
|
-
}
|
|
2870
|
-
if (config.include) {
|
|
2871
|
-
const nested = buildIncludeSchema(fieldMeta.type, config.include, currentDepth + 1);
|
|
2872
|
-
nestedSchemas["include"] = nested.schema;
|
|
2873
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2874
|
-
relForced.include = nested.forcedTree;
|
|
2875
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2876
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2877
|
-
relForced._countWherePlacement = "include";
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2880
|
-
if (config.where) {
|
|
2881
|
-
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2882
|
-
fieldMeta.type,
|
|
2883
|
-
config.where
|
|
2902
|
+
if (mode === "select" && !fieldMeta.isRelation) {
|
|
2903
|
+
throw new ShapeError(`Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`);
|
|
2904
|
+
}
|
|
2905
|
+
const contextLabel = `nested ${mode} for "${fieldName}" on model "${model}"`;
|
|
2906
|
+
validateNestedKeys(Object.keys(config), allowedNestedKeys, contextLabel);
|
|
2907
|
+
if (config.select && config.include) {
|
|
2908
|
+
throw new ShapeError(`Nested ${mode} for "${fieldName}" cannot define both "select" and "include".`);
|
|
2909
|
+
}
|
|
2910
|
+
if (!fieldMeta.isList) {
|
|
2911
|
+
if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
|
|
2912
|
+
throw new ShapeError(
|
|
2913
|
+
`Relation "${fieldName}" on model "${model}" is to-one. Only "select" and "include" are supported for to-one nested reads, not where/orderBy/cursor/take/skip.`
|
|
2884
2914
|
);
|
|
2885
|
-
if (whereSchema)
|
|
2886
|
-
nestedSchemas["where"] = whereSchema;
|
|
2887
|
-
if (hasWhereForced(forced))
|
|
2888
|
-
relForced.where = forced;
|
|
2889
|
-
}
|
|
2890
|
-
if (config.orderBy) {
|
|
2891
|
-
nestedSchemas["orderBy"] = deps.buildOrderBySchema(fieldMeta.type, config.orderBy);
|
|
2892
|
-
}
|
|
2893
|
-
if (config.cursor) {
|
|
2894
|
-
nestedSchemas["cursor"] = deps.buildCursorSchema(fieldMeta.type, config.cursor);
|
|
2895
|
-
}
|
|
2896
|
-
if (config.take) {
|
|
2897
|
-
nestedSchemas["take"] = deps.buildTakeSchema(config.take);
|
|
2898
|
-
}
|
|
2899
|
-
if (config.skip) {
|
|
2900
|
-
nestedSchemas["skip"] = import_zod6.z.number().int().min(0).optional();
|
|
2901
2915
|
}
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2916
|
+
}
|
|
2917
|
+
const { nestedSchemas, relForced } = buildNestedRelSchemas(fieldMeta.type, config, currentDepth);
|
|
2918
|
+
const nestedObj = import_zod7.z.object(nestedSchemas).strict();
|
|
2919
|
+
fieldSchemas[fieldName] = wrapRelationSchema(
|
|
2920
|
+
nestedObj,
|
|
2921
|
+
buildRelationArgsSkeleton(config)
|
|
2922
|
+
).optional();
|
|
2923
|
+
if (Object.keys(relForced).length > 0)
|
|
2924
|
+
forcedTree[fieldName] = relForced;
|
|
2925
|
+
}
|
|
2926
|
+
const schema = Object.keys(fieldSchemas).length > 0 ? strictObjectRequiringOne(
|
|
2927
|
+
fieldSchemas,
|
|
2928
|
+
`${mode} must specify at least one field`
|
|
2929
|
+
).optional() : import_zod7.z.object(fieldSchemas).strict().optional();
|
|
2914
2930
|
return {
|
|
2915
2931
|
schema,
|
|
2916
2932
|
forcedTree,
|
|
2917
2933
|
forcedCountWhere: topLevelForcedCountWhere
|
|
2918
2934
|
};
|
|
2919
2935
|
}
|
|
2920
|
-
|
|
2936
|
+
function buildIncludeSchema(model, includeConfig, depth) {
|
|
2937
|
+
return buildProjectionSchema("include", model, includeConfig, depth);
|
|
2938
|
+
}
|
|
2939
|
+
function buildSelectSchema(model, selectConfig, depth) {
|
|
2940
|
+
return buildProjectionSchema("select", model, selectConfig, depth);
|
|
2941
|
+
}
|
|
2942
|
+
return { buildIncludeSchema, buildSelectSchema, buildIncludeCountSchema, buildProjectionSchema };
|
|
2921
2943
|
}
|
|
2922
2944
|
|
|
2923
2945
|
// src/shared/operation-shape-keys.ts
|
|
@@ -2927,7 +2949,6 @@ var OPERATION_SHAPE_KEYS = {
|
|
|
2927
2949
|
findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2928
2950
|
findUnique: ["where", "include", "select"],
|
|
2929
2951
|
findUniqueOrThrow: ["where", "include", "select"],
|
|
2930
|
-
findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2931
2952
|
count: ["where", "select", "cursor", "orderBy", "skip", "take"],
|
|
2932
2953
|
aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
|
|
2933
2954
|
groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
|
|
@@ -2962,6 +2983,99 @@ var MUTATION_SHAPE_KEYS = {
|
|
|
2962
2983
|
delete: new Set(OPERATION_SHAPE_KEYS.delete),
|
|
2963
2984
|
deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
|
|
2964
2985
|
};
|
|
2986
|
+
var MUTATION_OPERATION_SPECS = {
|
|
2987
|
+
create: {
|
|
2988
|
+
bodyKeysBase: ["data"],
|
|
2989
|
+
bodyKeysProjection: ["data", "select", "include"],
|
|
2990
|
+
shapeKeysBase: ["data"],
|
|
2991
|
+
shapeKeysProjection: ["data", "select", "include"],
|
|
2992
|
+
supportsProjection: true
|
|
2993
|
+
},
|
|
2994
|
+
createMany: {
|
|
2995
|
+
bodyKeysBase: ["data", "skipDuplicates"],
|
|
2996
|
+
bodyKeysProjection: ["data", "select", "include", "skipDuplicates"],
|
|
2997
|
+
shapeKeysBase: ["data"],
|
|
2998
|
+
shapeKeysProjection: ["data"],
|
|
2999
|
+
supportsProjection: false
|
|
3000
|
+
},
|
|
3001
|
+
createManyAndReturn: {
|
|
3002
|
+
bodyKeysBase: ["data", "skipDuplicates"],
|
|
3003
|
+
bodyKeysProjection: ["data", "select", "include", "skipDuplicates"],
|
|
3004
|
+
shapeKeysBase: ["data"],
|
|
3005
|
+
shapeKeysProjection: ["data", "select", "include"],
|
|
3006
|
+
supportsProjection: true
|
|
3007
|
+
},
|
|
3008
|
+
update: {
|
|
3009
|
+
bodyKeysBase: ["data", "where"],
|
|
3010
|
+
bodyKeysProjection: ["data", "where", "select", "include"],
|
|
3011
|
+
shapeKeysBase: ["data", "where"],
|
|
3012
|
+
shapeKeysProjection: ["data", "where", "select", "include"],
|
|
3013
|
+
supportsProjection: true
|
|
3014
|
+
},
|
|
3015
|
+
updateMany: {
|
|
3016
|
+
bodyKeysBase: ["data", "where"],
|
|
3017
|
+
bodyKeysProjection: ["data", "where"],
|
|
3018
|
+
shapeKeysBase: ["data", "where"],
|
|
3019
|
+
shapeKeysProjection: ["data", "where"],
|
|
3020
|
+
supportsProjection: false
|
|
3021
|
+
},
|
|
3022
|
+
updateManyAndReturn: {
|
|
3023
|
+
bodyKeysBase: ["data", "where"],
|
|
3024
|
+
bodyKeysProjection: ["data", "where", "select", "include"],
|
|
3025
|
+
shapeKeysBase: ["data", "where"],
|
|
3026
|
+
shapeKeysProjection: ["data", "where", "select", "include"],
|
|
3027
|
+
supportsProjection: true
|
|
3028
|
+
},
|
|
3029
|
+
upsert: {
|
|
3030
|
+
bodyKeysBase: ["where", "create", "update", "select", "include"],
|
|
3031
|
+
bodyKeysProjection: ["where", "create", "update", "select", "include"],
|
|
3032
|
+
shapeKeysBase: ["where", "create", "update", "select", "include"],
|
|
3033
|
+
shapeKeysProjection: ["where", "create", "update", "select", "include"],
|
|
3034
|
+
supportsProjection: true
|
|
3035
|
+
},
|
|
3036
|
+
delete: {
|
|
3037
|
+
bodyKeysBase: ["where"],
|
|
3038
|
+
bodyKeysProjection: ["where", "select", "include"],
|
|
3039
|
+
shapeKeysBase: ["where"],
|
|
3040
|
+
shapeKeysProjection: ["where", "select", "include"],
|
|
3041
|
+
supportsProjection: true
|
|
3042
|
+
},
|
|
3043
|
+
deleteMany: {
|
|
3044
|
+
bodyKeysBase: ["where"],
|
|
3045
|
+
bodyKeysProjection: ["where"],
|
|
3046
|
+
shapeKeysBase: ["where"],
|
|
3047
|
+
shapeKeysProjection: ["where"],
|
|
3048
|
+
supportsProjection: false
|
|
3049
|
+
}
|
|
3050
|
+
};
|
|
3051
|
+
var bodyKeyCache = /* @__PURE__ */ new Map();
|
|
3052
|
+
var shapeKeyCache = /* @__PURE__ */ new Map();
|
|
3053
|
+
function getAllowedBodyKeys(method, withProjection) {
|
|
3054
|
+
const cacheKey = `${method}\0${withProjection ? "p" : "b"}`;
|
|
3055
|
+
const cached = bodyKeyCache.get(cacheKey);
|
|
3056
|
+
if (cached)
|
|
3057
|
+
return cached;
|
|
3058
|
+
const spec = MUTATION_OPERATION_SPECS[method];
|
|
3059
|
+
if (!spec)
|
|
3060
|
+
throw new Error(`Unknown mutation method "${method}"`);
|
|
3061
|
+
const keys = withProjection && spec.supportsProjection ? spec.bodyKeysProjection : spec.bodyKeysBase;
|
|
3062
|
+
const set = new Set(keys);
|
|
3063
|
+
bodyKeyCache.set(cacheKey, set);
|
|
3064
|
+
return set;
|
|
3065
|
+
}
|
|
3066
|
+
function getAllowedShapeKeys(method, withProjection) {
|
|
3067
|
+
const cacheKey = `${method}\0${withProjection ? "p" : "b"}`;
|
|
3068
|
+
const cached = shapeKeyCache.get(cacheKey);
|
|
3069
|
+
if (cached)
|
|
3070
|
+
return cached;
|
|
3071
|
+
const spec = MUTATION_OPERATION_SPECS[method];
|
|
3072
|
+
if (!spec)
|
|
3073
|
+
throw new Error(`Unknown mutation method "${method}"`);
|
|
3074
|
+
const keys = withProjection && spec.supportsProjection ? spec.shapeKeysProjection : spec.shapeKeysBase;
|
|
3075
|
+
const set = new Set(keys);
|
|
3076
|
+
shapeKeyCache.set(cacheKey, set);
|
|
3077
|
+
return set;
|
|
3078
|
+
}
|
|
2965
3079
|
|
|
2966
3080
|
// src/runtime/query-builder.ts
|
|
2967
3081
|
var METHOD_ALLOWED_ARGS = READ_METHOD_ALLOWED_ARGS;
|
|
@@ -3062,6 +3176,90 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3062
3176
|
}
|
|
3063
3177
|
return shapeOrFn;
|
|
3064
3178
|
}
|
|
3179
|
+
function buildGroupByOrderBySchema(model, orderBy, by, sortEnum) {
|
|
3180
|
+
const bySet = new Set(by);
|
|
3181
|
+
if (orderBy === true) {
|
|
3182
|
+
const groupByOrderFields2 = {};
|
|
3183
|
+
for (const field of by) {
|
|
3184
|
+
groupByOrderFields2[field] = sortEnum.optional();
|
|
3185
|
+
}
|
|
3186
|
+
groupByOrderFields2._count = sortEnum.optional();
|
|
3187
|
+
const singleSchema2 = strictObjectRequiringOne(
|
|
3188
|
+
groupByOrderFields2,
|
|
3189
|
+
"orderBy must specify at least one field"
|
|
3190
|
+
);
|
|
3191
|
+
return import_zod8.z.union([
|
|
3192
|
+
singleSchema2,
|
|
3193
|
+
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(singleSchema2).min(1))
|
|
3194
|
+
]).optional();
|
|
3195
|
+
}
|
|
3196
|
+
if (!isPlainObject(orderBy)) {
|
|
3197
|
+
throw new ShapeError(
|
|
3198
|
+
`groupBy orderBy shape on model "${model}" must be true or an object of fields`
|
|
3199
|
+
);
|
|
3200
|
+
}
|
|
3201
|
+
if (Object.keys(orderBy).length === 0) {
|
|
3202
|
+
throw new ShapeError(
|
|
3203
|
+
`Empty groupBy orderBy config on model "${model}". Define at least one field.`
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
const groupByOrderFields = {};
|
|
3207
|
+
for (const [fieldName, config] of Object.entries(orderBy)) {
|
|
3208
|
+
if (fieldName === "_count") {
|
|
3209
|
+
if (config === true) {
|
|
3210
|
+
groupByOrderFields._count = sortEnum.optional();
|
|
3211
|
+
} else if (isPlainObject(config)) {
|
|
3212
|
+
if (Object.keys(config).length === 0) {
|
|
3213
|
+
throw new ShapeError(
|
|
3214
|
+
`Empty groupBy orderBy "_count" config on model "${model}". Define at least one by-field.`
|
|
3215
|
+
);
|
|
3216
|
+
}
|
|
3217
|
+
const countFields = {};
|
|
3218
|
+
for (const [countField, countConfig] of Object.entries(config)) {
|
|
3219
|
+
if (countConfig !== true) {
|
|
3220
|
+
throw new ShapeError(
|
|
3221
|
+
`groupBy orderBy "_count.${countField}" config on model "${model}" must be true`
|
|
3222
|
+
);
|
|
3223
|
+
}
|
|
3224
|
+
if (!bySet.has(countField)) {
|
|
3225
|
+
throw new ShapeError(
|
|
3226
|
+
`orderBy _count field "${countField}" must be included in "by" for groupBy`
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3229
|
+
countFields[countField] = sortEnum.optional();
|
|
3230
|
+
}
|
|
3231
|
+
groupByOrderFields._count = strictObjectRequiringOne(
|
|
3232
|
+
countFields,
|
|
3233
|
+
"orderBy._count must specify at least one field"
|
|
3234
|
+
).optional();
|
|
3235
|
+
} else {
|
|
3236
|
+
throw new ShapeError(
|
|
3237
|
+
`groupBy orderBy "_count" config on model "${model}" must be true or an object of by-fields`
|
|
3238
|
+
);
|
|
3239
|
+
}
|
|
3240
|
+
continue;
|
|
3241
|
+
}
|
|
3242
|
+
if (config !== true) {
|
|
3243
|
+
throw new ShapeError(
|
|
3244
|
+
`groupBy orderBy field "${fieldName}" config on model "${model}" must be true`
|
|
3245
|
+
);
|
|
3246
|
+
}
|
|
3247
|
+
if (!bySet.has(fieldName)) {
|
|
3248
|
+
throw new ShapeError(
|
|
3249
|
+
`orderBy field "${fieldName}" must be included in "by" for groupBy`
|
|
3250
|
+
);
|
|
3251
|
+
}
|
|
3252
|
+
groupByOrderFields[fieldName] = sortEnum.optional();
|
|
3253
|
+
}
|
|
3254
|
+
const singleSchema = strictObjectRequiringOne(
|
|
3255
|
+
groupByOrderFields,
|
|
3256
|
+
"orderBy must specify at least one field"
|
|
3257
|
+
);
|
|
3258
|
+
return import_zod8.z.union([
|
|
3259
|
+
singleSchema,
|
|
3260
|
+
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(singleSchema).min(1))
|
|
3261
|
+
]).optional();
|
|
3262
|
+
}
|
|
3065
3263
|
function buildShapeZodSchema(model, method, shape) {
|
|
3066
3264
|
validateShapeArgs(method, shape);
|
|
3067
3265
|
validateUniqueWhere(model, method, shape);
|
|
@@ -3101,73 +3299,19 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3101
3299
|
}
|
|
3102
3300
|
if (shape.orderBy) {
|
|
3103
3301
|
if (method === "groupBy" && shape.by) {
|
|
3104
|
-
const sortEnum =
|
|
3105
|
-
|
|
3302
|
+
const sortEnum = import_zod8.z.enum(["asc", "desc"]);
|
|
3303
|
+
schemaFields.orderBy = buildGroupByOrderBySchema(
|
|
3304
|
+
model,
|
|
3305
|
+
shape.orderBy,
|
|
3306
|
+
shape.by,
|
|
3307
|
+
sortEnum
|
|
3308
|
+
);
|
|
3309
|
+
} else {
|
|
3106
3310
|
if (shape.orderBy === true) {
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
groupByOrderFields[field] = sortEnum.optional();
|
|
3110
|
-
}
|
|
3111
|
-
groupByOrderFields._count = sortEnum.optional();
|
|
3112
|
-
const fieldKeys = Object.keys(groupByOrderFields);
|
|
3113
|
-
const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
|
|
3114
|
-
(v) => fieldKeys.some(
|
|
3115
|
-
(k) => v[k] !== void 0
|
|
3116
|
-
),
|
|
3117
|
-
{ message: "orderBy must specify at least one field" }
|
|
3118
|
-
);
|
|
3119
|
-
schemaFields.orderBy = import_zod7.z.union([
|
|
3120
|
-
singleSchema,
|
|
3121
|
-
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3122
|
-
]).optional();
|
|
3123
|
-
} else {
|
|
3124
|
-
const groupByOrderFields = {};
|
|
3125
|
-
for (const [fieldName, config] of Object.entries(shape.orderBy)) {
|
|
3126
|
-
if (fieldName === "_count") {
|
|
3127
|
-
if (config === true) {
|
|
3128
|
-
groupByOrderFields._count = sortEnum.optional();
|
|
3129
|
-
} else if (typeof config === "object" && config !== null) {
|
|
3130
|
-
const countFields = {};
|
|
3131
|
-
for (const countField of Object.keys(config)) {
|
|
3132
|
-
if (!bySet.has(countField)) {
|
|
3133
|
-
throw new ShapeError(
|
|
3134
|
-
`orderBy _count field "${countField}" must be included in "by" for groupBy`
|
|
3135
|
-
);
|
|
3136
|
-
}
|
|
3137
|
-
countFields[countField] = sortEnum.optional();
|
|
3138
|
-
}
|
|
3139
|
-
const countKeys = Object.keys(countFields);
|
|
3140
|
-
groupByOrderFields._count = import_zod7.z.object(countFields).strict().refine(
|
|
3141
|
-
(v) => countKeys.some(
|
|
3142
|
-
(k) => v[k] !== void 0
|
|
3143
|
-
),
|
|
3144
|
-
{
|
|
3145
|
-
message: "orderBy._count must specify at least one field"
|
|
3146
|
-
}
|
|
3147
|
-
).optional();
|
|
3148
|
-
}
|
|
3149
|
-
continue;
|
|
3150
|
-
}
|
|
3151
|
-
if (!bySet.has(fieldName)) {
|
|
3152
|
-
throw new ShapeError(
|
|
3153
|
-
`orderBy field "${fieldName}" must be included in "by" for groupBy`
|
|
3154
|
-
);
|
|
3155
|
-
}
|
|
3156
|
-
groupByOrderFields[fieldName] = sortEnum.optional();
|
|
3157
|
-
}
|
|
3158
|
-
const fieldKeys = Object.keys(groupByOrderFields);
|
|
3159
|
-
const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
|
|
3160
|
-
(v) => fieldKeys.some(
|
|
3161
|
-
(k) => v[k] !== void 0
|
|
3162
|
-
),
|
|
3163
|
-
{ message: "orderBy must specify at least one field" }
|
|
3311
|
+
throw new ShapeError(
|
|
3312
|
+
`Shape config "orderBy: true" is only supported for groupBy. Define an object of allowed fields.`
|
|
3164
3313
|
);
|
|
3165
|
-
schemaFields.orderBy = import_zod7.z.union([
|
|
3166
|
-
singleSchema,
|
|
3167
|
-
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3168
|
-
]).optional();
|
|
3169
3314
|
}
|
|
3170
|
-
} else {
|
|
3171
3315
|
schemaFields.orderBy = argsBuilder.buildOrderBySchema(
|
|
3172
3316
|
model,
|
|
3173
3317
|
shape.orderBy
|
|
@@ -3175,19 +3319,16 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3175
3319
|
}
|
|
3176
3320
|
}
|
|
3177
3321
|
if (shape.cursor) {
|
|
3178
|
-
schemaFields.cursor = argsBuilder.buildCursorSchema(
|
|
3179
|
-
model,
|
|
3180
|
-
shape.cursor
|
|
3181
|
-
);
|
|
3322
|
+
schemaFields.cursor = argsBuilder.buildCursorSchema(model, shape.cursor);
|
|
3182
3323
|
}
|
|
3183
|
-
if (shape.take) {
|
|
3324
|
+
if (shape.take !== void 0) {
|
|
3184
3325
|
schemaFields.take = argsBuilder.buildTakeSchema(shape.take);
|
|
3185
3326
|
}
|
|
3186
3327
|
if (shape.skip !== void 0) {
|
|
3187
3328
|
if (shape.skip !== true) {
|
|
3188
3329
|
throw new ShapeError('Shape config "skip" must be true');
|
|
3189
3330
|
}
|
|
3190
|
-
schemaFields.skip =
|
|
3331
|
+
schemaFields.skip = import_zod8.z.number().int().min(0).optional();
|
|
3191
3332
|
}
|
|
3192
3333
|
if (shape.distinct) {
|
|
3193
3334
|
schemaFields.distinct = argsBuilder.buildDistinctSchema(
|
|
@@ -3234,13 +3375,10 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3234
3375
|
schemaFields.by = argsBuilder.buildBySchema(model, shape.by);
|
|
3235
3376
|
}
|
|
3236
3377
|
if (shape.having) {
|
|
3237
|
-
schemaFields.having = argsBuilder.buildHavingSchema(
|
|
3238
|
-
model,
|
|
3239
|
-
shape.having
|
|
3240
|
-
);
|
|
3378
|
+
schemaFields.having = argsBuilder.buildHavingSchema(model, shape.having);
|
|
3241
3379
|
}
|
|
3242
3380
|
return {
|
|
3243
|
-
zodSchema:
|
|
3381
|
+
zodSchema: import_zod8.z.object(schemaFields).strict(),
|
|
3244
3382
|
forcedWhere,
|
|
3245
3383
|
forcedOnlyWhereKeys,
|
|
3246
3384
|
forcedIncludeTree,
|
|
@@ -3433,22 +3571,18 @@ function buildScopedUniqueWhere(existingWhere, conditions, scopeFks, log, model)
|
|
|
3433
3571
|
allConditions.push(...conditions);
|
|
3434
3572
|
return { ...topLevel, AND: allConditions };
|
|
3435
3573
|
}
|
|
3436
|
-
function
|
|
3437
|
-
const t = typeof v;
|
|
3438
|
-
return t === "string" || t === "number" || t === "bigint";
|
|
3439
|
-
}
|
|
3440
|
-
function looseEqual(a, b, log, fk) {
|
|
3574
|
+
function scopeValuesEqual(a, b) {
|
|
3441
3575
|
if (a === b)
|
|
3442
3576
|
return true;
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
log.warn(
|
|
3448
|
-
`prisma-guard: Scope value for "${fk}" matched via type coercion (${typeof a} ${String(a)} vs ${typeof b} ${String(b)}). Consider normalizing types in the context function.`
|
|
3449
|
-
);
|
|
3577
|
+
const aIsBig = typeof a === "bigint";
|
|
3578
|
+
const bIsBig = typeof b === "bigint";
|
|
3579
|
+
if (aIsBig && typeof b === "number") {
|
|
3580
|
+
return Number.isInteger(b) && a === BigInt(b);
|
|
3450
3581
|
}
|
|
3451
|
-
|
|
3582
|
+
if (bIsBig && typeof a === "number") {
|
|
3583
|
+
return Number.isInteger(a) && b === BigInt(a);
|
|
3584
|
+
}
|
|
3585
|
+
return false;
|
|
3452
3586
|
}
|
|
3453
3587
|
function buildFkSelect(fks) {
|
|
3454
3588
|
const select = {};
|
|
@@ -3738,7 +3872,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3738
3872
|
const result = await query(nextArgs);
|
|
3739
3873
|
if (result === null)
|
|
3740
3874
|
return result;
|
|
3741
|
-
if (typeof result !== "object"
|
|
3875
|
+
if (typeof result !== "object") {
|
|
3742
3876
|
throw new ShapeError(
|
|
3743
3877
|
`${operation} on model "${model}" returned a non-object, non-null result`
|
|
3744
3878
|
);
|
|
@@ -3769,7 +3903,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3769
3903
|
`prisma-guard: Scope verification re-query on model "${model}" returned null for an existing ${operation} result. The record may have been deleted between the original query and verification.`
|
|
3770
3904
|
);
|
|
3771
3905
|
}
|
|
3772
|
-
if (typeof verifyResult !== "object"
|
|
3906
|
+
if (typeof verifyResult !== "object") {
|
|
3773
3907
|
throw new PolicyError(
|
|
3774
3908
|
`prisma-guard: Scope verification re-query on model "${model}" returned a non-object result.`
|
|
3775
3909
|
);
|
|
@@ -3783,7 +3917,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3783
3917
|
`prisma-guard: Cannot verify scope on model "${model}" \u2014 FK field "${fk}" not present in verification result. Ensure "${fk}" is selectable on model "${model}" (not excluded by select or field-level access).`
|
|
3784
3918
|
);
|
|
3785
3919
|
}
|
|
3786
|
-
if (!
|
|
3920
|
+
if (!scopeValuesEqual(verifyObj[fk], value)) {
|
|
3787
3921
|
if (operation === "findUniqueOrThrow") {
|
|
3788
3922
|
throw new PolicyError(
|
|
3789
3923
|
`prisma-guard: Record on model "${model}" not accessible in current scope`
|
|
@@ -3803,97 +3937,158 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3803
3937
|
}
|
|
3804
3938
|
|
|
3805
3939
|
// src/runtime/model-guard.ts
|
|
3940
|
+
var import_zod11 = require("zod");
|
|
3941
|
+
|
|
3942
|
+
// src/runtime/model-guard-data.ts
|
|
3943
|
+
var import_zod10 = require("zod");
|
|
3944
|
+
|
|
3945
|
+
// src/runtime/unique-selector-schema.ts
|
|
3806
3946
|
var import_zod9 = require("zod");
|
|
3947
|
+
function buildUniqueSelectorSchema(parentModel, parentField, relatedModel, config, typeMap, uniqueMap, enumMap, scalarBase, context) {
|
|
3948
|
+
const modelFields = typeMap[relatedModel];
|
|
3949
|
+
if (!modelFields) {
|
|
3950
|
+
throw new ShapeError(
|
|
3951
|
+
`Unknown related model "${relatedModel}" for ${context} on "${parentModel}.${parentField}"`
|
|
3952
|
+
);
|
|
3953
|
+
}
|
|
3954
|
+
const constraints = uniqueMap[relatedModel] ?? [];
|
|
3955
|
+
if (constraints.length === 0) {
|
|
3956
|
+
throw new ShapeError(
|
|
3957
|
+
`${context} on "${parentModel}.${parentField}" requires related model "${relatedModel}" to have at least one unique constraint`
|
|
3958
|
+
);
|
|
3959
|
+
}
|
|
3960
|
+
const configKeys = Object.keys(config);
|
|
3961
|
+
if (configKeys.length === 0) {
|
|
3962
|
+
throw new ShapeError(
|
|
3963
|
+
`${context} on "${parentModel}.${parentField}" must define at least one unique selector. Available: ${formatUniqueConstraints(constraints)}`
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3966
|
+
const fieldSchemas = {};
|
|
3967
|
+
const fieldKeys = [];
|
|
3968
|
+
for (const [key, value] of Object.entries(config)) {
|
|
3969
|
+
const compoundConstraint = constraints.find(
|
|
3970
|
+
(c) => c.selector === key && c.fields.length > 1
|
|
3971
|
+
);
|
|
3972
|
+
if (compoundConstraint) {
|
|
3973
|
+
if (!isPlainObject(value)) {
|
|
3974
|
+
throw new ShapeError(
|
|
3975
|
+
`Compound unique selector "${key}" in ${context} on "${parentModel}.${parentField}" must be an object with fields: ${compoundConstraint.fields.join(", ")}`
|
|
3976
|
+
);
|
|
3977
|
+
}
|
|
3978
|
+
const allowed = new Set(compoundConstraint.fields);
|
|
3979
|
+
const nestedKeys = Object.keys(value);
|
|
3980
|
+
for (const nestedKey of nestedKeys) {
|
|
3981
|
+
if (!allowed.has(nestedKey)) {
|
|
3982
|
+
throw new ShapeError(
|
|
3983
|
+
`Unknown field "${nestedKey}" in compound unique selector "${key}" on "${parentModel}.${parentField}". Allowed: ${compoundConstraint.fields.join(", ")}`
|
|
3984
|
+
);
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
for (const field of compoundConstraint.fields) {
|
|
3988
|
+
if (!(field in value)) {
|
|
3989
|
+
throw new ShapeError(
|
|
3990
|
+
`Missing field "${field}" in compound unique selector "${key}" on "${parentModel}.${parentField}"`
|
|
3991
|
+
);
|
|
3992
|
+
}
|
|
3993
|
+
const fieldValue = value[field];
|
|
3994
|
+
if (fieldValue !== true) {
|
|
3995
|
+
throw new ShapeError(
|
|
3996
|
+
`Field "${field}" in compound unique selector "${key}" on "${parentModel}.${parentField}" must be true`
|
|
3997
|
+
);
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
const nestedSchemas = {};
|
|
4001
|
+
for (const field of compoundConstraint.fields) {
|
|
4002
|
+
const fieldMeta2 = modelFields[field];
|
|
4003
|
+
if (!fieldMeta2) {
|
|
4004
|
+
throw new ShapeError(
|
|
4005
|
+
`Unknown field "${field}" on related model "${relatedModel}"`
|
|
4006
|
+
);
|
|
4007
|
+
}
|
|
4008
|
+
if (fieldMeta2.isRelation) {
|
|
4009
|
+
throw new ShapeError(
|
|
4010
|
+
`Relation field "${field}" cannot be used in compound unique selector`
|
|
4011
|
+
);
|
|
4012
|
+
}
|
|
4013
|
+
nestedSchemas[field] = buildDirectScalarSchema(
|
|
4014
|
+
fieldMeta2,
|
|
4015
|
+
enumMap,
|
|
4016
|
+
scalarBase
|
|
4017
|
+
);
|
|
4018
|
+
}
|
|
4019
|
+
fieldSchemas[key] = import_zod9.z.object(nestedSchemas).strict().optional();
|
|
4020
|
+
fieldKeys.push(key);
|
|
4021
|
+
continue;
|
|
4022
|
+
}
|
|
4023
|
+
const singleConstraint = constraints.find(
|
|
4024
|
+
(c) => c.fields.length === 1 && c.fields[0] === key && c.selector === key
|
|
4025
|
+
);
|
|
4026
|
+
if (!singleConstraint) {
|
|
4027
|
+
const available = formatUniqueConstraints(constraints);
|
|
4028
|
+
throw new ShapeError(
|
|
4029
|
+
`Field "${key}" in ${context} on "${parentModel}.${parentField}" is not a unique selector on model "${relatedModel}". Available: ${available}`
|
|
4030
|
+
);
|
|
4031
|
+
}
|
|
4032
|
+
if (value !== true) {
|
|
4033
|
+
throw new ShapeError(
|
|
4034
|
+
`Field "${key}" in ${context} on "${parentModel}.${parentField}" must be true`
|
|
4035
|
+
);
|
|
4036
|
+
}
|
|
4037
|
+
const fieldMeta = modelFields[key];
|
|
4038
|
+
if (!fieldMeta) {
|
|
4039
|
+
throw new ShapeError(
|
|
4040
|
+
`Unknown field "${key}" on related model "${relatedModel}"`
|
|
4041
|
+
);
|
|
4042
|
+
}
|
|
4043
|
+
if (fieldMeta.isRelation) {
|
|
4044
|
+
throw new ShapeError(
|
|
4045
|
+
`Relation field "${key}" cannot be used in unique selector`
|
|
4046
|
+
);
|
|
4047
|
+
}
|
|
4048
|
+
fieldSchemas[key] = buildDirectScalarSchema(
|
|
4049
|
+
fieldMeta,
|
|
4050
|
+
enumMap,
|
|
4051
|
+
scalarBase
|
|
4052
|
+
).optional();
|
|
4053
|
+
fieldKeys.push(key);
|
|
4054
|
+
}
|
|
4055
|
+
return import_zod9.z.object(fieldSchemas).strict().refine(
|
|
4056
|
+
(v) => fieldKeys.some((k) => v[k] !== void 0),
|
|
4057
|
+
{
|
|
4058
|
+
message: `${context} on "${parentModel}.${parentField}" requires at least one unique selector value`
|
|
4059
|
+
}
|
|
4060
|
+
);
|
|
4061
|
+
}
|
|
3807
4062
|
|
|
3808
4063
|
// src/runtime/model-guard-data.ts
|
|
3809
|
-
var
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
"data",
|
|
3813
|
-
"
|
|
3814
|
-
"
|
|
3815
|
-
])
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
"select",
|
|
3823
|
-
"include",
|
|
3824
|
-
"skipDuplicates"
|
|
3825
|
-
]);
|
|
3826
|
-
var ALLOWED_BODY_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
|
|
3827
|
-
var ALLOWED_BODY_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3828
|
-
"data",
|
|
3829
|
-
"where",
|
|
3830
|
-
"select",
|
|
3831
|
-
"include"
|
|
3832
|
-
]);
|
|
3833
|
-
var ALLOWED_BODY_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
|
|
3834
|
-
var ALLOWED_BODY_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3835
|
-
"where",
|
|
3836
|
-
"select",
|
|
3837
|
-
"include"
|
|
3838
|
-
]);
|
|
3839
|
-
var ALLOWED_BODY_KEYS_UPSERT = /* @__PURE__ */ new Set([
|
|
3840
|
-
"where",
|
|
3841
|
-
"create",
|
|
3842
|
-
"update",
|
|
3843
|
-
"select",
|
|
3844
|
-
"include"
|
|
3845
|
-
]);
|
|
3846
|
-
var VALID_SHAPE_KEYS_CREATE = /* @__PURE__ */ new Set(["data"]);
|
|
3847
|
-
var VALID_SHAPE_KEYS_CREATE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3848
|
-
"data",
|
|
3849
|
-
"select",
|
|
3850
|
-
"include"
|
|
3851
|
-
]);
|
|
3852
|
-
var VALID_SHAPE_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
|
|
3853
|
-
var VALID_SHAPE_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3854
|
-
"data",
|
|
3855
|
-
"where",
|
|
3856
|
-
"select",
|
|
3857
|
-
"include"
|
|
3858
|
-
]);
|
|
3859
|
-
var VALID_SHAPE_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
|
|
3860
|
-
var VALID_SHAPE_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3861
|
-
"where",
|
|
3862
|
-
"select",
|
|
3863
|
-
"include"
|
|
3864
|
-
]);
|
|
3865
|
-
var VALID_SHAPE_KEYS_UPSERT = /* @__PURE__ */ new Set([
|
|
3866
|
-
"where",
|
|
3867
|
-
"create",
|
|
3868
|
-
"update",
|
|
3869
|
-
"select",
|
|
3870
|
-
"include"
|
|
3871
|
-
]);
|
|
3872
|
-
var KNOWN_RELATION_WRITE_OPS = /* @__PURE__ */ new Set([
|
|
3873
|
-
"connect",
|
|
3874
|
-
"connectOrCreate",
|
|
3875
|
-
"create",
|
|
3876
|
-
"createMany",
|
|
3877
|
-
"disconnect",
|
|
3878
|
-
"delete",
|
|
3879
|
-
"set",
|
|
3880
|
-
"update",
|
|
3881
|
-
"updateMany",
|
|
3882
|
-
"upsert",
|
|
3883
|
-
"deleteMany"
|
|
3884
|
-
]);
|
|
3885
|
-
function validateMutationBodyKeys(body, allowed, method) {
|
|
3886
|
-
for (const key of Object.keys(body)) {
|
|
4064
|
+
var RELATION_OP_ALLOWED_KEYS = {
|
|
4065
|
+
connectOrCreate: /* @__PURE__ */ new Set(["where", "create"]),
|
|
4066
|
+
createMany: /* @__PURE__ */ new Set(["data", "skipDuplicates"]),
|
|
4067
|
+
"update.toMany": /* @__PURE__ */ new Set(["where", "data"]),
|
|
4068
|
+
updateMany: /* @__PURE__ */ new Set(["where", "data"]),
|
|
4069
|
+
"upsert.toOne": /* @__PURE__ */ new Set(["where", "create", "update"]),
|
|
4070
|
+
"upsert.toMany": /* @__PURE__ */ new Set(["where", "create", "update"])
|
|
4071
|
+
};
|
|
4072
|
+
function validateRelationOpKeys(actual, opKey, model, field, opLabel) {
|
|
4073
|
+
const allowed = RELATION_OP_ALLOWED_KEYS[opKey];
|
|
4074
|
+
if (!allowed)
|
|
4075
|
+
return;
|
|
4076
|
+
for (const key of Object.keys(actual)) {
|
|
3887
4077
|
if (!allowed.has(key)) {
|
|
3888
4078
|
throw new ShapeError(
|
|
3889
|
-
`
|
|
4079
|
+
`Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
|
|
3890
4080
|
);
|
|
3891
4081
|
}
|
|
3892
4082
|
}
|
|
3893
4083
|
}
|
|
3894
|
-
function
|
|
3895
|
-
for (const key of Object.keys(
|
|
4084
|
+
function validateAllowedKeys(value, allowed, method, kind) {
|
|
4085
|
+
for (const key of Object.keys(value)) {
|
|
3896
4086
|
if (!allowed.has(key)) {
|
|
4087
|
+
if (kind === "body") {
|
|
4088
|
+
throw new ShapeError(
|
|
4089
|
+
`Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`
|
|
4090
|
+
);
|
|
4091
|
+
}
|
|
3897
4092
|
throw new ShapeError(
|
|
3898
4093
|
`Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
|
|
3899
4094
|
);
|
|
@@ -3935,24 +4130,24 @@ function buildWhereFieldsSchema(model, config, typeMap, schemaBuilder) {
|
|
|
3935
4130
|
for (const [fieldName, value] of Object.entries(config)) {
|
|
3936
4131
|
if (value !== true)
|
|
3937
4132
|
throw new ShapeError(
|
|
3938
|
-
`Field "${fieldName}" in
|
|
4133
|
+
`Field "${fieldName}" in filter config must be true`
|
|
3939
4134
|
);
|
|
3940
4135
|
const meta = modelFields[fieldName];
|
|
3941
4136
|
if (!meta)
|
|
3942
4137
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
3943
4138
|
if (meta.isRelation)
|
|
3944
4139
|
throw new ShapeError(
|
|
3945
|
-
`Relation field "${fieldName}" cannot be used in
|
|
4140
|
+
`Relation field "${fieldName}" cannot be used in filter`
|
|
3946
4141
|
);
|
|
3947
4142
|
fieldSchemas[fieldName] = schemaBuilder.buildFieldSchema(model, fieldName).optional();
|
|
3948
4143
|
fieldKeys.push(fieldName);
|
|
3949
4144
|
}
|
|
3950
|
-
return
|
|
4145
|
+
return import_zod10.z.object(fieldSchemas).strict().refine(
|
|
3951
4146
|
(v) => fieldKeys.some((k) => v[k] !== void 0),
|
|
3952
|
-
{ message: `At least one field required in
|
|
4147
|
+
{ message: `At least one field required in filter` }
|
|
3953
4148
|
);
|
|
3954
4149
|
}
|
|
3955
|
-
function buildNestedDataSchema(model, config, typeMap, schemaBuilder) {
|
|
4150
|
+
function buildNestedDataSchema(model, config, mode, typeMap, schemaBuilder) {
|
|
3956
4151
|
const modelFields = typeMap[model];
|
|
3957
4152
|
if (!modelFields)
|
|
3958
4153
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -3973,382 +4168,349 @@ function buildNestedDataSchema(model, config, typeMap, schemaBuilder) {
|
|
|
3973
4168
|
throw new ShapeError(
|
|
3974
4169
|
`updatedAt field "${fieldName}" cannot be used in nested data`
|
|
3975
4170
|
);
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
4171
|
+
if (meta.isUnsupported)
|
|
4172
|
+
throw new ShapeError(
|
|
4173
|
+
`Field "${fieldName}" on model "${model}" has an Unsupported type and cannot be used in nested data`
|
|
4174
|
+
);
|
|
4175
|
+
const baseSchema = schemaBuilder.buildFieldSchema(model, fieldName);
|
|
4176
|
+
fieldSchemas[fieldName] = applyCreateUpdateNullability(meta, baseSchema, {
|
|
4177
|
+
mode,
|
|
4178
|
+
handlesUndefined: false
|
|
4179
|
+
});
|
|
3983
4180
|
}
|
|
3984
|
-
return
|
|
4181
|
+
return import_zod10.z.object(fieldSchemas).strict();
|
|
3985
4182
|
}
|
|
3986
|
-
function
|
|
3987
|
-
|
|
3988
|
-
|
|
4183
|
+
function requirePlainObjectConfig(value, message) {
|
|
4184
|
+
if (!isPlainObject(value))
|
|
4185
|
+
throw new ShapeError(message);
|
|
4186
|
+
return value;
|
|
4187
|
+
}
|
|
4188
|
+
function requireNestedObject(cfg, key, message) {
|
|
4189
|
+
const v = cfg[key];
|
|
4190
|
+
if (!v || !isPlainObject(v))
|
|
4191
|
+
throw new ShapeError(message);
|
|
4192
|
+
return v;
|
|
4193
|
+
}
|
|
4194
|
+
function buildUniqueSelector(ctx, cfg, context) {
|
|
4195
|
+
return buildUniqueSelectorSchema(
|
|
4196
|
+
ctx.model,
|
|
4197
|
+
ctx.fieldName,
|
|
4198
|
+
ctx.relatedModelName,
|
|
4199
|
+
cfg,
|
|
4200
|
+
ctx.typeMap,
|
|
4201
|
+
ctx.uniqueMap,
|
|
4202
|
+
ctx.enumMap,
|
|
4203
|
+
ctx.scalarBase,
|
|
4204
|
+
context
|
|
4205
|
+
);
|
|
4206
|
+
}
|
|
4207
|
+
function buildNestedData(ctx, cfg, mode) {
|
|
4208
|
+
return buildNestedDataSchema(
|
|
4209
|
+
ctx.relatedModelName,
|
|
4210
|
+
cfg,
|
|
4211
|
+
mode,
|
|
4212
|
+
ctx.typeMap,
|
|
4213
|
+
ctx.schemaBuilder
|
|
4214
|
+
);
|
|
4215
|
+
}
|
|
4216
|
+
var handleConnect = (ctx) => {
|
|
4217
|
+
const cfg = requirePlainObjectConfig(
|
|
4218
|
+
ctx.config,
|
|
4219
|
+
`connect config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
|
|
4220
|
+
);
|
|
4221
|
+
const schema = buildUniqueSelector(ctx, cfg, "connect");
|
|
4222
|
+
return wrapRelationOp(ctx.isList, schema);
|
|
4223
|
+
};
|
|
4224
|
+
var handleConnectOrCreate = (ctx) => {
|
|
4225
|
+
const cfg = requirePlainObjectConfig(
|
|
4226
|
+
ctx.config,
|
|
4227
|
+
`connectOrCreate config on "${ctx.model}.${ctx.fieldName}" must be an object with "where" and "create"`
|
|
4228
|
+
);
|
|
4229
|
+
validateRelationOpKeys(cfg, "connectOrCreate", ctx.model, ctx.fieldName, "connectOrCreate");
|
|
4230
|
+
const where = requireNestedObject(
|
|
4231
|
+
cfg,
|
|
4232
|
+
"where",
|
|
4233
|
+
`connectOrCreate on "${ctx.model}.${ctx.fieldName}" requires "where" object`
|
|
4234
|
+
);
|
|
4235
|
+
const create = requireNestedObject(
|
|
4236
|
+
cfg,
|
|
4237
|
+
"create",
|
|
4238
|
+
`connectOrCreate on "${ctx.model}.${ctx.fieldName}" requires "create" object`
|
|
4239
|
+
);
|
|
4240
|
+
const whereSchema = buildUniqueSelector(ctx, where, "connectOrCreate.where");
|
|
4241
|
+
const createSchema = buildNestedData(ctx, create, "create");
|
|
4242
|
+
const cocSchema = import_zod10.z.object({ where: whereSchema, create: createSchema }).strict();
|
|
4243
|
+
return wrapRelationOp(ctx.isList, cocSchema);
|
|
4244
|
+
};
|
|
4245
|
+
var handleCreate = (ctx) => {
|
|
4246
|
+
const cfg = requirePlainObjectConfig(
|
|
4247
|
+
ctx.config,
|
|
4248
|
+
`create config on "${ctx.model}.${ctx.fieldName}" must be an object of field names`
|
|
4249
|
+
);
|
|
4250
|
+
const createSchema = buildNestedData(ctx, cfg, "create");
|
|
4251
|
+
return wrapRelationOp(ctx.isList, createSchema);
|
|
4252
|
+
};
|
|
4253
|
+
var handleCreateMany = (ctx) => {
|
|
4254
|
+
if (!ctx.isList) {
|
|
3989
4255
|
throw new ShapeError(
|
|
3990
|
-
`
|
|
4256
|
+
`createMany is only valid on to-many relations ("${ctx.model}.${ctx.fieldName}")`
|
|
3991
4257
|
);
|
|
3992
|
-
for (const key of Object.keys(config)) {
|
|
3993
|
-
if (!KNOWN_RELATION_WRITE_OPS.has(key)) {
|
|
3994
|
-
throw new ShapeError(
|
|
3995
|
-
`Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
|
|
3996
|
-
);
|
|
3997
|
-
}
|
|
3998
4258
|
}
|
|
3999
|
-
const
|
|
4000
|
-
|
|
4001
|
-
|
|
4259
|
+
const cfg = requirePlainObjectConfig(
|
|
4260
|
+
ctx.config,
|
|
4261
|
+
`createMany config on "${ctx.model}.${ctx.fieldName}" must be an object`
|
|
4262
|
+
);
|
|
4263
|
+
validateRelationOpKeys(cfg, "createMany", ctx.model, ctx.fieldName, "createMany");
|
|
4264
|
+
const data = requireNestedObject(
|
|
4265
|
+
cfg,
|
|
4266
|
+
"data",
|
|
4267
|
+
`createMany on "${ctx.model}.${ctx.fieldName}" requires "data" object`
|
|
4268
|
+
);
|
|
4269
|
+
const dataSchema = buildNestedData(ctx, data, "create");
|
|
4270
|
+
const cmSchemaFields = {
|
|
4271
|
+
data: import_zod10.z.preprocess(coerceToArray, import_zod10.z.array(dataSchema))
|
|
4272
|
+
};
|
|
4273
|
+
if ("skipDuplicates" in cfg) {
|
|
4274
|
+
cmSchemaFields["skipDuplicates"] = import_zod10.z.boolean().optional();
|
|
4275
|
+
}
|
|
4276
|
+
return import_zod10.z.object(cmSchemaFields).strict().optional();
|
|
4277
|
+
};
|
|
4278
|
+
var handleDisconnect = (ctx) => {
|
|
4279
|
+
if (ctx.config === true) {
|
|
4280
|
+
if (ctx.isList) {
|
|
4002
4281
|
throw new ShapeError(
|
|
4003
|
-
`
|
|
4282
|
+
`disconnect on to-many relation "${ctx.model}.${ctx.fieldName}" requires unique selector config, not true`
|
|
4004
4283
|
);
|
|
4005
4284
|
}
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4285
|
+
return import_zod10.z.literal(true).optional();
|
|
4286
|
+
}
|
|
4287
|
+
if (!isPlainObject(ctx.config)) {
|
|
4288
|
+
throw new ShapeError(
|
|
4289
|
+
`disconnect config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
|
|
4011
4290
|
);
|
|
4012
|
-
opSchemas["connect"] = isList ? import_zod8.z.union([
|
|
4013
|
-
connectSchema,
|
|
4014
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(connectSchema))
|
|
4015
|
-
]).optional() : connectSchema.optional();
|
|
4016
4291
|
}
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
if (
|
|
4025
|
-
throw new ShapeError(
|
|
4026
|
-
`connectOrCreate on "${model}.${fieldName}" requires "where" object`
|
|
4027
|
-
);
|
|
4028
|
-
}
|
|
4029
|
-
if (!coc.create || !isPlainObject(coc.create)) {
|
|
4292
|
+
const schema = buildUniqueSelector(ctx, ctx.config, "disconnect");
|
|
4293
|
+
if (ctx.isList)
|
|
4294
|
+
return wrapRelationOp(true, schema);
|
|
4295
|
+
return import_zod10.z.union([import_zod10.z.literal(true), schema]).optional();
|
|
4296
|
+
};
|
|
4297
|
+
var handleDelete = (ctx) => {
|
|
4298
|
+
if (ctx.config === true) {
|
|
4299
|
+
if (ctx.isList) {
|
|
4030
4300
|
throw new ShapeError(
|
|
4031
|
-
`
|
|
4301
|
+
`delete on to-many relation "${ctx.model}.${ctx.fieldName}" requires unique selector config, not true`
|
|
4032
4302
|
);
|
|
4033
4303
|
}
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
);
|
|
4040
|
-
const createSchema = buildNestedDataSchema(
|
|
4041
|
-
relatedModelName,
|
|
4042
|
-
coc.create,
|
|
4043
|
-
typeMap,
|
|
4044
|
-
schemaBuilder
|
|
4304
|
+
return import_zod10.z.literal(true).optional();
|
|
4305
|
+
}
|
|
4306
|
+
if (!isPlainObject(ctx.config)) {
|
|
4307
|
+
throw new ShapeError(
|
|
4308
|
+
`delete config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
|
|
4045
4309
|
);
|
|
4046
|
-
const cocSchema = import_zod8.z.object({ where: whereSchema, create: createSchema }).strict();
|
|
4047
|
-
opSchemas["connectOrCreate"] = isList ? import_zod8.z.union([cocSchema, import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(cocSchema))]).optional() : cocSchema.optional();
|
|
4048
4310
|
}
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
typeMap,
|
|
4059
|
-
schemaBuilder
|
|
4311
|
+
const schema = buildUniqueSelector(ctx, ctx.config, "delete");
|
|
4312
|
+
if (ctx.isList)
|
|
4313
|
+
return wrapRelationOp(true, schema);
|
|
4314
|
+
return import_zod10.z.union([import_zod10.z.literal(true), schema]).optional();
|
|
4315
|
+
};
|
|
4316
|
+
var handleSet = (ctx) => {
|
|
4317
|
+
if (!ctx.isList) {
|
|
4318
|
+
throw new ShapeError(
|
|
4319
|
+
`set is only valid on to-many relations ("${ctx.model}.${ctx.fieldName}")`
|
|
4060
4320
|
);
|
|
4061
|
-
opSchemas["create"] = isList ? import_zod8.z.union([
|
|
4062
|
-
createSchema,
|
|
4063
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(createSchema))
|
|
4064
|
-
]).optional() : createSchema.optional();
|
|
4065
4321
|
}
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
}
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
relatedModelName,
|
|
4085
|
-
cmConfig.data,
|
|
4086
|
-
typeMap,
|
|
4087
|
-
schemaBuilder
|
|
4322
|
+
const cfg = requirePlainObjectConfig(
|
|
4323
|
+
ctx.config,
|
|
4324
|
+
`set config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
|
|
4325
|
+
);
|
|
4326
|
+
const schema = buildUniqueSelector(ctx, cfg, "set");
|
|
4327
|
+
return wrapRelationOp(true, schema);
|
|
4328
|
+
};
|
|
4329
|
+
var handleUpdate = (ctx) => {
|
|
4330
|
+
const cfg = requirePlainObjectConfig(
|
|
4331
|
+
ctx.config,
|
|
4332
|
+
`update config on "${ctx.model}.${ctx.fieldName}" must be an object`
|
|
4333
|
+
);
|
|
4334
|
+
if (ctx.isList) {
|
|
4335
|
+
validateRelationOpKeys(cfg, "update.toMany", ctx.model, ctx.fieldName, "update");
|
|
4336
|
+
const where = requireNestedObject(
|
|
4337
|
+
cfg,
|
|
4338
|
+
"where",
|
|
4339
|
+
`update on to-many "${ctx.model}.${ctx.fieldName}" requires "where" object`
|
|
4088
4340
|
);
|
|
4089
|
-
const
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4341
|
+
const data = requireNestedObject(
|
|
4342
|
+
cfg,
|
|
4343
|
+
"data",
|
|
4344
|
+
`update on to-many "${ctx.model}.${ctx.fieldName}" requires "data" object`
|
|
4345
|
+
);
|
|
4346
|
+
const whereSchema = buildUniqueSelector(ctx, where, "update.where");
|
|
4347
|
+
const dataSchema2 = buildNestedData(ctx, data, "update");
|
|
4348
|
+
const updateSchema = import_zod10.z.object({ where: whereSchema, data: dataSchema2 }).strict();
|
|
4349
|
+
return wrapRelationOp(true, updateSchema);
|
|
4096
4350
|
}
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
}
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4351
|
+
const dataSchema = buildNestedData(ctx, cfg, "update");
|
|
4352
|
+
return dataSchema.optional();
|
|
4353
|
+
};
|
|
4354
|
+
var handleUpsert = (ctx) => {
|
|
4355
|
+
const cfg = requirePlainObjectConfig(
|
|
4356
|
+
ctx.config,
|
|
4357
|
+
`upsert config on "${ctx.model}.${ctx.fieldName}" must be an object`
|
|
4358
|
+
);
|
|
4359
|
+
validateRelationOpKeys(
|
|
4360
|
+
cfg,
|
|
4361
|
+
ctx.isList ? "upsert.toMany" : "upsert.toOne",
|
|
4362
|
+
ctx.model,
|
|
4363
|
+
ctx.fieldName,
|
|
4364
|
+
"upsert"
|
|
4365
|
+
);
|
|
4366
|
+
const create = requireNestedObject(
|
|
4367
|
+
cfg,
|
|
4368
|
+
"create",
|
|
4369
|
+
`upsert on "${ctx.model}.${ctx.fieldName}" requires "create" object`
|
|
4370
|
+
);
|
|
4371
|
+
const update = requireNestedObject(
|
|
4372
|
+
cfg,
|
|
4373
|
+
"update",
|
|
4374
|
+
`upsert on "${ctx.model}.${ctx.fieldName}" requires "update" object`
|
|
4375
|
+
);
|
|
4376
|
+
const createSchema = buildNestedData(ctx, create, "create");
|
|
4377
|
+
const updateSchema = buildNestedData(ctx, update, "update");
|
|
4378
|
+
if (ctx.isList) {
|
|
4379
|
+
const where = requireNestedObject(
|
|
4380
|
+
cfg,
|
|
4381
|
+
"where",
|
|
4382
|
+
`upsert on to-many "${ctx.model}.${ctx.fieldName}" requires "where" object`
|
|
4383
|
+
);
|
|
4384
|
+
const whereSchema = buildUniqueSelector(ctx, where, "upsert.where");
|
|
4385
|
+
const upsertSchema2 = import_zod10.z.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
|
|
4386
|
+
return wrapRelationOp(true, upsertSchema2);
|
|
4125
4387
|
}
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
throw new ShapeError(
|
|
4130
|
-
`delete on to-many relation "${model}.${fieldName}" requires field config, not true`
|
|
4131
|
-
);
|
|
4132
|
-
}
|
|
4133
|
-
opSchemas["delete"] = import_zod8.z.literal(true).optional();
|
|
4134
|
-
} else if (isPlainObject(config.delete)) {
|
|
4135
|
-
const deleteSchema = buildWhereFieldsSchema(
|
|
4136
|
-
relatedModelName,
|
|
4137
|
-
config.delete,
|
|
4138
|
-
typeMap,
|
|
4139
|
-
schemaBuilder
|
|
4140
|
-
);
|
|
4141
|
-
if (isList) {
|
|
4142
|
-
opSchemas["delete"] = import_zod8.z.union([
|
|
4143
|
-
deleteSchema,
|
|
4144
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(deleteSchema))
|
|
4145
|
-
]).optional();
|
|
4146
|
-
} else {
|
|
4147
|
-
opSchemas["delete"] = import_zod8.z.union([import_zod8.z.literal(true), deleteSchema]).optional();
|
|
4148
|
-
}
|
|
4149
|
-
} else {
|
|
4388
|
+
const hasWhereKey = "where" in cfg;
|
|
4389
|
+
if (hasWhereKey) {
|
|
4390
|
+
if (!isPlainObject(cfg.where)) {
|
|
4150
4391
|
throw new ShapeError(
|
|
4151
|
-
`
|
|
4392
|
+
`upsert on to-one "${ctx.model}.${ctx.fieldName}" has invalid "where": must be a plain object of unique selectors`
|
|
4152
4393
|
);
|
|
4153
4394
|
}
|
|
4395
|
+
const whereSchema = buildUniqueSelector(ctx, cfg.where, "upsert.where");
|
|
4396
|
+
const upsertSchema2 = import_zod10.z.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
|
|
4397
|
+
return upsertSchema2.optional();
|
|
4154
4398
|
}
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
throw new ShapeError(
|
|
4163
|
-
`set config on "${model}.${fieldName}" must be an object of field names`
|
|
4164
|
-
);
|
|
4165
|
-
}
|
|
4166
|
-
const setSchema = buildWhereFieldsSchema(
|
|
4167
|
-
relatedModelName,
|
|
4168
|
-
config.set,
|
|
4169
|
-
typeMap,
|
|
4170
|
-
schemaBuilder
|
|
4399
|
+
const upsertSchema = import_zod10.z.object({ create: createSchema, update: updateSchema }).strict();
|
|
4400
|
+
return upsertSchema.optional();
|
|
4401
|
+
};
|
|
4402
|
+
var handleUpdateMany = (ctx) => {
|
|
4403
|
+
if (!ctx.isList) {
|
|
4404
|
+
throw new ShapeError(
|
|
4405
|
+
`updateMany is only valid on to-many relations ("${ctx.model}.${ctx.fieldName}")`
|
|
4171
4406
|
);
|
|
4172
|
-
opSchemas["set"] = import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(setSchema)).optional();
|
|
4173
|
-
}
|
|
4174
|
-
if (config.update !== void 0) {
|
|
4175
|
-
if (!isPlainObject(config.update)) {
|
|
4176
|
-
throw new ShapeError(
|
|
4177
|
-
`update config on "${model}.${fieldName}" must be an object`
|
|
4178
|
-
);
|
|
4179
|
-
}
|
|
4180
|
-
const updateConfig = config.update;
|
|
4181
|
-
if (isList) {
|
|
4182
|
-
if (!updateConfig.where || !isPlainObject(updateConfig.where)) {
|
|
4183
|
-
throw new ShapeError(
|
|
4184
|
-
`update on to-many "${model}.${fieldName}" requires "where" object`
|
|
4185
|
-
);
|
|
4186
|
-
}
|
|
4187
|
-
if (!updateConfig.data || !isPlainObject(updateConfig.data)) {
|
|
4188
|
-
throw new ShapeError(
|
|
4189
|
-
`update on to-many "${model}.${fieldName}" requires "data" object`
|
|
4190
|
-
);
|
|
4191
|
-
}
|
|
4192
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4193
|
-
relatedModelName,
|
|
4194
|
-
updateConfig.where,
|
|
4195
|
-
typeMap,
|
|
4196
|
-
schemaBuilder
|
|
4197
|
-
);
|
|
4198
|
-
const dataSchema = buildNestedDataSchema(
|
|
4199
|
-
relatedModelName,
|
|
4200
|
-
updateConfig.data,
|
|
4201
|
-
typeMap,
|
|
4202
|
-
schemaBuilder
|
|
4203
|
-
);
|
|
4204
|
-
const updateSchema = import_zod8.z.object({ where: whereSchema, data: dataSchema }).strict();
|
|
4205
|
-
opSchemas["update"] = import_zod8.z.union([
|
|
4206
|
-
updateSchema,
|
|
4207
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(updateSchema))
|
|
4208
|
-
]).optional();
|
|
4209
|
-
} else {
|
|
4210
|
-
const dataSchema = buildNestedDataSchema(
|
|
4211
|
-
relatedModelName,
|
|
4212
|
-
updateConfig,
|
|
4213
|
-
typeMap,
|
|
4214
|
-
schemaBuilder
|
|
4215
|
-
);
|
|
4216
|
-
opSchemas["update"] = dataSchema.optional();
|
|
4217
|
-
}
|
|
4218
4407
|
}
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
throw new ShapeError(
|
|
4233
|
-
`upsert on "${model}.${fieldName}" requires "update" object`
|
|
4234
|
-
);
|
|
4235
|
-
}
|
|
4236
|
-
const createSchema = buildNestedDataSchema(
|
|
4237
|
-
relatedModelName,
|
|
4238
|
-
upsertConfig.create,
|
|
4239
|
-
typeMap,
|
|
4240
|
-
schemaBuilder
|
|
4408
|
+
const cfg = requirePlainObjectConfig(
|
|
4409
|
+
ctx.config,
|
|
4410
|
+
`updateMany config on "${ctx.model}.${ctx.fieldName}" must be an object`
|
|
4411
|
+
);
|
|
4412
|
+
validateRelationOpKeys(cfg, "updateMany", ctx.model, ctx.fieldName, "updateMany");
|
|
4413
|
+
const where = requireNestedObject(
|
|
4414
|
+
cfg,
|
|
4415
|
+
"where",
|
|
4416
|
+
`updateMany on "${ctx.model}.${ctx.fieldName}" requires "where" object`
|
|
4417
|
+
);
|
|
4418
|
+
if (Object.keys(where).length === 0) {
|
|
4419
|
+
throw new ShapeError(
|
|
4420
|
+
`updateMany "where" on "${ctx.model}.${ctx.fieldName}" must define at least one filter field`
|
|
4241
4421
|
);
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4422
|
+
}
|
|
4423
|
+
const data = requireNestedObject(
|
|
4424
|
+
cfg,
|
|
4425
|
+
"data",
|
|
4426
|
+
`updateMany on "${ctx.model}.${ctx.fieldName}" requires "data" object`
|
|
4427
|
+
);
|
|
4428
|
+
if (Object.keys(data).length === 0) {
|
|
4429
|
+
throw new ShapeError(
|
|
4430
|
+
`updateMany "data" on "${ctx.model}.${ctx.fieldName}" must define at least one field`
|
|
4247
4431
|
);
|
|
4248
|
-
if (isList) {
|
|
4249
|
-
if (!upsertConfig.where || !isPlainObject(upsertConfig.where)) {
|
|
4250
|
-
throw new ShapeError(
|
|
4251
|
-
`upsert on to-many "${model}.${fieldName}" requires "where" object`
|
|
4252
|
-
);
|
|
4253
|
-
}
|
|
4254
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4255
|
-
relatedModelName,
|
|
4256
|
-
upsertConfig.where,
|
|
4257
|
-
typeMap,
|
|
4258
|
-
schemaBuilder
|
|
4259
|
-
);
|
|
4260
|
-
const upsertSchema = import_zod8.z.object({
|
|
4261
|
-
where: whereSchema,
|
|
4262
|
-
create: createSchema,
|
|
4263
|
-
update: updateSchema
|
|
4264
|
-
}).strict();
|
|
4265
|
-
opSchemas["upsert"] = import_zod8.z.union([
|
|
4266
|
-
upsertSchema,
|
|
4267
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(upsertSchema))
|
|
4268
|
-
]).optional();
|
|
4269
|
-
} else {
|
|
4270
|
-
if (upsertConfig.where) {
|
|
4271
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4272
|
-
relatedModelName,
|
|
4273
|
-
upsertConfig.where,
|
|
4274
|
-
typeMap,
|
|
4275
|
-
schemaBuilder
|
|
4276
|
-
);
|
|
4277
|
-
const upsertSchema = import_zod8.z.object({
|
|
4278
|
-
where: whereSchema,
|
|
4279
|
-
create: createSchema,
|
|
4280
|
-
update: updateSchema
|
|
4281
|
-
}).strict();
|
|
4282
|
-
opSchemas["upsert"] = upsertSchema.optional();
|
|
4283
|
-
} else {
|
|
4284
|
-
const upsertSchema = import_zod8.z.object({ create: createSchema, update: updateSchema }).strict();
|
|
4285
|
-
opSchemas["upsert"] = upsertSchema.optional();
|
|
4286
|
-
}
|
|
4287
|
-
}
|
|
4288
4432
|
}
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
`updateMany on "${model}.${fieldName}" requires "where" object`
|
|
4304
|
-
);
|
|
4305
|
-
}
|
|
4306
|
-
if (!umConfig.data || !isPlainObject(umConfig.data)) {
|
|
4307
|
-
throw new ShapeError(
|
|
4308
|
-
`updateMany on "${model}.${fieldName}" requires "data" object`
|
|
4309
|
-
);
|
|
4310
|
-
}
|
|
4311
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4312
|
-
relatedModelName,
|
|
4313
|
-
umConfig.where,
|
|
4314
|
-
typeMap,
|
|
4315
|
-
schemaBuilder
|
|
4433
|
+
const whereSchema = buildWhereFieldsSchema(
|
|
4434
|
+
ctx.relatedModelName,
|
|
4435
|
+
where,
|
|
4436
|
+
ctx.typeMap,
|
|
4437
|
+
ctx.schemaBuilder
|
|
4438
|
+
);
|
|
4439
|
+
const dataSchema = buildNestedData(ctx, data, "update");
|
|
4440
|
+
const umSchema = import_zod10.z.object({ where: whereSchema, data: dataSchema }).strict();
|
|
4441
|
+
return wrapRelationOp(true, umSchema);
|
|
4442
|
+
};
|
|
4443
|
+
var handleDeleteMany = (ctx) => {
|
|
4444
|
+
if (!ctx.isList) {
|
|
4445
|
+
throw new ShapeError(
|
|
4446
|
+
`deleteMany is only valid on to-many relations ("${ctx.model}.${ctx.fieldName}")`
|
|
4316
4447
|
);
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4448
|
+
}
|
|
4449
|
+
const cfg = requirePlainObjectConfig(
|
|
4450
|
+
ctx.config,
|
|
4451
|
+
`deleteMany config on "${ctx.model}.${ctx.fieldName}" must be an object of allowed filter fields`
|
|
4452
|
+
);
|
|
4453
|
+
if (Object.keys(cfg).length === 0) {
|
|
4454
|
+
throw new ShapeError(
|
|
4455
|
+
`deleteMany config on "${ctx.model}.${ctx.fieldName}" is empty. Unconstrained nested deletes are not allowed. Define at least one allowed filter field.`
|
|
4322
4456
|
);
|
|
4323
|
-
const umSchema = import_zod8.z.object({ where: whereSchema, data: dataSchema }).strict();
|
|
4324
|
-
opSchemas["updateMany"] = import_zod8.z.union([umSchema, import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(umSchema))]).optional();
|
|
4325
4457
|
}
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4458
|
+
const filterSchema = buildWhereFieldsSchema(
|
|
4459
|
+
ctx.relatedModelName,
|
|
4460
|
+
cfg,
|
|
4461
|
+
ctx.typeMap,
|
|
4462
|
+
ctx.schemaBuilder
|
|
4463
|
+
);
|
|
4464
|
+
return wrapRelationOp(true, filterSchema);
|
|
4465
|
+
};
|
|
4466
|
+
var RELATION_OP_HANDLERS = {
|
|
4467
|
+
connect: handleConnect,
|
|
4468
|
+
connectOrCreate: handleConnectOrCreate,
|
|
4469
|
+
create: handleCreate,
|
|
4470
|
+
createMany: handleCreateMany,
|
|
4471
|
+
disconnect: handleDisconnect,
|
|
4472
|
+
delete: handleDelete,
|
|
4473
|
+
set: handleSet,
|
|
4474
|
+
update: handleUpdate,
|
|
4475
|
+
upsert: handleUpsert,
|
|
4476
|
+
updateMany: handleUpdateMany,
|
|
4477
|
+
deleteMany: handleDeleteMany
|
|
4478
|
+
};
|
|
4479
|
+
var KNOWN_RELATION_WRITE_OPS = new Set(Object.keys(RELATION_OP_HANDLERS));
|
|
4480
|
+
function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, config, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder) {
|
|
4481
|
+
const relatedFields = typeMap[relatedModelName];
|
|
4482
|
+
if (!relatedFields)
|
|
4483
|
+
throw new ShapeError(
|
|
4484
|
+
`Unknown related model "${relatedModelName}" for field "${model}.${fieldName}"`
|
|
4485
|
+
);
|
|
4486
|
+
for (const key of Object.keys(config)) {
|
|
4487
|
+
if (!KNOWN_RELATION_WRITE_OPS.has(key)) {
|
|
4333
4488
|
throw new ShapeError(
|
|
4334
|
-
`
|
|
4489
|
+
`Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
|
|
4335
4490
|
);
|
|
4336
4491
|
}
|
|
4337
|
-
|
|
4492
|
+
}
|
|
4493
|
+
const opSchemas = {};
|
|
4494
|
+
for (const [op, opConfig] of Object.entries(config)) {
|
|
4495
|
+
if (opConfig === void 0)
|
|
4496
|
+
continue;
|
|
4497
|
+
const handler = RELATION_OP_HANDLERS[op];
|
|
4498
|
+
opSchemas[op] = handler({
|
|
4499
|
+
model,
|
|
4500
|
+
fieldName,
|
|
4338
4501
|
relatedModelName,
|
|
4339
|
-
|
|
4502
|
+
isList,
|
|
4503
|
+
config: opConfig,
|
|
4340
4504
|
typeMap,
|
|
4505
|
+
uniqueMap,
|
|
4506
|
+
enumMap,
|
|
4507
|
+
scalarBase,
|
|
4341
4508
|
schemaBuilder
|
|
4342
|
-
);
|
|
4343
|
-
opSchemas["deleteMany"] = import_zod8.z.union([
|
|
4344
|
-
filterSchema,
|
|
4345
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(filterSchema)),
|
|
4346
|
-
import_zod8.z.object({}).strict()
|
|
4347
|
-
]).optional();
|
|
4509
|
+
});
|
|
4348
4510
|
}
|
|
4349
|
-
return
|
|
4511
|
+
return import_zod10.z.object(opSchemas).strict();
|
|
4350
4512
|
}
|
|
4351
|
-
function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDefaults) {
|
|
4513
|
+
function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults) {
|
|
4352
4514
|
const modelFields = typeMap[model];
|
|
4353
4515
|
if (!modelFields)
|
|
4354
4516
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -4360,11 +4522,23 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4360
4522
|
const fieldMeta = modelFields[fieldName];
|
|
4361
4523
|
if (!fieldMeta) {
|
|
4362
4524
|
if (isUnsupportedMarker(value)) {
|
|
4363
|
-
schemaMap[fieldName] = import_zod8.z.unknown().optional();
|
|
4364
4525
|
continue;
|
|
4365
4526
|
}
|
|
4366
4527
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
4367
4528
|
}
|
|
4529
|
+
if (fieldMeta.isUnsupported) {
|
|
4530
|
+
if (isUnsupportedMarker(value)) {
|
|
4531
|
+
continue;
|
|
4532
|
+
}
|
|
4533
|
+
if (value === true || typeof value === "function") {
|
|
4534
|
+
throw new ShapeError(
|
|
4535
|
+
`Field "${fieldName}" on model "${model}" has an Unsupported type and cannot be client-controlled. Use unsupported() to acknowledge it or a forced server value.`
|
|
4536
|
+
);
|
|
4537
|
+
}
|
|
4538
|
+
const actualValue = isForcedValue(value) ? value.value : value;
|
|
4539
|
+
forced[fieldName] = deepClone(actualValue);
|
|
4540
|
+
continue;
|
|
4541
|
+
}
|
|
4368
4542
|
if (fieldMeta.isRelation) {
|
|
4369
4543
|
if (!isPlainObject(value)) {
|
|
4370
4544
|
throw new ShapeError(
|
|
@@ -4378,6 +4552,9 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4378
4552
|
fieldMeta.isList,
|
|
4379
4553
|
value,
|
|
4380
4554
|
typeMap,
|
|
4555
|
+
uniqueMap,
|
|
4556
|
+
enumMap,
|
|
4557
|
+
scalarBase,
|
|
4381
4558
|
schemaBuilder
|
|
4382
4559
|
).optional();
|
|
4383
4560
|
continue;
|
|
@@ -4387,7 +4564,7 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4387
4564
|
`updatedAt field "${fieldName}" cannot be used in data shape`
|
|
4388
4565
|
);
|
|
4389
4566
|
if (typeof value === "function") {
|
|
4390
|
-
|
|
4567
|
+
const baseSchema = schemaBuilder.buildBaseFieldSchema(
|
|
4391
4568
|
model,
|
|
4392
4569
|
fieldName
|
|
4393
4570
|
);
|
|
@@ -4405,46 +4582,22 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4405
4582
|
`Inline refine for "${model}.${fieldName}" must return a Zod schema`
|
|
4406
4583
|
);
|
|
4407
4584
|
}
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
fieldSchema = fieldSchema.optional();
|
|
4416
|
-
}
|
|
4417
|
-
}
|
|
4418
|
-
} else {
|
|
4419
|
-
if (!fieldMeta.isRequired) {
|
|
4420
|
-
fieldSchema = fieldSchema.nullable().optional();
|
|
4421
|
-
} else {
|
|
4422
|
-
fieldSchema = fieldSchema.optional();
|
|
4423
|
-
}
|
|
4424
|
-
}
|
|
4425
|
-
schemaMap[fieldName] = fieldSchema;
|
|
4426
|
-
} else if (value === true) {
|
|
4427
|
-
let fieldSchema = schemaBuilder.buildFieldSchema(
|
|
4428
|
-
model,
|
|
4429
|
-
fieldName
|
|
4585
|
+
const handlesUndefined = schemaProducesValueForUndefined(
|
|
4586
|
+
refined
|
|
4587
|
+
);
|
|
4588
|
+
schemaMap[fieldName] = applyCreateUpdateNullability(
|
|
4589
|
+
fieldMeta,
|
|
4590
|
+
refined,
|
|
4591
|
+
{ mode, handlesUndefined }
|
|
4430
4592
|
);
|
|
4593
|
+
} else if (value === true) {
|
|
4594
|
+
const fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
|
|
4431
4595
|
const isZodDefaultField = zodDefaultSet !== void 0 && zodDefaultSet.has(fieldName);
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
fieldSchema = fieldSchema.optional();
|
|
4438
|
-
}
|
|
4439
|
-
}
|
|
4440
|
-
} else {
|
|
4441
|
-
if (!fieldMeta.isRequired) {
|
|
4442
|
-
fieldSchema = fieldSchema.nullable().optional();
|
|
4443
|
-
} else {
|
|
4444
|
-
fieldSchema = fieldSchema.optional();
|
|
4445
|
-
}
|
|
4446
|
-
}
|
|
4447
|
-
schemaMap[fieldName] = fieldSchema;
|
|
4596
|
+
schemaMap[fieldName] = applyCreateUpdateNullability(
|
|
4597
|
+
fieldMeta,
|
|
4598
|
+
fieldSchema,
|
|
4599
|
+
{ mode, handlesUndefined: isZodDefaultField }
|
|
4600
|
+
);
|
|
4448
4601
|
} else {
|
|
4449
4602
|
const actualValue = isForcedValue(value) ? value.value : value;
|
|
4450
4603
|
let fieldSchema = schemaBuilder.buildFieldSchema(
|
|
@@ -4488,7 +4641,7 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4488
4641
|
}
|
|
4489
4642
|
}
|
|
4490
4643
|
return {
|
|
4491
|
-
schema:
|
|
4644
|
+
schema: import_zod10.z.object(schemaMap).strict(),
|
|
4492
4645
|
forced
|
|
4493
4646
|
};
|
|
4494
4647
|
}
|
|
@@ -4525,106 +4678,120 @@ function isGuardShape(obj) {
|
|
|
4525
4678
|
const keys = Object.keys(obj);
|
|
4526
4679
|
return keys.length === 0 || keys.every((k) => GUARD_SHAPE_KEYS.has(k));
|
|
4527
4680
|
}
|
|
4528
|
-
function
|
|
4529
|
-
|
|
4530
|
-
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
return value;
|
|
4534
|
-
if (Array.isArray(value))
|
|
4535
|
-
return value.map(toPlainObject);
|
|
4536
|
-
if (value instanceof Date)
|
|
4537
|
-
return value;
|
|
4538
|
-
if (value instanceof Uint8Array)
|
|
4539
|
-
return value;
|
|
4540
|
-
if (value instanceof RegExp)
|
|
4541
|
-
return value;
|
|
4542
|
-
if (typeof value.toFixed === "function" && typeof value.toNumber === "function")
|
|
4543
|
-
return value;
|
|
4544
|
-
const result = {};
|
|
4545
|
-
for (const [k, v] of Object.entries(value)) {
|
|
4546
|
-
result[k] = toPlainObject(v);
|
|
4681
|
+
function requireBody(body) {
|
|
4682
|
+
if (body === void 0 || body === null)
|
|
4683
|
+
return {};
|
|
4684
|
+
if (!isPlainObject(body)) {
|
|
4685
|
+
throw new ShapeError("Request body must be a plain object");
|
|
4547
4686
|
}
|
|
4548
|
-
return
|
|
4687
|
+
return body;
|
|
4549
4688
|
}
|
|
4550
|
-
function
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4689
|
+
function assertNoCallerInBody(body) {
|
|
4690
|
+
if ("caller" in body) {
|
|
4691
|
+
throw new CallerError(
|
|
4692
|
+
"Pass caller via the guard(input, caller) argument, not in the request body."
|
|
4693
|
+
);
|
|
4694
|
+
}
|
|
4555
4695
|
}
|
|
4556
|
-
function resolveDynamicShape(
|
|
4557
|
-
|
|
4696
|
+
function resolveDynamicShape(shapeFn, ctx, context) {
|
|
4697
|
+
if (ctx === void 0) {
|
|
4698
|
+
throw new ShapeError(
|
|
4699
|
+
`Dynamic ${context} requires a context. Provide contextFn on the extension.`
|
|
4700
|
+
);
|
|
4701
|
+
}
|
|
4558
4702
|
let result;
|
|
4559
4703
|
try {
|
|
4560
|
-
result =
|
|
4704
|
+
result = shapeFn(ctx);
|
|
4561
4705
|
} catch (err) {
|
|
4562
4706
|
throw new ShapeError(
|
|
4563
|
-
`Dynamic
|
|
4707
|
+
`Dynamic ${context} function threw: ${err.message}`,
|
|
4564
4708
|
{ cause: err }
|
|
4565
4709
|
);
|
|
4566
4710
|
}
|
|
4567
|
-
if (!
|
|
4568
|
-
throw new ShapeError(
|
|
4711
|
+
if (!isGuardShape(result)) {
|
|
4712
|
+
throw new ShapeError(
|
|
4713
|
+
`Dynamic ${context} function must return a valid guard shape object`
|
|
4714
|
+
);
|
|
4569
4715
|
}
|
|
4570
4716
|
return result;
|
|
4571
4717
|
}
|
|
4572
|
-
function
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
return { shape: shape2, body: parsed2, matchedKey: "_default", wasDynamic: wasDynamic2 };
|
|
4578
|
-
}
|
|
4579
|
-
const namedMap = input;
|
|
4580
|
-
for (const key of Object.keys(namedMap)) {
|
|
4718
|
+
function resolveNamedShape(input, body, contextFn, explicitCaller) {
|
|
4719
|
+
assertNoCallerInBody(body);
|
|
4720
|
+
const caller = explicitCaller;
|
|
4721
|
+
const keys = Object.keys(input);
|
|
4722
|
+
for (const key of keys) {
|
|
4581
4723
|
if (GUARD_SHAPE_KEYS.has(key)) {
|
|
4582
4724
|
throw new ShapeError(
|
|
4583
|
-
`Caller key "${key}" collides with reserved shape
|
|
4584
|
-
);
|
|
4585
|
-
}
|
|
4586
|
-
const val = namedMap[key];
|
|
4587
|
-
if (typeof val !== "function" && !isGuardShape(val)) {
|
|
4588
|
-
throw new ShapeError(
|
|
4589
|
-
`Named shape value for "${key}" must be a guard shape object or function`
|
|
4725
|
+
`Caller key "${key}" collides with reserved guard shape key. Rename the caller path.`
|
|
4590
4726
|
);
|
|
4591
4727
|
}
|
|
4592
4728
|
}
|
|
4593
|
-
const parsed = body === void 0 || body === null ? {} : requireBody(body);
|
|
4594
|
-
if ("caller" in parsed) {
|
|
4595
|
-
throw new CallerError(
|
|
4596
|
-
"Pass caller as second argument to .guard() or via context function, not in the request body."
|
|
4597
|
-
);
|
|
4598
|
-
}
|
|
4599
4729
|
if (typeof caller !== "string") {
|
|
4600
|
-
if ("default" in
|
|
4601
|
-
|
|
4602
|
-
const wasDynamic2 = typeof shapeOrFn2 === "function";
|
|
4603
|
-
const shape2 = wasDynamic2 ? resolveDynamicShape(shapeOrFn2, contextFn) : shapeOrFn2;
|
|
4604
|
-
return { shape: shape2, body: parsed, matchedKey: "default", wasDynamic: wasDynamic2 };
|
|
4730
|
+
if ("default" in input) {
|
|
4731
|
+
return resolveShapeEntry(input.default, body, contextFn, "default");
|
|
4605
4732
|
}
|
|
4606
|
-
const patterns2 = Object.keys(namedMap);
|
|
4607
4733
|
throw new CallerError(
|
|
4608
|
-
`Missing caller. This guard uses named shape routing with keys: ${
|
|
4734
|
+
`Missing caller. This guard uses named shape routing with keys: ${keys.map((k) => `"${k}"`).join(", ")}. Provide caller via guard(input, caller).`
|
|
4609
4735
|
);
|
|
4610
4736
|
}
|
|
4611
|
-
const
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
}
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4737
|
+
const matched = matchCallerPattern(keys, caller);
|
|
4738
|
+
if (matched) {
|
|
4739
|
+
return resolveShapeEntry(input[matched], body, contextFn, matched);
|
|
4740
|
+
}
|
|
4741
|
+
if ("default" in input) {
|
|
4742
|
+
return resolveShapeEntry(input.default, body, contextFn, "default");
|
|
4743
|
+
}
|
|
4744
|
+
throw new CallerError(
|
|
4745
|
+
`Unknown caller: "${caller}". Allowed: ${keys.map((k) => `"${k}"`).join(", ")}`
|
|
4746
|
+
);
|
|
4747
|
+
}
|
|
4748
|
+
function resolveShapeEntry(entry, body, contextFn, matchedKey) {
|
|
4749
|
+
if (typeof entry === "function") {
|
|
4750
|
+
const ctx = validateContext(contextFn());
|
|
4751
|
+
const shape = resolveDynamicShape(entry, ctx, `shape "${matchedKey}"`);
|
|
4752
|
+
return {
|
|
4753
|
+
shape,
|
|
4754
|
+
body,
|
|
4755
|
+
matchedKey,
|
|
4756
|
+
wasDynamic: true
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
return {
|
|
4760
|
+
shape: entry,
|
|
4761
|
+
body,
|
|
4762
|
+
matchedKey,
|
|
4763
|
+
wasDynamic: false
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4766
|
+
function resolveShape(input, rawBody, contextFn, explicitCaller) {
|
|
4767
|
+
const body = requireBody(rawBody);
|
|
4768
|
+
if (typeof input === "function") {
|
|
4769
|
+
const ctx = validateContext(contextFn());
|
|
4770
|
+
const shape = resolveDynamicShape(input, ctx, "shape");
|
|
4771
|
+
return {
|
|
4772
|
+
shape,
|
|
4773
|
+
body,
|
|
4774
|
+
matchedKey: "_default",
|
|
4775
|
+
wasDynamic: true
|
|
4776
|
+
};
|
|
4777
|
+
}
|
|
4778
|
+
if (isGuardShape(input)) {
|
|
4779
|
+
return {
|
|
4780
|
+
shape: input,
|
|
4781
|
+
body,
|
|
4782
|
+
matchedKey: "_default",
|
|
4783
|
+
wasDynamic: false
|
|
4784
|
+
};
|
|
4623
4785
|
}
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
return
|
|
4786
|
+
if (!isPlainObject(input)) {
|
|
4787
|
+
throw new ShapeError("Guard input must be a shape object or a named map of shapes");
|
|
4788
|
+
}
|
|
4789
|
+
return resolveNamedShape(
|
|
4790
|
+
input,
|
|
4791
|
+
body,
|
|
4792
|
+
contextFn,
|
|
4793
|
+
explicitCaller
|
|
4794
|
+
);
|
|
4628
4795
|
}
|
|
4629
4796
|
|
|
4630
4797
|
// src/runtime/model-guard.ts
|
|
@@ -4647,129 +4814,20 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
4647
4814
|
"updateManyAndReturn"
|
|
4648
4815
|
]);
|
|
4649
4816
|
var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set(["createMany", "createManyAndReturn"]);
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
);
|
|
4657
|
-
continue;
|
|
4658
|
-
}
|
|
4659
|
-
if (value === true) {
|
|
4660
|
-
result[key] = true;
|
|
4661
|
-
} else {
|
|
4662
|
-
const nested = {};
|
|
4663
|
-
if (value.select)
|
|
4664
|
-
nested.select = buildDefaultSelectInput(value.select);
|
|
4665
|
-
if (value.include) {
|
|
4666
|
-
nested.include = buildDefaultIncludeInput(value.include);
|
|
4667
|
-
}
|
|
4668
|
-
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
4669
|
-
}
|
|
4670
|
-
}
|
|
4671
|
-
return result;
|
|
4672
|
-
}
|
|
4673
|
-
function buildDefaultIncludeInput(config) {
|
|
4674
|
-
const result = {};
|
|
4675
|
-
for (const [key, value] of Object.entries(config)) {
|
|
4676
|
-
if (key === "_count") {
|
|
4677
|
-
result[key] = buildDefaultCountInput(
|
|
4678
|
-
value
|
|
4679
|
-
);
|
|
4680
|
-
continue;
|
|
4681
|
-
}
|
|
4682
|
-
if (value === true) {
|
|
4683
|
-
result[key] = true;
|
|
4684
|
-
} else {
|
|
4685
|
-
const nested = {};
|
|
4686
|
-
if (value.include) {
|
|
4687
|
-
nested.include = buildDefaultIncludeInput(value.include);
|
|
4688
|
-
}
|
|
4689
|
-
if (value.select)
|
|
4690
|
-
nested.select = buildDefaultSelectInput(value.select);
|
|
4691
|
-
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
4692
|
-
}
|
|
4693
|
-
}
|
|
4694
|
-
return result;
|
|
4695
|
-
}
|
|
4696
|
-
function buildDefaultCountInput(config) {
|
|
4697
|
-
if (config === true)
|
|
4698
|
-
return true;
|
|
4699
|
-
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select)) {
|
|
4700
|
-
return true;
|
|
4701
|
-
}
|
|
4702
|
-
const selectObj = config.select;
|
|
4703
|
-
const result = {};
|
|
4704
|
-
for (const key of Object.keys(selectObj)) {
|
|
4705
|
-
result[key] = true;
|
|
4706
|
-
}
|
|
4707
|
-
return { select: result };
|
|
4708
|
-
}
|
|
4709
|
-
function buildDefaultProjectionBody(shape) {
|
|
4710
|
-
if (shape.select) {
|
|
4711
|
-
return { select: buildDefaultSelectInput(shape.select) };
|
|
4712
|
-
}
|
|
4713
|
-
if (shape.include) {
|
|
4714
|
-
return { include: buildDefaultIncludeInput(shape.include) };
|
|
4715
|
-
}
|
|
4716
|
-
return {};
|
|
4717
|
-
}
|
|
4718
|
-
function applyClientProjectionOverrides(shapeDefault, clientProjection) {
|
|
4719
|
-
const result = { ...shapeDefault };
|
|
4720
|
-
for (const [key, clientValue] of Object.entries(clientProjection)) {
|
|
4721
|
-
const defaultValue = result[key];
|
|
4722
|
-
if (defaultValue === void 0) {
|
|
4723
|
-
result[key] = clientValue;
|
|
4724
|
-
continue;
|
|
4725
|
-
}
|
|
4726
|
-
if (clientValue === true) {
|
|
4727
|
-
result[key] = true;
|
|
4728
|
-
continue;
|
|
4729
|
-
}
|
|
4730
|
-
if (isPlainObject(clientValue)) {
|
|
4731
|
-
if (!isPlainObject(defaultValue)) {
|
|
4732
|
-
result[key] = clientValue;
|
|
4733
|
-
continue;
|
|
4734
|
-
}
|
|
4735
|
-
const merged = { ...defaultValue };
|
|
4736
|
-
const clientObj = clientValue;
|
|
4737
|
-
for (const [argKey, argValue] of Object.entries(clientObj)) {
|
|
4738
|
-
const defaultArgValue = merged[argKey];
|
|
4739
|
-
if ((argKey === "select" || argKey === "include") && isPlainObject(argValue) && isPlainObject(defaultArgValue)) {
|
|
4740
|
-
merged[argKey] = applyClientProjectionOverrides(
|
|
4741
|
-
defaultArgValue,
|
|
4742
|
-
argValue
|
|
4743
|
-
);
|
|
4744
|
-
} else {
|
|
4745
|
-
merged[argKey] = argValue;
|
|
4746
|
-
}
|
|
4747
|
-
}
|
|
4748
|
-
result[key] = merged;
|
|
4749
|
-
}
|
|
4750
|
-
}
|
|
4751
|
-
return result;
|
|
4752
|
-
}
|
|
4753
|
-
function hasClientControlledValues(obj) {
|
|
4754
|
-
for (const value of Object.values(obj)) {
|
|
4755
|
-
if (isForcedValue(value))
|
|
4756
|
-
continue;
|
|
4757
|
-
if (value === true)
|
|
4758
|
-
return true;
|
|
4759
|
-
if (isPlainObject(value) && hasClientControlledValues(value))
|
|
4817
|
+
var MAX_PROJECTION_WALK_DEPTH = 10;
|
|
4818
|
+
function walkForClientContent(obj, predicate, depth) {
|
|
4819
|
+
if (depth > MAX_PROJECTION_WALK_DEPTH)
|
|
4820
|
+
return false;
|
|
4821
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
4822
|
+
if (predicate(value, depth))
|
|
4760
4823
|
return true;
|
|
4761
|
-
}
|
|
4762
|
-
return false;
|
|
4763
|
-
}
|
|
4764
|
-
function checkIncludeForClientArgs(config) {
|
|
4765
|
-
for (const [key, value] of Object.entries(config)) {
|
|
4766
4824
|
if (key === "_count") {
|
|
4767
4825
|
if (value !== true && isPlainObject(value) && isPlainObject(value.select)) {
|
|
4768
4826
|
const selectObj = value.select;
|
|
4769
4827
|
for (const entryVal of Object.values(selectObj)) {
|
|
4770
4828
|
if (isPlainObject(entryVal) && entryVal.where) {
|
|
4771
4829
|
const w = entryVal.where;
|
|
4772
|
-
if (isPlainObject(w) && hasClientControlledValues(w))
|
|
4830
|
+
if (isPlainObject(w) && hasClientControlledValues(w, depth + 1))
|
|
4773
4831
|
return true;
|
|
4774
4832
|
}
|
|
4775
4833
|
}
|
|
@@ -4778,54 +4836,41 @@ function checkIncludeForClientArgs(config) {
|
|
|
4778
4836
|
}
|
|
4779
4837
|
if (value === true)
|
|
4780
4838
|
continue;
|
|
4781
|
-
|
|
4839
|
+
const nested = value;
|
|
4840
|
+
if (nested.orderBy || nested.cursor || nested.take || nested.skip)
|
|
4782
4841
|
return true;
|
|
4783
|
-
if (
|
|
4842
|
+
if (nested.where && isPlainObject(nested.where) && hasClientControlledValues(nested.where, depth + 1)) {
|
|
4784
4843
|
return true;
|
|
4785
4844
|
}
|
|
4786
|
-
if (
|
|
4845
|
+
if (nested.include && walkForClientContent(nested.include, predicate, depth + 1))
|
|
4787
4846
|
return true;
|
|
4788
|
-
if (
|
|
4847
|
+
if (nested.select && walkForClientContent(nested.select, predicate, depth + 1))
|
|
4789
4848
|
return true;
|
|
4790
4849
|
}
|
|
4791
4850
|
return false;
|
|
4792
4851
|
}
|
|
4793
|
-
function
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
for (const entryVal of Object.values(selectObj)) {
|
|
4799
|
-
if (isPlainObject(entryVal) && entryVal.where) {
|
|
4800
|
-
const w = entryVal.where;
|
|
4801
|
-
if (isPlainObject(w) && hasClientControlledValues(w))
|
|
4802
|
-
return true;
|
|
4803
|
-
}
|
|
4804
|
-
}
|
|
4805
|
-
}
|
|
4852
|
+
function hasClientControlledValues(obj, depth = 0) {
|
|
4853
|
+
if (depth > MAX_PROJECTION_WALK_DEPTH)
|
|
4854
|
+
return false;
|
|
4855
|
+
for (const value of Object.values(obj)) {
|
|
4856
|
+
if (isForcedValue(value))
|
|
4806
4857
|
continue;
|
|
4807
|
-
}
|
|
4808
4858
|
if (value === true)
|
|
4809
|
-
continue;
|
|
4810
|
-
if (value.orderBy || value.cursor || value.take || value.skip)
|
|
4811
4859
|
return true;
|
|
4812
|
-
if (
|
|
4860
|
+
if (isPlainObject(value) && hasClientControlledValues(value, depth + 1)) {
|
|
4813
4861
|
return true;
|
|
4814
4862
|
}
|
|
4815
|
-
if (value.select && checkSelectForClientArgs(value.select))
|
|
4816
|
-
return true;
|
|
4817
|
-
if (value.include && checkIncludeForClientArgs(value.include))
|
|
4818
|
-
return true;
|
|
4819
4863
|
}
|
|
4820
4864
|
return false;
|
|
4821
4865
|
}
|
|
4822
4866
|
function hasNestedClientControlledArgs(shape) {
|
|
4867
|
+
const predicate = () => false;
|
|
4823
4868
|
if (shape.include) {
|
|
4824
|
-
if (
|
|
4869
|
+
if (walkForClientContent(shape.include, predicate, 0))
|
|
4825
4870
|
return true;
|
|
4826
4871
|
}
|
|
4827
4872
|
if (shape.select) {
|
|
4828
|
-
if (
|
|
4873
|
+
if (walkForClientContent(shape.select, predicate, 0))
|
|
4829
4874
|
return true;
|
|
4830
4875
|
}
|
|
4831
4876
|
return false;
|
|
@@ -4897,77 +4942,62 @@ function createModelGuardExtension(config) {
|
|
|
4897
4942
|
const whereBuiltCache = /* @__PURE__ */ new Map();
|
|
4898
4943
|
const projectionCache = /* @__PURE__ */ new Map();
|
|
4899
4944
|
const uniqueWhereCache = /* @__PURE__ */ new Map();
|
|
4945
|
+
function memoize(cache, key, wasDynamic, build) {
|
|
4946
|
+
if (wasDynamic)
|
|
4947
|
+
return build();
|
|
4948
|
+
const cached = cache.get(key);
|
|
4949
|
+
if (cached)
|
|
4950
|
+
return cached;
|
|
4951
|
+
const built = build();
|
|
4952
|
+
cache.set(key, built);
|
|
4953
|
+
return built;
|
|
4954
|
+
}
|
|
4900
4955
|
function getReadShape(method, queryShape, matchedKey, wasDynamic) {
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
const built = queryBuilder.buildShapeZodSchema(
|
|
4956
|
+
return memoize(
|
|
4957
|
+
readShapeCache,
|
|
4958
|
+
`${method}\0${matchedKey}`,
|
|
4959
|
+
wasDynamic,
|
|
4960
|
+
() => queryBuilder.buildShapeZodSchema(
|
|
4907
4961
|
modelName,
|
|
4908
4962
|
method,
|
|
4909
4963
|
queryShape
|
|
4910
|
-
)
|
|
4911
|
-
readShapeCache.set(cacheKey, built);
|
|
4912
|
-
return built;
|
|
4913
|
-
}
|
|
4914
|
-
return queryBuilder.buildShapeZodSchema(
|
|
4915
|
-
modelName,
|
|
4916
|
-
method,
|
|
4917
|
-
queryShape
|
|
4964
|
+
)
|
|
4918
4965
|
);
|
|
4919
4966
|
}
|
|
4920
4967
|
function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4968
|
+
const skipCache = wasDynamic || hasDataRefines(dataConfig);
|
|
4969
|
+
return memoize(
|
|
4970
|
+
dataSchemaCache,
|
|
4971
|
+
`${mode}\0${matchedKey}`,
|
|
4972
|
+
skipCache,
|
|
4973
|
+
() => buildDataSchema(
|
|
4927
4974
|
modelName,
|
|
4928
4975
|
dataConfig,
|
|
4929
4976
|
mode,
|
|
4930
4977
|
typeMap,
|
|
4978
|
+
uniqueMap,
|
|
4979
|
+
enumMap,
|
|
4980
|
+
scalarBase,
|
|
4931
4981
|
schemaBuilder,
|
|
4932
4982
|
zodDefaults
|
|
4933
|
-
)
|
|
4934
|
-
dataSchemaCache.set(cacheKey, built);
|
|
4935
|
-
return built;
|
|
4936
|
-
}
|
|
4937
|
-
return buildDataSchema(
|
|
4938
|
-
modelName,
|
|
4939
|
-
dataConfig,
|
|
4940
|
-
mode,
|
|
4941
|
-
typeMap,
|
|
4942
|
-
schemaBuilder,
|
|
4943
|
-
zodDefaults
|
|
4983
|
+
)
|
|
4944
4984
|
);
|
|
4945
4985
|
}
|
|
4946
4986
|
function getWhereBuilt(whereConfig, matchedKey, wasDynamic) {
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
return built;
|
|
4954
|
-
}
|
|
4955
|
-
return queryBuilder.buildWhereSchema(modelName, whereConfig);
|
|
4987
|
+
return memoize(
|
|
4988
|
+
whereBuiltCache,
|
|
4989
|
+
matchedKey,
|
|
4990
|
+
wasDynamic,
|
|
4991
|
+
() => queryBuilder.buildWhereSchema(modelName, whereConfig)
|
|
4992
|
+
);
|
|
4956
4993
|
}
|
|
4957
4994
|
function getUniqueWhereBuilt(whereConfig, matchedKey, wasDynamic) {
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
modelName,
|
|
4965
|
-
whereConfig
|
|
4966
|
-
);
|
|
4967
|
-
uniqueWhereCache.set(cacheKey, built);
|
|
4968
|
-
return built;
|
|
4969
|
-
}
|
|
4970
|
-
return queryBuilder.buildUniqueWhereSchema(modelName, whereConfig);
|
|
4995
|
+
return memoize(
|
|
4996
|
+
uniqueWhereCache,
|
|
4997
|
+
`unique\0${matchedKey}`,
|
|
4998
|
+
wasDynamic,
|
|
4999
|
+
() => queryBuilder.buildUniqueWhereSchema(modelName, whereConfig)
|
|
5000
|
+
);
|
|
4971
5001
|
}
|
|
4972
5002
|
function buildProjectionSchema(shape) {
|
|
4973
5003
|
const schemaFields = {};
|
|
@@ -4994,7 +5024,7 @@ function createModelGuardExtension(config) {
|
|
|
4994
5024
|
forcedSelectCountWhere = result.forcedCountWhere;
|
|
4995
5025
|
}
|
|
4996
5026
|
return {
|
|
4997
|
-
zodSchema:
|
|
5027
|
+
zodSchema: import_zod11.z.object(schemaFields).strict(),
|
|
4998
5028
|
forcedIncludeTree,
|
|
4999
5029
|
forcedSelectTree,
|
|
5000
5030
|
forcedIncludeCountWhere,
|
|
@@ -5002,16 +5032,12 @@ function createModelGuardExtension(config) {
|
|
|
5002
5032
|
};
|
|
5003
5033
|
}
|
|
5004
5034
|
function getProjection(shape, matchedKey, wasDynamic) {
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
projectionCache.set(cacheKey, built);
|
|
5012
|
-
return built;
|
|
5013
|
-
}
|
|
5014
|
-
return buildProjectionSchema(shape);
|
|
5035
|
+
return memoize(
|
|
5036
|
+
projectionCache,
|
|
5037
|
+
`projection\0${matchedKey}`,
|
|
5038
|
+
wasDynamic,
|
|
5039
|
+
() => buildProjectionSchema(shape)
|
|
5040
|
+
);
|
|
5015
5041
|
}
|
|
5016
5042
|
function resolveProjection(shape, parsed, method, matchedKey, wasDynamic) {
|
|
5017
5043
|
const hasBodyProjection = "select" in parsed || "include" in parsed;
|
|
@@ -5205,24 +5231,11 @@ function createModelGuardExtension(config) {
|
|
|
5205
5231
|
const hasShapeProjection = !!resolved.shape.select || !!resolved.shape.include;
|
|
5206
5232
|
if (!hasShapeProjection)
|
|
5207
5233
|
return resolved.body;
|
|
5208
|
-
const defaultProjection = buildDefaultProjectionBody(resolved.shape);
|
|
5209
5234
|
const hasBodyProjection = "select" in resolved.body || "include" in resolved.body;
|
|
5210
|
-
if (
|
|
5211
|
-
return
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
if ("select" in resolved.body && "select" in defaultProjection && isPlainObject(resolved.body.select) && isPlainObject(defaultProjection.select)) {
|
|
5215
|
-
merged.select = applyClientProjectionOverrides(
|
|
5216
|
-
defaultProjection.select,
|
|
5217
|
-
resolved.body.select
|
|
5218
|
-
);
|
|
5219
|
-
} else if ("include" in resolved.body && "include" in defaultProjection && isPlainObject(resolved.body.include) && isPlainObject(defaultProjection.include)) {
|
|
5220
|
-
merged.include = applyClientProjectionOverrides(
|
|
5221
|
-
defaultProjection.include,
|
|
5222
|
-
resolved.body.include
|
|
5223
|
-
);
|
|
5224
|
-
}
|
|
5225
|
-
return merged;
|
|
5235
|
+
if (hasBodyProjection)
|
|
5236
|
+
return resolved.body;
|
|
5237
|
+
const defaultProjection = buildDefaultProjectionBody(resolved.shape);
|
|
5238
|
+
return { ...resolved.body, ...defaultProjection };
|
|
5226
5239
|
}
|
|
5227
5240
|
function makeReadMethod(method) {
|
|
5228
5241
|
return (body) => {
|
|
@@ -5255,29 +5268,21 @@ function createModelGuardExtension(config) {
|
|
|
5255
5268
|
function makeCreateMethod(method) {
|
|
5256
5269
|
const isBatch = BATCH_CREATE_METHODS.has(method);
|
|
5257
5270
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_MANY_PROJECTION;
|
|
5261
|
-
} else if (isBatch) {
|
|
5262
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_MANY;
|
|
5263
|
-
} else if (supportsProjection) {
|
|
5264
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_PROJECTION;
|
|
5265
|
-
} else {
|
|
5266
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE;
|
|
5267
|
-
}
|
|
5268
|
-
const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_CREATE_PROJECTION : VALID_SHAPE_KEYS_CREATE;
|
|
5271
|
+
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5272
|
+
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5269
5273
|
return (body) => {
|
|
5270
5274
|
const caller = resolveCaller();
|
|
5271
5275
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5272
5276
|
if (!resolved.shape.data) {
|
|
5273
5277
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5274
5278
|
}
|
|
5275
|
-
|
|
5279
|
+
validateAllowedKeys(
|
|
5276
5280
|
resolved.shape,
|
|
5277
5281
|
allowedShapeKeys,
|
|
5278
|
-
method
|
|
5282
|
+
method,
|
|
5283
|
+
"shape"
|
|
5279
5284
|
);
|
|
5280
|
-
|
|
5285
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, method, "body");
|
|
5281
5286
|
const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
|
|
5282
5287
|
validateCreateCompleteness(
|
|
5283
5288
|
modelName,
|
|
@@ -5336,20 +5341,21 @@ function createModelGuardExtension(config) {
|
|
|
5336
5341
|
const isUniqueWhere = method === "update";
|
|
5337
5342
|
const isBulk = BULK_MUTATION_METHODS.has(method);
|
|
5338
5343
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5339
|
-
const allowedBodyKeys = supportsProjection
|
|
5340
|
-
const allowedShapeKeys = supportsProjection
|
|
5344
|
+
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5345
|
+
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5341
5346
|
return (body) => {
|
|
5342
5347
|
const caller = resolveCaller();
|
|
5343
5348
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5344
5349
|
if (!resolved.shape.data) {
|
|
5345
5350
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5346
5351
|
}
|
|
5347
|
-
|
|
5352
|
+
validateAllowedKeys(
|
|
5348
5353
|
resolved.shape,
|
|
5349
5354
|
allowedShapeKeys,
|
|
5350
|
-
method
|
|
5355
|
+
method,
|
|
5356
|
+
"shape"
|
|
5351
5357
|
);
|
|
5352
|
-
|
|
5358
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, method, "body");
|
|
5353
5359
|
if (isBulk && !resolved.shape.where) {
|
|
5354
5360
|
throw new ShapeError(
|
|
5355
5361
|
`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`
|
|
@@ -5417,20 +5423,21 @@ function createModelGuardExtension(config) {
|
|
|
5417
5423
|
const isUniqueWhere = method === "delete";
|
|
5418
5424
|
const isBulk = BULK_MUTATION_METHODS.has(method);
|
|
5419
5425
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5420
|
-
const allowedBodyKeys = supportsProjection
|
|
5421
|
-
const allowedShapeKeys = supportsProjection
|
|
5426
|
+
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5427
|
+
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5422
5428
|
return (body) => {
|
|
5423
5429
|
const caller = resolveCaller();
|
|
5424
5430
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5425
5431
|
if (resolved.shape.data) {
|
|
5426
5432
|
throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
|
|
5427
5433
|
}
|
|
5428
|
-
|
|
5434
|
+
validateAllowedKeys(
|
|
5429
5435
|
resolved.shape,
|
|
5430
5436
|
allowedShapeKeys,
|
|
5431
|
-
method
|
|
5437
|
+
method,
|
|
5438
|
+
"shape"
|
|
5432
5439
|
);
|
|
5433
|
-
|
|
5440
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, method, "body");
|
|
5434
5441
|
if (isBulk && !resolved.shape.where) {
|
|
5435
5442
|
throw new ShapeError(
|
|
5436
5443
|
`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`
|
|
@@ -5483,6 +5490,8 @@ function createModelGuardExtension(config) {
|
|
|
5483
5490
|
};
|
|
5484
5491
|
}
|
|
5485
5492
|
function makeUpsertMethod() {
|
|
5493
|
+
const allowedBodyKeys = getAllowedBodyKeys("upsert", true);
|
|
5494
|
+
const allowedShapeKeys = getAllowedShapeKeys("upsert", true);
|
|
5486
5495
|
return (body) => {
|
|
5487
5496
|
const caller = resolveCaller();
|
|
5488
5497
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
@@ -5500,15 +5509,17 @@ function createModelGuardExtension(config) {
|
|
|
5500
5509
|
if (!resolved.shape.where) {
|
|
5501
5510
|
throw new ShapeError('Guard shape requires "where" for upsert');
|
|
5502
5511
|
}
|
|
5503
|
-
|
|
5512
|
+
validateAllowedKeys(
|
|
5504
5513
|
resolved.shape,
|
|
5505
|
-
|
|
5506
|
-
"upsert"
|
|
5514
|
+
allowedShapeKeys,
|
|
5515
|
+
"upsert",
|
|
5516
|
+
"shape"
|
|
5507
5517
|
);
|
|
5508
|
-
|
|
5518
|
+
validateAllowedKeys(
|
|
5509
5519
|
resolved.body,
|
|
5510
|
-
|
|
5511
|
-
"upsert"
|
|
5520
|
+
allowedBodyKeys,
|
|
5521
|
+
"upsert",
|
|
5522
|
+
"body"
|
|
5512
5523
|
);
|
|
5513
5524
|
validateUniqueWhereShapeConfig(
|
|
5514
5525
|
modelName,
|
|
@@ -5598,12 +5609,7 @@ function createModelGuardExtension(config) {
|
|
|
5598
5609
|
try {
|
|
5599
5610
|
return fn(body);
|
|
5600
5611
|
} catch (err) {
|
|
5601
|
-
|
|
5602
|
-
throw new ShapeError(`Validation failed: ${formatZodError(err)}`, {
|
|
5603
|
-
cause: err
|
|
5604
|
-
});
|
|
5605
|
-
}
|
|
5606
|
-
throw err;
|
|
5612
|
+
throw toShapeError(err);
|
|
5607
5613
|
}
|
|
5608
5614
|
};
|
|
5609
5615
|
}
|
|
@@ -5636,6 +5642,15 @@ function createModelGuardExtension(config) {
|
|
|
5636
5642
|
}
|
|
5637
5643
|
|
|
5638
5644
|
// src/runtime/guard.ts
|
|
5645
|
+
function wrapParseFn(fn) {
|
|
5646
|
+
return (...args) => {
|
|
5647
|
+
try {
|
|
5648
|
+
return fn(...args);
|
|
5649
|
+
} catch (err) {
|
|
5650
|
+
throw toShapeError(err);
|
|
5651
|
+
}
|
|
5652
|
+
};
|
|
5653
|
+
}
|
|
5639
5654
|
function createGuard(config) {
|
|
5640
5655
|
const scalarBase = createScalarBase(
|
|
5641
5656
|
config.guardConfig.strictDecimal ?? false
|
|
@@ -5657,14 +5672,6 @@ function createGuard(config) {
|
|
|
5657
5672
|
warn: (msg) => console.warn(msg)
|
|
5658
5673
|
};
|
|
5659
5674
|
const wrapZodErrors = config.wrapZodErrors ?? false;
|
|
5660
|
-
function rethrowZod(err) {
|
|
5661
|
-
if (err instanceof import_zod10.ZodError) {
|
|
5662
|
-
throw new ShapeError(`Validation failed: ${formatZodError(err)}`, {
|
|
5663
|
-
cause: err
|
|
5664
|
-
});
|
|
5665
|
-
}
|
|
5666
|
-
throw err;
|
|
5667
|
-
}
|
|
5668
5675
|
return {
|
|
5669
5676
|
input: (model, opts) => {
|
|
5670
5677
|
const result = schemaBuilder.buildInputSchema(model, opts);
|
|
@@ -5672,13 +5679,7 @@ function createGuard(config) {
|
|
|
5672
5679
|
return result;
|
|
5673
5680
|
return {
|
|
5674
5681
|
schema: result.schema,
|
|
5675
|
-
parse(
|
|
5676
|
-
try {
|
|
5677
|
-
return result.parse(data);
|
|
5678
|
-
} catch (err) {
|
|
5679
|
-
rethrowZod(err);
|
|
5680
|
-
}
|
|
5681
|
-
}
|
|
5682
|
+
parse: wrapParseFn(result.parse)
|
|
5682
5683
|
};
|
|
5683
5684
|
},
|
|
5684
5685
|
model: (model, opts) => schemaBuilder.buildModelSchema(model, opts),
|
|
@@ -5688,13 +5689,7 @@ function createGuard(config) {
|
|
|
5688
5689
|
return qs;
|
|
5689
5690
|
return {
|
|
5690
5691
|
schemas: qs.schemas,
|
|
5691
|
-
parse(
|
|
5692
|
-
try {
|
|
5693
|
-
return qs.parse(body, opts);
|
|
5694
|
-
} catch (err) {
|
|
5695
|
-
rethrowZod(err);
|
|
5696
|
-
}
|
|
5697
|
-
}
|
|
5692
|
+
parse: wrapParseFn(qs.parse)
|
|
5698
5693
|
};
|
|
5699
5694
|
},
|
|
5700
5695
|
extension: (contextFn) => {
|