prisma-guard 1.27.0 → 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 +1664 -1663
- 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 +1663 -1662
- 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))
|
|
@@ -1027,12 +1139,18 @@ function tryInlineForcedField(result, field, forcedValue) {
|
|
|
1027
1139
|
if (!isPlainObject(forcedValue))
|
|
1028
1140
|
return false;
|
|
1029
1141
|
const existing = result[field];
|
|
1030
|
-
if (!isPlainObject(existing))
|
|
1031
|
-
|
|
1142
|
+
if (!isPlainObject(existing)) {
|
|
1143
|
+
const merged2 = { equals: existing };
|
|
1144
|
+
for (const [op, value] of Object.entries(forcedValue)) {
|
|
1145
|
+
merged2[op] = deepClone(value);
|
|
1146
|
+
}
|
|
1147
|
+
result[field] = merged2;
|
|
1148
|
+
return true;
|
|
1149
|
+
}
|
|
1032
1150
|
const merged = { ...existing };
|
|
1033
1151
|
for (const [op, value] of Object.entries(forcedValue)) {
|
|
1034
1152
|
if (op in merged) {
|
|
1035
|
-
if (!
|
|
1153
|
+
if (!deepEqual(merged[op], value)) {
|
|
1036
1154
|
throw new ShapeError(
|
|
1037
1155
|
`Conflicting where values for "${field}.${op}": client provided a different value than the forced shape`
|
|
1038
1156
|
);
|
|
@@ -1063,6 +1181,17 @@ function mergeWhereForced(where, forced) {
|
|
|
1063
1181
|
if (Object.keys(forced.conditions).length > 0) {
|
|
1064
1182
|
const remaining = {};
|
|
1065
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
|
+
}
|
|
1066
1195
|
const inlined = tryInlineForcedField(result, field, forcedValue);
|
|
1067
1196
|
if (!inlined) {
|
|
1068
1197
|
remaining[field] = deepClone(forcedValue);
|
|
@@ -1078,32 +1207,6 @@ function mergeWhereForced(where, forced) {
|
|
|
1078
1207
|
}
|
|
1079
1208
|
return result;
|
|
1080
1209
|
}
|
|
1081
|
-
function uniqueValuesEqual(a, b) {
|
|
1082
|
-
if (a === b)
|
|
1083
|
-
return true;
|
|
1084
|
-
if (a === null || b === null)
|
|
1085
|
-
return false;
|
|
1086
|
-
if (typeof a !== typeof b)
|
|
1087
|
-
return false;
|
|
1088
|
-
if (a instanceof Date && b instanceof Date) {
|
|
1089
|
-
return a.getTime() === b.getTime();
|
|
1090
|
-
}
|
|
1091
|
-
if (Array.isArray(a)) {
|
|
1092
|
-
if (!Array.isArray(b))
|
|
1093
|
-
return false;
|
|
1094
|
-
if (a.length !== b.length)
|
|
1095
|
-
return false;
|
|
1096
|
-
return a.every((v, i) => uniqueValuesEqual(v, b[i]));
|
|
1097
|
-
}
|
|
1098
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1099
|
-
const aKeys = Object.keys(a);
|
|
1100
|
-
const bKeys = Object.keys(b);
|
|
1101
|
-
if (aKeys.length !== bKeys.length)
|
|
1102
|
-
return false;
|
|
1103
|
-
return aKeys.every((key) => key in b && uniqueValuesEqual(a[key], b[key]));
|
|
1104
|
-
}
|
|
1105
|
-
return false;
|
|
1106
|
-
}
|
|
1107
1210
|
function mergeUniqueValue(target, key, value) {
|
|
1108
1211
|
const cloned = deepClone(value);
|
|
1109
1212
|
if (!(key in target)) {
|
|
@@ -1114,7 +1217,7 @@ function mergeUniqueValue(target, key, value) {
|
|
|
1114
1217
|
if (isPlainObject(existing) && isPlainObject(cloned)) {
|
|
1115
1218
|
const merged = { ...existing };
|
|
1116
1219
|
for (const [nestedKey, nestedValue] of Object.entries(cloned)) {
|
|
1117
|
-
if (nestedKey in merged && !
|
|
1220
|
+
if (nestedKey in merged && !deepEqual(merged[nestedKey], nestedValue)) {
|
|
1118
1221
|
throw new ShapeError(
|
|
1119
1222
|
`Conflicting unique where value for "${key}.${nestedKey}"`
|
|
1120
1223
|
);
|
|
@@ -1124,7 +1227,7 @@ function mergeUniqueValue(target, key, value) {
|
|
|
1124
1227
|
target[key] = merged;
|
|
1125
1228
|
return;
|
|
1126
1229
|
}
|
|
1127
|
-
if (!
|
|
1230
|
+
if (!deepEqual(existing, cloned)) {
|
|
1128
1231
|
throw new ShapeError(`Conflicting unique where value for "${key}"`);
|
|
1129
1232
|
}
|
|
1130
1233
|
}
|
|
@@ -1151,7 +1254,30 @@ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
|
|
|
1151
1254
|
throw new ShapeError('Request cannot define both "include" and "select"');
|
|
1152
1255
|
}
|
|
1153
1256
|
if ("where" in bodyObj) {
|
|
1154
|
-
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
|
+
}
|
|
1155
1281
|
const { where: _, ...rest } = bodyObj;
|
|
1156
1282
|
parseable = rest;
|
|
1157
1283
|
} else if (isUniqueMethod && hasWhereForced(built.forcedWhere) && isPlainObject(bodyObj.where)) {
|
|
@@ -1227,6 +1353,86 @@ function buildCountForPlacement(countWhere) {
|
|
|
1227
1353
|
}
|
|
1228
1354
|
return { _count: { select: countSelect } };
|
|
1229
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
|
+
}
|
|
1230
1436
|
function applyForcedTree(validated, key, tree) {
|
|
1231
1437
|
const container = validated[key];
|
|
1232
1438
|
if (!container)
|
|
@@ -1235,89 +1441,13 @@ function applyForcedTree(validated, key, tree) {
|
|
|
1235
1441
|
const relVal = container[relName];
|
|
1236
1442
|
if (relVal === void 0)
|
|
1237
1443
|
continue;
|
|
1238
|
-
|
|
1239
|
-
const expanded = {};
|
|
1240
|
-
if (forced.where && hasWhereForced(forced.where)) {
|
|
1241
|
-
expanded.where = mergeWhereForced(void 0, forced.where);
|
|
1242
|
-
}
|
|
1243
|
-
if (forced.include) {
|
|
1244
|
-
expanded.include = buildForcedOnlyContainer(forced.include);
|
|
1245
|
-
applyForcedTree(expanded, "include", forced.include);
|
|
1246
|
-
}
|
|
1247
|
-
if (forced.select) {
|
|
1248
|
-
expanded.select = buildForcedOnlyContainer(forced.select);
|
|
1249
|
-
applyForcedTree(expanded, "select", forced.select);
|
|
1250
|
-
}
|
|
1251
|
-
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1252
|
-
const placement = forced._countWherePlacement ?? "include";
|
|
1253
|
-
if (!expanded[placement])
|
|
1254
|
-
expanded[placement] = {};
|
|
1255
|
-
const placementObj = expanded[placement];
|
|
1256
|
-
Object.assign(placementObj, buildCountForPlacement(forced._countWhere));
|
|
1257
|
-
}
|
|
1258
|
-
if (expanded.include && expanded.select) {
|
|
1259
|
-
throw new ShapeError(
|
|
1260
|
-
`Forced tree for relation "${relName}" produces both "include" and "select". Prisma does not allow both at the same level.`
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
container[relName] = Object.keys(expanded).length > 0 ? expanded : true;
|
|
1264
|
-
continue;
|
|
1265
|
-
}
|
|
1266
|
-
if (isPlainObject(relVal)) {
|
|
1267
|
-
const relObj = relVal;
|
|
1268
|
-
if (forced.where && hasWhereForced(forced.where)) {
|
|
1269
|
-
relObj.where = mergeWhereForced(
|
|
1270
|
-
relObj.where,
|
|
1271
|
-
forced.where
|
|
1272
|
-
);
|
|
1273
|
-
}
|
|
1274
|
-
if (forced.include) {
|
|
1275
|
-
if (!relObj.include) {
|
|
1276
|
-
relObj.include = buildForcedOnlyContainer(forced.include);
|
|
1277
|
-
}
|
|
1278
|
-
applyForcedTree(relObj, "include", forced.include);
|
|
1279
|
-
}
|
|
1280
|
-
if (forced.select) {
|
|
1281
|
-
if (!relObj.select) {
|
|
1282
|
-
relObj.select = buildForcedOnlyContainer(forced.select);
|
|
1283
|
-
}
|
|
1284
|
-
applyForcedTree(relObj, "select", forced.select);
|
|
1285
|
-
}
|
|
1286
|
-
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1287
|
-
const placement = forced._countWherePlacement ?? "include";
|
|
1288
|
-
const projContainer = relObj[placement];
|
|
1289
|
-
if (projContainer) {
|
|
1290
|
-
applyForcedCountWhere(projContainer, forced._countWhere);
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
if (relObj.include && relObj.select) {
|
|
1294
|
-
throw new ShapeError(
|
|
1295
|
-
`Relation "${relName}" has both "include" and "select" after forced tree merge. Prisma does not allow both at the same level.`
|
|
1296
|
-
);
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1444
|
+
container[relName] = applyForcedToRelValue(relName, relVal, forced);
|
|
1299
1445
|
}
|
|
1300
1446
|
}
|
|
1301
1447
|
function buildForcedOnlyContainer(tree) {
|
|
1302
1448
|
const result = {};
|
|
1303
1449
|
for (const [relName, forced] of Object.entries(tree)) {
|
|
1304
|
-
const nested =
|
|
1305
|
-
if (forced.where && hasWhereForced(forced.where)) {
|
|
1306
|
-
nested.where = mergeWhereForced(void 0, forced.where);
|
|
1307
|
-
}
|
|
1308
|
-
if (forced.include) {
|
|
1309
|
-
nested.include = buildForcedOnlyContainer(forced.include);
|
|
1310
|
-
}
|
|
1311
|
-
if (forced.select) {
|
|
1312
|
-
nested.select = buildForcedOnlyContainer(forced.select);
|
|
1313
|
-
}
|
|
1314
|
-
if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
|
|
1315
|
-
const placement = forced._countWherePlacement ?? "include";
|
|
1316
|
-
if (!nested[placement])
|
|
1317
|
-
nested[placement] = {};
|
|
1318
|
-
const placementObj = nested[placement];
|
|
1319
|
-
Object.assign(placementObj, buildCountForPlacement(forced._countWhere));
|
|
1320
|
-
}
|
|
1450
|
+
const nested = collectSubtree(forced);
|
|
1321
1451
|
result[relName] = Object.keys(nested).length > 0 ? nested : true;
|
|
1322
1452
|
}
|
|
1323
1453
|
return result;
|
|
@@ -1333,11 +1463,15 @@ function applyForcedCountWhere(container, forcedCountWhere) {
|
|
|
1333
1463
|
const selectObj = selectVal;
|
|
1334
1464
|
for (const [relName, forced] of Object.entries(forcedCountWhere)) {
|
|
1335
1465
|
const relVal = selectObj[relName];
|
|
1336
|
-
if (relVal === void 0)
|
|
1466
|
+
if (relVal === void 0) {
|
|
1467
|
+
selectObj[relName] = { where: mergeWhereForced(void 0, forced) };
|
|
1337
1468
|
continue;
|
|
1469
|
+
}
|
|
1338
1470
|
if (relVal === true) {
|
|
1339
1471
|
selectObj[relName] = { where: mergeWhereForced(void 0, forced) };
|
|
1340
|
-
|
|
1472
|
+
continue;
|
|
1473
|
+
}
|
|
1474
|
+
if (isPlainObject(relVal)) {
|
|
1341
1475
|
const relObj = relVal;
|
|
1342
1476
|
relObj.where = mergeWhereForced(
|
|
1343
1477
|
relObj.where,
|
|
@@ -1346,12 +1480,6 @@ function applyForcedCountWhere(container, forcedCountWhere) {
|
|
|
1346
1480
|
}
|
|
1347
1481
|
}
|
|
1348
1482
|
}
|
|
1349
|
-
function formatUniqueConstraint(constraint) {
|
|
1350
|
-
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
1351
|
-
}
|
|
1352
|
-
function formatUniqueConstraints(constraints) {
|
|
1353
|
-
return constraints.map(formatUniqueConstraint).join(" | ");
|
|
1354
|
-
}
|
|
1355
1483
|
function resolvedWhereCoversConstraint(where, constraint) {
|
|
1356
1484
|
if (constraint.fields.length === 1) {
|
|
1357
1485
|
return constraint.fields[0] in where;
|
|
@@ -1457,7 +1585,12 @@ function stripUniqueWhereForcedInput(where, forced) {
|
|
|
1457
1585
|
const currentValue = result[key];
|
|
1458
1586
|
if (isPlainObject(currentValue) && isPlainObject(forcedValue)) {
|
|
1459
1587
|
const nested = { ...currentValue };
|
|
1460
|
-
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
|
+
}
|
|
1461
1594
|
delete nested[nestedKey];
|
|
1462
1595
|
}
|
|
1463
1596
|
if (Object.keys(nested).length === 0) {
|
|
@@ -1467,11 +1600,25 @@ function stripUniqueWhereForcedInput(where, forced) {
|
|
|
1467
1600
|
}
|
|
1468
1601
|
continue;
|
|
1469
1602
|
}
|
|
1603
|
+
if (!deepEqual(currentValue, forcedValue)) {
|
|
1604
|
+
throw new ShapeError(
|
|
1605
|
+
`Client unique where value for "${key}" conflicts with forced value`
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1470
1608
|
delete result[key];
|
|
1471
1609
|
}
|
|
1472
1610
|
return result;
|
|
1473
1611
|
}
|
|
1474
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
|
+
|
|
1475
1622
|
// src/runtime/query-builder-where.ts
|
|
1476
1623
|
var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Bytes"]);
|
|
1477
1624
|
var STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
@@ -1485,47 +1632,40 @@ var JSON_STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
|
1485
1632
|
"string_starts_with",
|
|
1486
1633
|
"string_ends_with"
|
|
1487
1634
|
]);
|
|
1635
|
+
var NEGATIVE_RELATION_OPS = /* @__PURE__ */ new Set(["none", "isNot"]);
|
|
1488
1636
|
var MAX_WHERE_DEPTH = 10;
|
|
1489
|
-
function safeStringify(
|
|
1490
|
-
if (typeof
|
|
1491
|
-
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();
|
|
1492
1647
|
try {
|
|
1493
|
-
|
|
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;
|
|
1494
1665
|
} catch {
|
|
1495
|
-
return String(
|
|
1666
|
+
return String(value);
|
|
1496
1667
|
}
|
|
1497
1668
|
}
|
|
1498
|
-
function forcedValuesEqual(a, b) {
|
|
1499
|
-
if (a === b)
|
|
1500
|
-
return true;
|
|
1501
|
-
if (a === null || b === null)
|
|
1502
|
-
return false;
|
|
1503
|
-
if (typeof a !== typeof b)
|
|
1504
|
-
return false;
|
|
1505
|
-
if (typeof a === "bigint")
|
|
1506
|
-
return a === b;
|
|
1507
|
-
if (a instanceof Date && b instanceof Date)
|
|
1508
|
-
return a.getTime() === b.getTime();
|
|
1509
|
-
if (a instanceof RegExp && b instanceof RegExp) {
|
|
1510
|
-
return a.source === b.source && a.flags === b.flags;
|
|
1511
|
-
}
|
|
1512
|
-
if (typeof a !== "object")
|
|
1513
|
-
return false;
|
|
1514
|
-
if (Array.isArray(a)) {
|
|
1515
|
-
if (!Array.isArray(b))
|
|
1516
|
-
return false;
|
|
1517
|
-
if (a.length !== b.length)
|
|
1518
|
-
return false;
|
|
1519
|
-
return a.every((v, i) => forcedValuesEqual(v, b[i]));
|
|
1520
|
-
}
|
|
1521
|
-
if (!isPlainObject(a) || !isPlainObject(b))
|
|
1522
|
-
return false;
|
|
1523
|
-
const aKeys = Object.keys(a);
|
|
1524
|
-
const bKeys = Object.keys(b);
|
|
1525
|
-
if (aKeys.length !== bKeys.length)
|
|
1526
|
-
return false;
|
|
1527
|
-
return aKeys.every((k) => k in b && forcedValuesEqual(a[k], b[k]));
|
|
1528
|
-
}
|
|
1529
1669
|
function mergeScalarConditions(target, source) {
|
|
1530
1670
|
for (const [field, ops] of Object.entries(source)) {
|
|
1531
1671
|
const existing = target[field];
|
|
@@ -1543,7 +1683,7 @@ function mergeScalarConditions(target, source) {
|
|
|
1543
1683
|
for (const [op, val] of Object.entries(ops)) {
|
|
1544
1684
|
if (op in existing) {
|
|
1545
1685
|
const existingVal = existing[op];
|
|
1546
|
-
if (!
|
|
1686
|
+
if (!deepEqual(existingVal, val)) {
|
|
1547
1687
|
throw new ShapeError(
|
|
1548
1688
|
`Conflicting forced where values for "${field}.${op}": shape defines both ${safeStringify(existingVal)} and ${safeStringify(val)}`
|
|
1549
1689
|
);
|
|
@@ -1553,7 +1693,7 @@ function mergeScalarConditions(target, source) {
|
|
|
1553
1693
|
Object.assign(existing, ops);
|
|
1554
1694
|
continue;
|
|
1555
1695
|
}
|
|
1556
|
-
if (!
|
|
1696
|
+
if (!deepEqual(existing, ops)) {
|
|
1557
1697
|
throw new ShapeError(`Conflicting forced where values for "${field}"`);
|
|
1558
1698
|
}
|
|
1559
1699
|
}
|
|
@@ -1644,27 +1784,27 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1644
1784
|
scalarConditions
|
|
1645
1785
|
);
|
|
1646
1786
|
}
|
|
1647
|
-
|
|
1787
|
+
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1788
|
+
for (const key of Object.keys(whereConfig)) {
|
|
1648
1789
|
if (COMBINATOR_KEYS.has(key))
|
|
1649
1790
|
continue;
|
|
1650
1791
|
if (!(key in fieldSchemas)) {
|
|
1651
|
-
|
|
1792
|
+
forcedOnlyKeys.add(key);
|
|
1652
1793
|
}
|
|
1653
1794
|
}
|
|
1654
|
-
for (const key of Object.keys(
|
|
1795
|
+
for (const key of Object.keys(scalarConditions)) {
|
|
1796
|
+
if (COMBINATOR_KEYS.has(key))
|
|
1797
|
+
continue;
|
|
1655
1798
|
if (!(key in fieldSchemas)) {
|
|
1656
|
-
fieldSchemas[key] =
|
|
1799
|
+
fieldSchemas[key] = import_zod5.z.object({}).strict().optional();
|
|
1657
1800
|
}
|
|
1658
1801
|
}
|
|
1659
|
-
const
|
|
1660
|
-
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1661
|
-
for (const key of Object.keys(whereConfig)) {
|
|
1662
|
-
if (COMBINATOR_KEYS.has(key))
|
|
1663
|
-
continue;
|
|
1802
|
+
for (const key of Object.keys(relationForced)) {
|
|
1664
1803
|
if (!(key in fieldSchemas)) {
|
|
1665
|
-
|
|
1804
|
+
fieldSchemas[key] = import_zod5.z.object({}).strict().optional();
|
|
1666
1805
|
}
|
|
1667
1806
|
}
|
|
1807
|
+
const schema = Object.keys(fieldSchemas).length > 0 ? import_zod5.z.object(fieldSchemas).strict().optional() : null;
|
|
1668
1808
|
return {
|
|
1669
1809
|
schema,
|
|
1670
1810
|
forced: {
|
|
@@ -1695,12 +1835,12 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1695
1835
|
);
|
|
1696
1836
|
}
|
|
1697
1837
|
if (key === "NOT") {
|
|
1698
|
-
fieldSchemas[key] =
|
|
1838
|
+
fieldSchemas[key] = import_zod5.z.union([
|
|
1699
1839
|
elementSchema,
|
|
1700
|
-
|
|
1840
|
+
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(elementSchema).min(1))
|
|
1701
1841
|
]).optional();
|
|
1702
1842
|
} else {
|
|
1703
|
-
fieldSchemas[key] =
|
|
1843
|
+
fieldSchemas[key] = import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(elementSchema).min(1)).optional();
|
|
1704
1844
|
}
|
|
1705
1845
|
}
|
|
1706
1846
|
if (hasWhereForced(result.forced)) {
|
|
@@ -1769,6 +1909,11 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1769
1909
|
`Empty nested where for relation "${key}.${op}" on model "${model}". Define at least one field.`
|
|
1770
1910
|
);
|
|
1771
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
|
+
}
|
|
1772
1917
|
if (nested.schema) {
|
|
1773
1918
|
if (!hasWhereForced(nested.forced)) {
|
|
1774
1919
|
opSchemas[op] = nested.schema.refine(
|
|
@@ -1793,7 +1938,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1793
1938
|
}
|
|
1794
1939
|
if (hasClientOps) {
|
|
1795
1940
|
const clientOpKeys = Object.keys(opSchemas);
|
|
1796
|
-
const opObjSchema =
|
|
1941
|
+
const opObjSchema = import_zod5.z.object(opSchemas).strict();
|
|
1797
1942
|
if (Object.keys(opForced).length === 0 && !hasForcedNull) {
|
|
1798
1943
|
fieldSchemas[key] = opObjSchema.refine(
|
|
1799
1944
|
(v) => clientOpKeys.some(
|
|
@@ -1879,10 +2024,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1879
2024
|
);
|
|
1880
2025
|
}
|
|
1881
2026
|
if (modeConfigValue === true) {
|
|
1882
|
-
opSchemas.mode =
|
|
2027
|
+
opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
|
|
1883
2028
|
} else {
|
|
1884
2029
|
const actualModeValue = isForcedValue(modeConfigValue) ? modeConfigValue.value : modeConfigValue;
|
|
1885
|
-
const modeSchema =
|
|
2030
|
+
const modeSchema = import_zod5.z.enum(["default", "insensitive"]);
|
|
1886
2031
|
let parsed;
|
|
1887
2032
|
try {
|
|
1888
2033
|
parsed = modeSchema.parse(actualModeValue);
|
|
@@ -1894,10 +2039,10 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1894
2039
|
fieldForced.mode = parsed;
|
|
1895
2040
|
}
|
|
1896
2041
|
} else if (hasModeCompatibleOp) {
|
|
1897
|
-
opSchemas.mode =
|
|
2042
|
+
opSchemas.mode = import_zod5.z.enum(["default", "insensitive"]).optional();
|
|
1898
2043
|
}
|
|
1899
2044
|
if (hasClientOps) {
|
|
1900
|
-
const opObj =
|
|
2045
|
+
const opObj = import_zod5.z.object(opSchemas).strict();
|
|
1901
2046
|
const refined = opObj.refine(
|
|
1902
2047
|
(v) => clientOpKeys.some(
|
|
1903
2048
|
(k) => v[k] !== void 0
|
|
@@ -1913,7 +2058,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1913
2058
|
enumMap,
|
|
1914
2059
|
scalarBase
|
|
1915
2060
|
);
|
|
1916
|
-
fieldSchemas[fieldName] =
|
|
2061
|
+
fieldSchemas[fieldName] = import_zod5.z.union([refined, equalsBase]).optional();
|
|
1917
2062
|
} else {
|
|
1918
2063
|
fieldSchemas[fieldName] = refined.optional();
|
|
1919
2064
|
}
|
|
@@ -1927,15 +2072,8 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
1927
2072
|
(constraint) => constraint.selector === selector
|
|
1928
2073
|
) ?? null;
|
|
1929
2074
|
}
|
|
1930
|
-
function buildDirectUniqueSchema(fieldMeta) {
|
|
1931
|
-
const base = createBaseType(fieldMeta, enumMap, scalarBase);
|
|
1932
|
-
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
1933
|
-
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
1934
|
-
}
|
|
1935
|
-
return base;
|
|
1936
|
-
}
|
|
1937
2075
|
function parseForcedUniqueValue(model, fieldName, fieldMeta, value) {
|
|
1938
|
-
const schema =
|
|
2076
|
+
const schema = buildDirectScalarSchema(fieldMeta, enumMap, scalarBase);
|
|
1939
2077
|
const actual = isForcedValue(value) ? value.value : value;
|
|
1940
2078
|
try {
|
|
1941
2079
|
return schema.parse(actual);
|
|
@@ -2013,7 +2151,11 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2013
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.`
|
|
2014
2152
|
);
|
|
2015
2153
|
}
|
|
2016
|
-
const directSchema2 =
|
|
2154
|
+
const directSchema2 = buildDirectScalarSchema(
|
|
2155
|
+
fieldMeta2,
|
|
2156
|
+
enumMap,
|
|
2157
|
+
scalarBase
|
|
2158
|
+
);
|
|
2017
2159
|
if (fieldValue === true) {
|
|
2018
2160
|
nestedSchemas[fieldName] = directSchema2;
|
|
2019
2161
|
} else {
|
|
@@ -2026,7 +2168,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2026
2168
|
}
|
|
2027
2169
|
}
|
|
2028
2170
|
if (Object.keys(nestedSchemas).length > 0) {
|
|
2029
|
-
fieldSchemas[key] =
|
|
2171
|
+
fieldSchemas[key] = import_zod5.z.object(nestedSchemas).strict();
|
|
2030
2172
|
}
|
|
2031
2173
|
if (Object.keys(forcedCompound).length > 0) {
|
|
2032
2174
|
forcedConditions[key] = forcedCompound;
|
|
@@ -2060,7 +2202,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2060
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 }.`
|
|
2061
2203
|
);
|
|
2062
2204
|
}
|
|
2063
|
-
const directSchema =
|
|
2205
|
+
const directSchema = buildDirectScalarSchema(fieldMeta, enumMap, scalarBase);
|
|
2064
2206
|
if (value === true) {
|
|
2065
2207
|
fieldSchemas[key] = directSchema;
|
|
2066
2208
|
continue;
|
|
@@ -2074,7 +2216,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2074
2216
|
forcedOnlyKeys.add(key);
|
|
2075
2217
|
}
|
|
2076
2218
|
return {
|
|
2077
|
-
schema: Object.keys(fieldSchemas).length > 0 ?
|
|
2219
|
+
schema: Object.keys(fieldSchemas).length > 0 ? import_zod5.z.object(fieldSchemas).strict() : null,
|
|
2078
2220
|
forced: {
|
|
2079
2221
|
conditions: forcedConditions,
|
|
2080
2222
|
relations: {}
|
|
@@ -2086,31 +2228,13 @@ function createWhereBuilder(typeMap, enumMap, scalarBase, uniqueMap = {}) {
|
|
|
2086
2228
|
}
|
|
2087
2229
|
|
|
2088
2230
|
// src/runtime/query-builder-args.ts
|
|
2089
|
-
var
|
|
2231
|
+
var import_zod6 = require("zod");
|
|
2090
2232
|
var UNSUPPORTED_BY_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
|
|
2091
|
-
function requireConfigTrue(config, context) {
|
|
2092
|
-
for (const [key, value] of Object.entries(config)) {
|
|
2093
|
-
if (value !== true) {
|
|
2094
|
-
throw new ShapeError(
|
|
2095
|
-
`Config value for "${key}" in ${context} must be true, got ${typeof value}`
|
|
2096
|
-
);
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
function isPlainRecord(value) {
|
|
2101
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2102
|
-
}
|
|
2103
|
-
function formatUniqueConstraint2(constraint) {
|
|
2104
|
-
return constraint.fields.length === 1 ? constraint.selector : `${constraint.selector}(${constraint.fields.join(", ")})`;
|
|
2105
|
-
}
|
|
2106
|
-
function formatUniqueConstraints2(constraints) {
|
|
2107
|
-
return constraints.map(formatUniqueConstraint2).join(" | ");
|
|
2108
|
-
}
|
|
2109
2233
|
function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
2110
|
-
const sortEnum =
|
|
2111
|
-
const nullsEnum =
|
|
2112
|
-
const sortWithNulls =
|
|
2113
|
-
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]);
|
|
2114
2238
|
function validateScalarOrderByField(fieldName, model, modelFields) {
|
|
2115
2239
|
const fieldMeta = modelFields[fieldName];
|
|
2116
2240
|
if (!fieldMeta)
|
|
@@ -2129,6 +2253,16 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2129
2253
|
);
|
|
2130
2254
|
}
|
|
2131
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
|
+
}
|
|
2132
2266
|
const modelFields = typeMap[model];
|
|
2133
2267
|
if (!modelFields)
|
|
2134
2268
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -2144,53 +2278,35 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2144
2278
|
fieldSchemas[fieldName] = scalarOrderSchema.optional();
|
|
2145
2279
|
continue;
|
|
2146
2280
|
}
|
|
2147
|
-
if (!
|
|
2281
|
+
if (!isPlainObject(config)) {
|
|
2148
2282
|
throw new ShapeError(
|
|
2149
|
-
`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`
|
|
2150
2284
|
);
|
|
2151
2285
|
}
|
|
2152
2286
|
if (!fieldMeta.isRelation) {
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
fieldMeta.isList
|
|
2287
|
+
throw new ShapeError(
|
|
2288
|
+
`orderBy config for scalar field "${model}.${fieldName}" must be true. Operator objects are not valid in orderBy.`
|
|
2156
2289
|
);
|
|
2157
|
-
const opSchemas = {};
|
|
2158
|
-
for (const [op, enabled] of Object.entries(config)) {
|
|
2159
|
-
if (enabled !== true) {
|
|
2160
|
-
throw new ShapeError(
|
|
2161
|
-
`orderBy operator config for "${model}.${fieldName}.${op}" must be true`
|
|
2162
|
-
);
|
|
2163
|
-
}
|
|
2164
|
-
if (!allowedOps.includes(op)) {
|
|
2165
|
-
throw new ShapeError(
|
|
2166
|
-
`Operator "${op}" not supported for orderBy field "${model}.${fieldName}"`
|
|
2167
|
-
);
|
|
2168
|
-
}
|
|
2169
|
-
opSchemas[op] = scalarOrderSchema.optional();
|
|
2170
|
-
}
|
|
2171
|
-
const opKeys = Object.keys(opSchemas);
|
|
2172
|
-
fieldSchemas[fieldName] = import_zod5.z.object(opSchemas).strict().refine(
|
|
2173
|
-
(v) => opKeys.some(
|
|
2174
|
-
(k) => v[k] !== void 0
|
|
2175
|
-
),
|
|
2176
|
-
{
|
|
2177
|
-
message: `orderBy field "${fieldName}" must specify at least one operator`
|
|
2178
|
-
}
|
|
2179
|
-
).optional();
|
|
2180
|
-
continue;
|
|
2181
2290
|
}
|
|
2182
2291
|
if (fieldMeta.isList) {
|
|
2183
|
-
|
|
2292
|
+
const configKeys = Object.keys(config);
|
|
2293
|
+
if (!configKeys.includes("_count")) {
|
|
2184
2294
|
throw new ShapeError(
|
|
2185
2295
|
`To-many relation orderBy "${fieldName}" only supports _count`
|
|
2186
2296
|
);
|
|
2187
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
|
+
}
|
|
2188
2304
|
if (config._count !== true) {
|
|
2189
2305
|
throw new ShapeError(
|
|
2190
2306
|
`orderBy relation aggregate "${fieldName}._count" must be true`
|
|
2191
2307
|
);
|
|
2192
2308
|
}
|
|
2193
|
-
fieldSchemas[fieldName] =
|
|
2309
|
+
fieldSchemas[fieldName] = import_zod6.z.object({
|
|
2194
2310
|
_count: sortEnum.optional()
|
|
2195
2311
|
}).strict().optional();
|
|
2196
2312
|
continue;
|
|
@@ -2201,17 +2317,11 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2201
2317
|
);
|
|
2202
2318
|
fieldSchemas[fieldName] = nested;
|
|
2203
2319
|
}
|
|
2204
|
-
const
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
(k) => v[k] !== void 0
|
|
2208
|
-
),
|
|
2209
|
-
{ message: "orderBy must specify at least one field" }
|
|
2320
|
+
const singleSchema = strictObjectRequiringOne(
|
|
2321
|
+
fieldSchemas,
|
|
2322
|
+
"orderBy must specify at least one field"
|
|
2210
2323
|
);
|
|
2211
|
-
return
|
|
2212
|
-
singleSchema,
|
|
2213
|
-
import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))
|
|
2214
|
-
]).optional();
|
|
2324
|
+
return singleOrArraySchema(singleSchema).optional();
|
|
2215
2325
|
}
|
|
2216
2326
|
function buildTakeSchema(config) {
|
|
2217
2327
|
if (typeof config === "number") {
|
|
@@ -2221,7 +2331,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2221
2331
|
if (config <= 0) {
|
|
2222
2332
|
throw new ShapeError("take must be a positive integer");
|
|
2223
2333
|
}
|
|
2224
|
-
return
|
|
2334
|
+
return import_zod6.z.number().int().min(1).max(config).default(config);
|
|
2225
2335
|
}
|
|
2226
2336
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
2227
2337
|
throw new ShapeError("take config must be a number or { max, default? }");
|
|
@@ -2246,9 +2356,9 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2246
2356
|
if (config.default > config.max) {
|
|
2247
2357
|
throw new ShapeError("take.default cannot exceed take.max");
|
|
2248
2358
|
}
|
|
2249
|
-
return
|
|
2359
|
+
return import_zod6.z.number().int().min(1).max(config.max).default(config.default);
|
|
2250
2360
|
}
|
|
2251
|
-
return
|
|
2361
|
+
return import_zod6.z.number().int().min(1).max(config.max).optional();
|
|
2252
2362
|
}
|
|
2253
2363
|
function buildCursorFieldSchema(model, fieldName) {
|
|
2254
2364
|
const modelFields = typeMap[model];
|
|
@@ -2270,11 +2380,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2270
2380
|
`List field "${fieldName}" cannot be used in cursor`
|
|
2271
2381
|
);
|
|
2272
2382
|
}
|
|
2273
|
-
|
|
2274
|
-
if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
|
|
2275
|
-
return wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, base);
|
|
2276
|
-
}
|
|
2277
|
-
return base;
|
|
2383
|
+
return buildDirectScalarSchema(fieldMeta, enumMap, scalarBase);
|
|
2278
2384
|
}
|
|
2279
2385
|
function cursorConfigMatchesConstraint(cursorConfig, constraint) {
|
|
2280
2386
|
if (!(constraint.selector in cursorConfig))
|
|
@@ -2283,66 +2389,55 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2283
2389
|
if (constraint.fields.length === 1) {
|
|
2284
2390
|
return value === true;
|
|
2285
2391
|
}
|
|
2286
|
-
if (!
|
|
2392
|
+
if (!isPlainObject(value))
|
|
2287
2393
|
return false;
|
|
2288
2394
|
const keys = Object.keys(value);
|
|
2289
2395
|
if (keys.length !== constraint.fields.length)
|
|
2290
2396
|
return false;
|
|
2291
2397
|
return constraint.fields.every((field) => value[field] === true);
|
|
2292
2398
|
}
|
|
2293
|
-
function getUniqueConstraints(model) {
|
|
2294
|
-
const constraints = uniqueMap[model];
|
|
2295
|
-
if (constraints && constraints.length > 0) {
|
|
2296
|
-
return constraints;
|
|
2297
|
-
}
|
|
2298
|
-
const modelFields = typeMap[model];
|
|
2299
|
-
if (!modelFields) {
|
|
2300
|
-
throw new ShapeError(`Unknown model: ${model}`);
|
|
2301
|
-
}
|
|
2302
|
-
const inferred = [];
|
|
2303
|
-
for (const [fieldName, fieldMeta] of Object.entries(modelFields)) {
|
|
2304
|
-
if (fieldMeta.isRelation)
|
|
2305
|
-
continue;
|
|
2306
|
-
if (fieldMeta.isId || fieldMeta.isUnique) {
|
|
2307
|
-
inferred.push({
|
|
2308
|
-
selector: fieldName,
|
|
2309
|
-
fields: [fieldName]
|
|
2310
|
-
});
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
2313
|
-
return inferred;
|
|
2314
|
-
}
|
|
2315
2399
|
function buildCursorSchema(model, cursorConfig) {
|
|
2316
|
-
const constraints =
|
|
2400
|
+
const constraints = uniqueMap[model] ?? [];
|
|
2317
2401
|
if (constraints.length === 0) {
|
|
2318
2402
|
throw new ShapeError(
|
|
2319
2403
|
`cursor on model "${model}" requires at least one unique constraint`
|
|
2320
2404
|
);
|
|
2321
2405
|
}
|
|
2322
|
-
const matching = constraints.
|
|
2406
|
+
const matching = constraints.filter(
|
|
2323
2407
|
(constraint) => cursorConfigMatchesConstraint(cursorConfig, constraint)
|
|
2324
2408
|
);
|
|
2325
|
-
if (
|
|
2409
|
+
if (matching.length === 0) {
|
|
2326
2410
|
throw new ShapeError(
|
|
2327
|
-
`cursor on model "${model}" must
|
|
2411
|
+
`cursor on model "${model}" must match a unique selector: ${formatUniqueConstraints(constraints)}`
|
|
2328
2412
|
);
|
|
2329
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
|
+
}
|
|
2330
2422
|
const fieldSchemas = {};
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
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();
|
|
2340
2435
|
}
|
|
2341
|
-
fieldSchemas[matching.selector] = import_zod5.z.object(nestedSchemas).strict().optional();
|
|
2342
2436
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2437
|
+
const selectorKeys = matching.map((c) => c.selector);
|
|
2438
|
+
return strictObjectRequiringOne(
|
|
2439
|
+
fieldSchemas,
|
|
2440
|
+
`cursor must specify one of: ${selectorKeys.join(", ")}`
|
|
2346
2441
|
).optional();
|
|
2347
2442
|
}
|
|
2348
2443
|
function buildDistinctSchema(model, distinctConfig) {
|
|
@@ -2367,10 +2462,8 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2367
2462
|
);
|
|
2368
2463
|
allowedFields.add(fieldName);
|
|
2369
2464
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
import_zod5.z.array(import_zod5.z.enum([...allowedFields])).min(1)
|
|
2373
|
-
]).optional();
|
|
2465
|
+
const fieldEnum = import_zod6.z.enum([...allowedFields]);
|
|
2466
|
+
return import_zod6.z.union([fieldEnum, import_zod6.z.array(fieldEnum).min(1)]).optional();
|
|
2374
2467
|
}
|
|
2375
2468
|
function buildBySchema(model, byConfig) {
|
|
2376
2469
|
const modelFields = typeMap[model];
|
|
@@ -2403,7 +2496,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2403
2496
|
}
|
|
2404
2497
|
allowedFields.add(fieldName);
|
|
2405
2498
|
}
|
|
2406
|
-
return
|
|
2499
|
+
return import_zod6.z.array(import_zod6.z.enum([...allowedFields])).min(1);
|
|
2407
2500
|
}
|
|
2408
2501
|
function buildHavingSchema(model, havingConfig) {
|
|
2409
2502
|
const modelFields = typeMap[model];
|
|
@@ -2444,22 +2537,21 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2444
2537
|
).optional();
|
|
2445
2538
|
}
|
|
2446
2539
|
if (fieldMeta.type === "String") {
|
|
2447
|
-
opSchemas.mode =
|
|
2540
|
+
opSchemas.mode = import_zod6.z.enum(["default", "insensitive"]).optional();
|
|
2448
2541
|
}
|
|
2449
2542
|
const opKeys = Object.keys(opSchemas).filter((key) => key !== "mode");
|
|
2450
|
-
|
|
2543
|
+
const opShape = { ...opSchemas };
|
|
2544
|
+
const opObjSchema = import_zod6.z.object(opShape).strict().refine(
|
|
2451
2545
|
(v) => opKeys.some((k) => v[k] !== void 0),
|
|
2452
2546
|
{
|
|
2453
2547
|
message: `having field "${fieldName}" must specify at least one operator`
|
|
2454
2548
|
}
|
|
2455
|
-
)
|
|
2549
|
+
);
|
|
2550
|
+
fieldSchemas[fieldName] = opObjSchema.optional();
|
|
2456
2551
|
}
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
(k) => v[k] !== void 0
|
|
2461
|
-
),
|
|
2462
|
-
{ message: "having must specify at least one field" }
|
|
2552
|
+
return strictObjectRequiringOne(
|
|
2553
|
+
fieldSchemas,
|
|
2554
|
+
"having must specify at least one field"
|
|
2463
2555
|
).optional();
|
|
2464
2556
|
}
|
|
2465
2557
|
function buildAggregateFieldSchema(model, op, config) {
|
|
@@ -2468,47 +2560,45 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2468
2560
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2469
2561
|
requireConfigTrue(config, `${op} on model "${model}"`);
|
|
2470
2562
|
const allowedTypes = op === "_avg" || op === "_sum" ? NUMERIC_TYPES : COMPARABLE_TYPES;
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
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
|
+
}
|
|
2490
2585
|
}
|
|
2491
|
-
|
|
2492
|
-
}
|
|
2493
|
-
const aggregateFieldKeys = Object.keys(fieldSchemas);
|
|
2494
|
-
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2495
|
-
(v) => aggregateFieldKeys.some(
|
|
2496
|
-
(k) => v[k] !== void 0
|
|
2497
|
-
),
|
|
2498
|
-
{ message: `${op} must specify at least one field` }
|
|
2499
|
-
).optional();
|
|
2586
|
+
);
|
|
2500
2587
|
}
|
|
2501
2588
|
function buildCountFieldSchema(model, config, context) {
|
|
2502
2589
|
if (config === true) {
|
|
2503
|
-
return
|
|
2590
|
+
return import_zod6.z.literal(true).optional();
|
|
2504
2591
|
}
|
|
2505
2592
|
const modelFields = typeMap[model];
|
|
2506
2593
|
if (!modelFields)
|
|
2507
2594
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2508
2595
|
requireConfigTrue(config, `${context} on model "${model}"`);
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2596
|
+
return buildLiteralTrueSchema(
|
|
2597
|
+
Object.keys(config),
|
|
2598
|
+
`${context} must specify at least one field`,
|
|
2599
|
+
(fieldName) => {
|
|
2600
|
+
if (fieldName === "_all")
|
|
2601
|
+
return;
|
|
2512
2602
|
const fieldMeta = modelFields[fieldName];
|
|
2513
2603
|
if (!fieldMeta)
|
|
2514
2604
|
throw new ShapeError(
|
|
@@ -2519,45 +2609,30 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2519
2609
|
`Relation field "${fieldName}" cannot be used in ${context}`
|
|
2520
2610
|
);
|
|
2521
2611
|
}
|
|
2522
|
-
|
|
2523
|
-
}
|
|
2524
|
-
const countFieldKeys = Object.keys(fieldSchemas);
|
|
2525
|
-
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2526
|
-
(v) => countFieldKeys.some(
|
|
2527
|
-
(k) => v[k] !== void 0
|
|
2528
|
-
),
|
|
2529
|
-
{ message: `${context} must specify at least one field` }
|
|
2530
|
-
).optional();
|
|
2612
|
+
);
|
|
2531
2613
|
}
|
|
2532
2614
|
function buildCountSelectSchema(model, selectConfig) {
|
|
2533
2615
|
const modelFields = typeMap[model];
|
|
2534
2616
|
if (!modelFields)
|
|
2535
2617
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2536
2618
|
requireConfigTrue(selectConfig, `count select on model "${model}"`);
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
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
|
+
);
|
|
2542
2634
|
}
|
|
2543
|
-
|
|
2544
|
-
if (!fieldMeta)
|
|
2545
|
-
throw new ShapeError(
|
|
2546
|
-
`Unknown field "${fieldName}" on model "${model}" in count select`
|
|
2547
|
-
);
|
|
2548
|
-
if (fieldMeta.isRelation)
|
|
2549
|
-
throw new ShapeError(
|
|
2550
|
-
`Relation field "${fieldName}" cannot be used in count select`
|
|
2551
|
-
);
|
|
2552
|
-
fieldSchemas[fieldName] = import_zod5.z.literal(true).optional();
|
|
2553
|
-
}
|
|
2554
|
-
const countSelectKeys = Object.keys(fieldSchemas);
|
|
2555
|
-
return import_zod5.z.object(fieldSchemas).strict().refine(
|
|
2556
|
-
(v) => countSelectKeys.some(
|
|
2557
|
-
(k) => v[k] !== void 0
|
|
2558
|
-
),
|
|
2559
|
-
{ message: "count select must specify at least one field" }
|
|
2560
|
-
).optional();
|
|
2635
|
+
);
|
|
2561
2636
|
}
|
|
2562
2637
|
return {
|
|
2563
2638
|
buildOrderBySchema,
|
|
@@ -2573,25 +2648,64 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2573
2648
|
}
|
|
2574
2649
|
|
|
2575
2650
|
// src/runtime/query-builder-projection.ts
|
|
2576
|
-
var
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
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
|
+
};
|
|
2595
2709
|
var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
|
|
2596
2710
|
var MAX_PROJECTION_DEPTH = 10;
|
|
2597
2711
|
function validateNestedKeys(keys, allowed, context) {
|
|
@@ -2603,13 +2717,25 @@ function validateNestedKeys(keys, allowed, context) {
|
|
|
2603
2717
|
}
|
|
2604
2718
|
}
|
|
2605
2719
|
}
|
|
2606
|
-
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) {
|
|
2607
2733
|
function buildIncludeCountSchema(model, config) {
|
|
2608
2734
|
const modelFields = typeMap[model];
|
|
2609
2735
|
if (!modelFields)
|
|
2610
2736
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2611
2737
|
if (config === true) {
|
|
2612
|
-
return { schema:
|
|
2738
|
+
return { schema: import_zod7.z.literal(true).optional(), forcedCountWhere: {} };
|
|
2613
2739
|
}
|
|
2614
2740
|
if (!isPlainObject(config) || !("select" in config)) {
|
|
2615
2741
|
throw new ShapeError(
|
|
@@ -2645,273 +2771,175 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
|
|
|
2645
2771
|
if (!fieldMeta.isList)
|
|
2646
2772
|
throw new ShapeError(`Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`);
|
|
2647
2773
|
if (fieldConfig === true) {
|
|
2648
|
-
countSelectFields[fieldName] =
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
`Empty config for _count.select.${fieldName} on model "${model}". Use true or { where: { ... } }.`
|
|
2653
|
-
);
|
|
2654
|
-
}
|
|
2655
|
-
validateNestedKeys(
|
|
2656
|
-
Object.keys(fieldConfig),
|
|
2657
|
-
KNOWN_COUNT_SELECT_ENTRY_KEYS,
|
|
2658
|
-
`_count.select.${fieldName} on model "${model}"`
|
|
2659
|
-
);
|
|
2660
|
-
if (fieldConfig.where) {
|
|
2661
|
-
const relatedType = fieldMeta.type;
|
|
2662
|
-
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2663
|
-
relatedType,
|
|
2664
|
-
fieldConfig.where
|
|
2665
|
-
);
|
|
2666
|
-
const nestedSchemas = {};
|
|
2667
|
-
if (whereSchema)
|
|
2668
|
-
nestedSchemas["where"] = whereSchema;
|
|
2669
|
-
const nestedObj = import_zod6.z.object(nestedSchemas).strict();
|
|
2670
|
-
countSelectFields[fieldName] = import_zod6.z.union([import_zod6.z.literal(true), nestedObj]).optional();
|
|
2671
|
-
if (hasWhereForced(forced)) {
|
|
2672
|
-
forcedCountWhere[fieldName] = forced;
|
|
2673
|
-
}
|
|
2674
|
-
} else {
|
|
2675
|
-
countSelectFields[fieldName] = import_zod6.z.literal(true).optional();
|
|
2676
|
-
}
|
|
2677
|
-
} else {
|
|
2774
|
+
countSelectFields[fieldName] = import_zod7.z.literal(true).optional();
|
|
2775
|
+
continue;
|
|
2776
|
+
}
|
|
2777
|
+
if (!isPlainObject(fieldConfig)) {
|
|
2678
2778
|
throw new ShapeError(
|
|
2679
2779
|
`Invalid config for _count.select.${fieldName} on model "${model}". Expected true or { where: { ... } }`
|
|
2680
2780
|
);
|
|
2681
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
|
+
}
|
|
2682
2809
|
}
|
|
2683
|
-
const
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
{ message: "_count.select must specify at least one field" }
|
|
2810
|
+
const selectSchema = strictObjectRequiringOne(
|
|
2811
|
+
countSelectFields,
|
|
2812
|
+
"_count.select must specify at least one field"
|
|
2687
2813
|
);
|
|
2688
2814
|
return {
|
|
2689
|
-
schema:
|
|
2815
|
+
schema: import_zod7.z.object({ select: selectSchema }).strict().optional(),
|
|
2690
2816
|
forcedCountWhere
|
|
2691
2817
|
};
|
|
2692
2818
|
}
|
|
2693
|
-
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) {
|
|
2694
2867
|
const currentDepth = depth ?? 0;
|
|
2695
2868
|
if (currentDepth > MAX_PROJECTION_DEPTH) {
|
|
2696
2869
|
throw new ShapeError(
|
|
2697
|
-
|
|
2870
|
+
`${mode === "include" ? "Include" : "Select"} schema for model "${model}" exceeds maximum nesting depth (${MAX_PROJECTION_DEPTH}). Check for circular relation references in the shape.`
|
|
2698
2871
|
);
|
|
2699
2872
|
}
|
|
2700
|
-
if (Object.keys(
|
|
2873
|
+
if (Object.keys(projectionConfig).length === 0) {
|
|
2701
2874
|
throw new ShapeError(
|
|
2702
|
-
`Empty
|
|
2875
|
+
`Empty ${mode} config on model "${model}". Define at least one ${mode === "include" ? "relation" : "field"}.`
|
|
2703
2876
|
);
|
|
2704
2877
|
}
|
|
2705
2878
|
const modelFields = typeMap[model];
|
|
2706
2879
|
if (!modelFields)
|
|
2707
2880
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
2881
|
+
const allowedNestedKeys = KNOWN_NESTED_KEYS[mode];
|
|
2708
2882
|
const fieldSchemas = {};
|
|
2709
2883
|
const forcedTree = {};
|
|
2710
2884
|
let topLevelForcedCountWhere = {};
|
|
2711
|
-
for (const [
|
|
2712
|
-
if (
|
|
2885
|
+
for (const [fieldName, config] of Object.entries(projectionConfig)) {
|
|
2886
|
+
if (fieldName === "_count") {
|
|
2713
2887
|
const countResult = buildIncludeCountSchema(model, config);
|
|
2714
2888
|
fieldSchemas["_count"] = countResult.schema;
|
|
2715
2889
|
topLevelForcedCountWhere = countResult.forcedCountWhere;
|
|
2716
2890
|
continue;
|
|
2717
2891
|
}
|
|
2718
|
-
const fieldMeta = modelFields[
|
|
2719
|
-
if (!fieldMeta)
|
|
2720
|
-
throw new ShapeError(`Unknown field "${relName}" on model "${model}"`);
|
|
2721
|
-
if (!fieldMeta.isRelation)
|
|
2722
|
-
throw new ShapeError(`Field "${relName}" is not a relation on model "${model}"`);
|
|
2723
|
-
if (config === true) {
|
|
2724
|
-
fieldSchemas[relName] = import_zod6.z.literal(true).optional();
|
|
2725
|
-
} else {
|
|
2726
|
-
validateNestedKeys(
|
|
2727
|
-
Object.keys(config),
|
|
2728
|
-
KNOWN_NESTED_INCLUDE_KEYS,
|
|
2729
|
-
`nested include for "${relName}" on model "${model}"`
|
|
2730
|
-
);
|
|
2731
|
-
if (config.select && config.include) {
|
|
2732
|
-
throw new ShapeError(`Nested include for "${relName}" cannot define both "select" and "include".`);
|
|
2733
|
-
}
|
|
2734
|
-
if (!fieldMeta.isList) {
|
|
2735
|
-
if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
|
|
2736
|
-
throw new ShapeError(
|
|
2737
|
-
`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.`
|
|
2738
|
-
);
|
|
2739
|
-
}
|
|
2740
|
-
}
|
|
2741
|
-
const nestedSchemas = {};
|
|
2742
|
-
const relForced = {};
|
|
2743
|
-
if (config.where) {
|
|
2744
|
-
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2745
|
-
fieldMeta.type,
|
|
2746
|
-
config.where
|
|
2747
|
-
);
|
|
2748
|
-
if (whereSchema)
|
|
2749
|
-
nestedSchemas["where"] = whereSchema;
|
|
2750
|
-
if (hasWhereForced(forced))
|
|
2751
|
-
relForced.where = forced;
|
|
2752
|
-
}
|
|
2753
|
-
if (config.include) {
|
|
2754
|
-
const nested = buildIncludeSchema(fieldMeta.type, config.include, currentDepth + 1);
|
|
2755
|
-
nestedSchemas["include"] = nested.schema;
|
|
2756
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2757
|
-
relForced.include = nested.forcedTree;
|
|
2758
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2759
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2760
|
-
relForced._countWherePlacement = "include";
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
if (config.select) {
|
|
2764
|
-
const nested = buildSelectSchema(fieldMeta.type, config.select, currentDepth + 1);
|
|
2765
|
-
nestedSchemas["select"] = nested.schema;
|
|
2766
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2767
|
-
relForced.select = nested.forcedTree;
|
|
2768
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2769
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2770
|
-
relForced._countWherePlacement = "select";
|
|
2771
|
-
}
|
|
2772
|
-
}
|
|
2773
|
-
if (config.orderBy) {
|
|
2774
|
-
nestedSchemas["orderBy"] = deps.buildOrderBySchema(fieldMeta.type, config.orderBy);
|
|
2775
|
-
}
|
|
2776
|
-
if (config.cursor) {
|
|
2777
|
-
nestedSchemas["cursor"] = deps.buildCursorSchema(fieldMeta.type, config.cursor);
|
|
2778
|
-
}
|
|
2779
|
-
if (config.take) {
|
|
2780
|
-
nestedSchemas["take"] = deps.buildTakeSchema(config.take);
|
|
2781
|
-
}
|
|
2782
|
-
if (config.skip) {
|
|
2783
|
-
nestedSchemas["skip"] = import_zod6.z.number().int().min(0).optional();
|
|
2784
|
-
}
|
|
2785
|
-
const nestedObj = import_zod6.z.object(nestedSchemas).strict();
|
|
2786
|
-
fieldSchemas[relName] = import_zod6.z.union([import_zod6.z.literal(true), nestedObj]).optional();
|
|
2787
|
-
if (Object.keys(relForced).length > 0)
|
|
2788
|
-
forcedTree[relName] = relForced;
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
const includeFieldKeys = Object.keys(fieldSchemas);
|
|
2792
|
-
const baseSchema = import_zod6.z.object(fieldSchemas).strict();
|
|
2793
|
-
const schema = includeFieldKeys.length > 0 ? baseSchema.refine(
|
|
2794
|
-
(v) => includeFieldKeys.some((k) => v[k] !== void 0),
|
|
2795
|
-
{ message: "include must specify at least one field" }
|
|
2796
|
-
).optional() : baseSchema.optional();
|
|
2797
|
-
return {
|
|
2798
|
-
schema,
|
|
2799
|
-
forcedTree,
|
|
2800
|
-
forcedCountWhere: topLevelForcedCountWhere
|
|
2801
|
-
};
|
|
2802
|
-
}
|
|
2803
|
-
function buildSelectSchema(model, selectConfig, depth) {
|
|
2804
|
-
const currentDepth = depth ?? 0;
|
|
2805
|
-
if (currentDepth > MAX_PROJECTION_DEPTH) {
|
|
2806
|
-
throw new ShapeError(
|
|
2807
|
-
`Select schema for model "${model}" exceeds maximum nesting depth (${MAX_PROJECTION_DEPTH}). Check for circular relation references in the shape.`
|
|
2808
|
-
);
|
|
2809
|
-
}
|
|
2810
|
-
if (Object.keys(selectConfig).length === 0) {
|
|
2811
|
-
throw new ShapeError(
|
|
2812
|
-
`Empty select config on model "${model}". Define at least one field.`
|
|
2813
|
-
);
|
|
2814
|
-
}
|
|
2815
|
-
const modelFields = typeMap[model];
|
|
2816
|
-
if (!modelFields)
|
|
2817
|
-
throw new ShapeError(`Unknown model: ${model}`);
|
|
2818
|
-
const fieldSchemas = {};
|
|
2819
|
-
const forcedTree = {};
|
|
2820
|
-
let topLevelForcedCountWhere = {};
|
|
2821
|
-
for (const [fieldName, config] of Object.entries(selectConfig)) {
|
|
2822
|
-
if (fieldName === "_count") {
|
|
2823
|
-
const countResult = buildIncludeCountSchema(model, config);
|
|
2824
|
-
fieldSchemas["_count"] = countResult.schema;
|
|
2825
|
-
topLevelForcedCountWhere = countResult.forcedCountWhere;
|
|
2826
|
-
continue;
|
|
2827
|
-
}
|
|
2828
|
-
const fieldMeta = modelFields[fieldName];
|
|
2892
|
+
const fieldMeta = modelFields[fieldName];
|
|
2829
2893
|
if (!fieldMeta)
|
|
2830
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
|
+
}
|
|
2831
2898
|
if (config === true) {
|
|
2832
|
-
fieldSchemas[fieldName] =
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
);
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
throw new ShapeError(
|
|
2848
|
-
`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.`
|
|
2849
|
-
);
|
|
2850
|
-
}
|
|
2851
|
-
}
|
|
2852
|
-
const nestedSchemas = {};
|
|
2853
|
-
const relForced = {};
|
|
2854
|
-
if (config.select) {
|
|
2855
|
-
const nested = buildSelectSchema(fieldMeta.type, config.select, currentDepth + 1);
|
|
2856
|
-
nestedSchemas["select"] = nested.schema;
|
|
2857
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2858
|
-
relForced.select = nested.forcedTree;
|
|
2859
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2860
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2861
|
-
relForced._countWherePlacement = "select";
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
if (config.include) {
|
|
2865
|
-
const nested = buildIncludeSchema(fieldMeta.type, config.include, currentDepth + 1);
|
|
2866
|
-
nestedSchemas["include"] = nested.schema;
|
|
2867
|
-
if (Object.keys(nested.forcedTree).length > 0)
|
|
2868
|
-
relForced.include = nested.forcedTree;
|
|
2869
|
-
if (Object.keys(nested.forcedCountWhere).length > 0) {
|
|
2870
|
-
relForced._countWhere = nested.forcedCountWhere;
|
|
2871
|
-
relForced._countWherePlacement = "include";
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
if (config.where) {
|
|
2875
|
-
const { schema: whereSchema, forced } = deps.buildWhereSchema(
|
|
2876
|
-
fieldMeta.type,
|
|
2877
|
-
config.where
|
|
2899
|
+
fieldSchemas[fieldName] = import_zod7.z.literal(true).optional();
|
|
2900
|
+
continue;
|
|
2901
|
+
}
|
|
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.`
|
|
2878
2914
|
);
|
|
2879
|
-
if (whereSchema)
|
|
2880
|
-
nestedSchemas["where"] = whereSchema;
|
|
2881
|
-
if (hasWhereForced(forced))
|
|
2882
|
-
relForced.where = forced;
|
|
2883
|
-
}
|
|
2884
|
-
if (config.orderBy) {
|
|
2885
|
-
nestedSchemas["orderBy"] = deps.buildOrderBySchema(fieldMeta.type, config.orderBy);
|
|
2886
|
-
}
|
|
2887
|
-
if (config.cursor) {
|
|
2888
|
-
nestedSchemas["cursor"] = deps.buildCursorSchema(fieldMeta.type, config.cursor);
|
|
2889
|
-
}
|
|
2890
|
-
if (config.take) {
|
|
2891
|
-
nestedSchemas["take"] = deps.buildTakeSchema(config.take);
|
|
2892
2915
|
}
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
const
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
).optional() : baseSchema.optional();
|
|
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();
|
|
2908
2930
|
return {
|
|
2909
2931
|
schema,
|
|
2910
2932
|
forcedTree,
|
|
2911
2933
|
forcedCountWhere: topLevelForcedCountWhere
|
|
2912
2934
|
};
|
|
2913
2935
|
}
|
|
2914
|
-
|
|
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 };
|
|
2915
2943
|
}
|
|
2916
2944
|
|
|
2917
2945
|
// src/shared/operation-shape-keys.ts
|
|
@@ -2921,7 +2949,6 @@ var OPERATION_SHAPE_KEYS = {
|
|
|
2921
2949
|
findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2922
2950
|
findUnique: ["where", "include", "select"],
|
|
2923
2951
|
findUniqueOrThrow: ["where", "include", "select"],
|
|
2924
|
-
findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2925
2952
|
count: ["where", "select", "cursor", "orderBy", "skip", "take"],
|
|
2926
2953
|
aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
|
|
2927
2954
|
groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
|
|
@@ -2956,6 +2983,99 @@ var MUTATION_SHAPE_KEYS = {
|
|
|
2956
2983
|
delete: new Set(OPERATION_SHAPE_KEYS.delete),
|
|
2957
2984
|
deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
|
|
2958
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
|
+
}
|
|
2959
3079
|
|
|
2960
3080
|
// src/runtime/query-builder.ts
|
|
2961
3081
|
var METHOD_ALLOWED_ARGS = READ_METHOD_ALLOWED_ARGS;
|
|
@@ -3056,6 +3176,90 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3056
3176
|
}
|
|
3057
3177
|
return shapeOrFn;
|
|
3058
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
|
+
}
|
|
3059
3263
|
function buildShapeZodSchema(model, method, shape) {
|
|
3060
3264
|
validateShapeArgs(method, shape);
|
|
3061
3265
|
validateUniqueWhere(model, method, shape);
|
|
@@ -3095,73 +3299,19 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3095
3299
|
}
|
|
3096
3300
|
if (shape.orderBy) {
|
|
3097
3301
|
if (method === "groupBy" && shape.by) {
|
|
3098
|
-
const sortEnum =
|
|
3099
|
-
|
|
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 {
|
|
3100
3310
|
if (shape.orderBy === true) {
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
groupByOrderFields[field] = sortEnum.optional();
|
|
3104
|
-
}
|
|
3105
|
-
groupByOrderFields._count = sortEnum.optional();
|
|
3106
|
-
const fieldKeys = Object.keys(groupByOrderFields);
|
|
3107
|
-
const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
|
|
3108
|
-
(v) => fieldKeys.some(
|
|
3109
|
-
(k) => v[k] !== void 0
|
|
3110
|
-
),
|
|
3111
|
-
{ message: "orderBy must specify at least one field" }
|
|
3112
|
-
);
|
|
3113
|
-
schemaFields.orderBy = import_zod7.z.union([
|
|
3114
|
-
singleSchema,
|
|
3115
|
-
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3116
|
-
]).optional();
|
|
3117
|
-
} else {
|
|
3118
|
-
const groupByOrderFields = {};
|
|
3119
|
-
for (const [fieldName, config] of Object.entries(shape.orderBy)) {
|
|
3120
|
-
if (fieldName === "_count") {
|
|
3121
|
-
if (config === true) {
|
|
3122
|
-
groupByOrderFields._count = sortEnum.optional();
|
|
3123
|
-
} else if (typeof config === "object" && config !== null) {
|
|
3124
|
-
const countFields = {};
|
|
3125
|
-
for (const countField of Object.keys(config)) {
|
|
3126
|
-
if (!bySet.has(countField)) {
|
|
3127
|
-
throw new ShapeError(
|
|
3128
|
-
`orderBy _count field "${countField}" must be included in "by" for groupBy`
|
|
3129
|
-
);
|
|
3130
|
-
}
|
|
3131
|
-
countFields[countField] = sortEnum.optional();
|
|
3132
|
-
}
|
|
3133
|
-
const countKeys = Object.keys(countFields);
|
|
3134
|
-
groupByOrderFields._count = import_zod7.z.object(countFields).strict().refine(
|
|
3135
|
-
(v) => countKeys.some(
|
|
3136
|
-
(k) => v[k] !== void 0
|
|
3137
|
-
),
|
|
3138
|
-
{
|
|
3139
|
-
message: "orderBy._count must specify at least one field"
|
|
3140
|
-
}
|
|
3141
|
-
).optional();
|
|
3142
|
-
}
|
|
3143
|
-
continue;
|
|
3144
|
-
}
|
|
3145
|
-
if (!bySet.has(fieldName)) {
|
|
3146
|
-
throw new ShapeError(
|
|
3147
|
-
`orderBy field "${fieldName}" must be included in "by" for groupBy`
|
|
3148
|
-
);
|
|
3149
|
-
}
|
|
3150
|
-
groupByOrderFields[fieldName] = sortEnum.optional();
|
|
3151
|
-
}
|
|
3152
|
-
const fieldKeys = Object.keys(groupByOrderFields);
|
|
3153
|
-
const singleSchema = import_zod7.z.object(groupByOrderFields).strict().refine(
|
|
3154
|
-
(v) => fieldKeys.some(
|
|
3155
|
-
(k) => v[k] !== void 0
|
|
3156
|
-
),
|
|
3157
|
-
{ 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.`
|
|
3158
3313
|
);
|
|
3159
|
-
schemaFields.orderBy = import_zod7.z.union([
|
|
3160
|
-
singleSchema,
|
|
3161
|
-
import_zod7.z.preprocess(coerceToArray, import_zod7.z.array(singleSchema).min(1))
|
|
3162
|
-
]).optional();
|
|
3163
3314
|
}
|
|
3164
|
-
} else {
|
|
3165
3315
|
schemaFields.orderBy = argsBuilder.buildOrderBySchema(
|
|
3166
3316
|
model,
|
|
3167
3317
|
shape.orderBy
|
|
@@ -3169,19 +3319,16 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3169
3319
|
}
|
|
3170
3320
|
}
|
|
3171
3321
|
if (shape.cursor) {
|
|
3172
|
-
schemaFields.cursor = argsBuilder.buildCursorSchema(
|
|
3173
|
-
model,
|
|
3174
|
-
shape.cursor
|
|
3175
|
-
);
|
|
3322
|
+
schemaFields.cursor = argsBuilder.buildCursorSchema(model, shape.cursor);
|
|
3176
3323
|
}
|
|
3177
|
-
if (shape.take) {
|
|
3324
|
+
if (shape.take !== void 0) {
|
|
3178
3325
|
schemaFields.take = argsBuilder.buildTakeSchema(shape.take);
|
|
3179
3326
|
}
|
|
3180
3327
|
if (shape.skip !== void 0) {
|
|
3181
3328
|
if (shape.skip !== true) {
|
|
3182
3329
|
throw new ShapeError('Shape config "skip" must be true');
|
|
3183
3330
|
}
|
|
3184
|
-
schemaFields.skip =
|
|
3331
|
+
schemaFields.skip = import_zod8.z.number().int().min(0).optional();
|
|
3185
3332
|
}
|
|
3186
3333
|
if (shape.distinct) {
|
|
3187
3334
|
schemaFields.distinct = argsBuilder.buildDistinctSchema(
|
|
@@ -3228,13 +3375,10 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3228
3375
|
schemaFields.by = argsBuilder.buildBySchema(model, shape.by);
|
|
3229
3376
|
}
|
|
3230
3377
|
if (shape.having) {
|
|
3231
|
-
schemaFields.having = argsBuilder.buildHavingSchema(
|
|
3232
|
-
model,
|
|
3233
|
-
shape.having
|
|
3234
|
-
);
|
|
3378
|
+
schemaFields.having = argsBuilder.buildHavingSchema(model, shape.having);
|
|
3235
3379
|
}
|
|
3236
3380
|
return {
|
|
3237
|
-
zodSchema:
|
|
3381
|
+
zodSchema: import_zod8.z.object(schemaFields).strict(),
|
|
3238
3382
|
forcedWhere,
|
|
3239
3383
|
forcedOnlyWhereKeys,
|
|
3240
3384
|
forcedIncludeTree,
|
|
@@ -3427,22 +3571,18 @@ function buildScopedUniqueWhere(existingWhere, conditions, scopeFks, log, model)
|
|
|
3427
3571
|
allConditions.push(...conditions);
|
|
3428
3572
|
return { ...topLevel, AND: allConditions };
|
|
3429
3573
|
}
|
|
3430
|
-
function
|
|
3431
|
-
const t = typeof v;
|
|
3432
|
-
return t === "string" || t === "number" || t === "bigint";
|
|
3433
|
-
}
|
|
3434
|
-
function looseEqual(a, b, log, fk) {
|
|
3574
|
+
function scopeValuesEqual(a, b) {
|
|
3435
3575
|
if (a === b)
|
|
3436
3576
|
return true;
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
log.warn(
|
|
3442
|
-
`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.`
|
|
3443
|
-
);
|
|
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);
|
|
3444
3581
|
}
|
|
3445
|
-
|
|
3582
|
+
if (bIsBig && typeof a === "number") {
|
|
3583
|
+
return Number.isInteger(a) && b === BigInt(a);
|
|
3584
|
+
}
|
|
3585
|
+
return false;
|
|
3446
3586
|
}
|
|
3447
3587
|
function buildFkSelect(fks) {
|
|
3448
3588
|
const select = {};
|
|
@@ -3732,7 +3872,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3732
3872
|
const result = await query(nextArgs);
|
|
3733
3873
|
if (result === null)
|
|
3734
3874
|
return result;
|
|
3735
|
-
if (typeof result !== "object"
|
|
3875
|
+
if (typeof result !== "object") {
|
|
3736
3876
|
throw new ShapeError(
|
|
3737
3877
|
`${operation} on model "${model}" returned a non-object, non-null result`
|
|
3738
3878
|
);
|
|
@@ -3763,7 +3903,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3763
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.`
|
|
3764
3904
|
);
|
|
3765
3905
|
}
|
|
3766
|
-
if (typeof verifyResult !== "object"
|
|
3906
|
+
if (typeof verifyResult !== "object") {
|
|
3767
3907
|
throw new PolicyError(
|
|
3768
3908
|
`prisma-guard: Scope verification re-query on model "${model}" returned a non-object result.`
|
|
3769
3909
|
);
|
|
@@ -3777,7 +3917,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3777
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).`
|
|
3778
3918
|
);
|
|
3779
3919
|
}
|
|
3780
|
-
if (!
|
|
3920
|
+
if (!scopeValuesEqual(verifyObj[fk], value)) {
|
|
3781
3921
|
if (operation === "findUniqueOrThrow") {
|
|
3782
3922
|
throw new PolicyError(
|
|
3783
3923
|
`prisma-guard: Record on model "${model}" not accessible in current scope`
|
|
@@ -3797,97 +3937,158 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3797
3937
|
}
|
|
3798
3938
|
|
|
3799
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
|
|
3800
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
|
+
}
|
|
3801
4062
|
|
|
3802
4063
|
// src/runtime/model-guard-data.ts
|
|
3803
|
-
var
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
"data",
|
|
3807
|
-
"
|
|
3808
|
-
"
|
|
3809
|
-
])
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
"select",
|
|
3817
|
-
"include",
|
|
3818
|
-
"skipDuplicates"
|
|
3819
|
-
]);
|
|
3820
|
-
var ALLOWED_BODY_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
|
|
3821
|
-
var ALLOWED_BODY_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3822
|
-
"data",
|
|
3823
|
-
"where",
|
|
3824
|
-
"select",
|
|
3825
|
-
"include"
|
|
3826
|
-
]);
|
|
3827
|
-
var ALLOWED_BODY_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
|
|
3828
|
-
var ALLOWED_BODY_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3829
|
-
"where",
|
|
3830
|
-
"select",
|
|
3831
|
-
"include"
|
|
3832
|
-
]);
|
|
3833
|
-
var ALLOWED_BODY_KEYS_UPSERT = /* @__PURE__ */ new Set([
|
|
3834
|
-
"where",
|
|
3835
|
-
"create",
|
|
3836
|
-
"update",
|
|
3837
|
-
"select",
|
|
3838
|
-
"include"
|
|
3839
|
-
]);
|
|
3840
|
-
var VALID_SHAPE_KEYS_CREATE = /* @__PURE__ */ new Set(["data"]);
|
|
3841
|
-
var VALID_SHAPE_KEYS_CREATE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3842
|
-
"data",
|
|
3843
|
-
"select",
|
|
3844
|
-
"include"
|
|
3845
|
-
]);
|
|
3846
|
-
var VALID_SHAPE_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
|
|
3847
|
-
var VALID_SHAPE_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3848
|
-
"data",
|
|
3849
|
-
"where",
|
|
3850
|
-
"select",
|
|
3851
|
-
"include"
|
|
3852
|
-
]);
|
|
3853
|
-
var VALID_SHAPE_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
|
|
3854
|
-
var VALID_SHAPE_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set([
|
|
3855
|
-
"where",
|
|
3856
|
-
"select",
|
|
3857
|
-
"include"
|
|
3858
|
-
]);
|
|
3859
|
-
var VALID_SHAPE_KEYS_UPSERT = /* @__PURE__ */ new Set([
|
|
3860
|
-
"where",
|
|
3861
|
-
"create",
|
|
3862
|
-
"update",
|
|
3863
|
-
"select",
|
|
3864
|
-
"include"
|
|
3865
|
-
]);
|
|
3866
|
-
var KNOWN_RELATION_WRITE_OPS = /* @__PURE__ */ new Set([
|
|
3867
|
-
"connect",
|
|
3868
|
-
"connectOrCreate",
|
|
3869
|
-
"create",
|
|
3870
|
-
"createMany",
|
|
3871
|
-
"disconnect",
|
|
3872
|
-
"delete",
|
|
3873
|
-
"set",
|
|
3874
|
-
"update",
|
|
3875
|
-
"updateMany",
|
|
3876
|
-
"upsert",
|
|
3877
|
-
"deleteMany"
|
|
3878
|
-
]);
|
|
3879
|
-
function validateMutationBodyKeys(body, allowed, method) {
|
|
3880
|
-
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)) {
|
|
3881
4077
|
if (!allowed.has(key)) {
|
|
3882
4078
|
throw new ShapeError(
|
|
3883
|
-
`
|
|
4079
|
+
`Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
|
|
3884
4080
|
);
|
|
3885
4081
|
}
|
|
3886
4082
|
}
|
|
3887
4083
|
}
|
|
3888
|
-
function
|
|
3889
|
-
for (const key of Object.keys(
|
|
4084
|
+
function validateAllowedKeys(value, allowed, method, kind) {
|
|
4085
|
+
for (const key of Object.keys(value)) {
|
|
3890
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
|
+
}
|
|
3891
4092
|
throw new ShapeError(
|
|
3892
4093
|
`Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
|
|
3893
4094
|
);
|
|
@@ -3929,24 +4130,24 @@ function buildWhereFieldsSchema(model, config, typeMap, schemaBuilder) {
|
|
|
3929
4130
|
for (const [fieldName, value] of Object.entries(config)) {
|
|
3930
4131
|
if (value !== true)
|
|
3931
4132
|
throw new ShapeError(
|
|
3932
|
-
`Field "${fieldName}" in
|
|
4133
|
+
`Field "${fieldName}" in filter config must be true`
|
|
3933
4134
|
);
|
|
3934
4135
|
const meta = modelFields[fieldName];
|
|
3935
4136
|
if (!meta)
|
|
3936
4137
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
3937
4138
|
if (meta.isRelation)
|
|
3938
4139
|
throw new ShapeError(
|
|
3939
|
-
`Relation field "${fieldName}" cannot be used in
|
|
4140
|
+
`Relation field "${fieldName}" cannot be used in filter`
|
|
3940
4141
|
);
|
|
3941
4142
|
fieldSchemas[fieldName] = schemaBuilder.buildFieldSchema(model, fieldName).optional();
|
|
3942
4143
|
fieldKeys.push(fieldName);
|
|
3943
4144
|
}
|
|
3944
|
-
return
|
|
4145
|
+
return import_zod10.z.object(fieldSchemas).strict().refine(
|
|
3945
4146
|
(v) => fieldKeys.some((k) => v[k] !== void 0),
|
|
3946
|
-
{ message: `At least one field required in
|
|
4147
|
+
{ message: `At least one field required in filter` }
|
|
3947
4148
|
);
|
|
3948
4149
|
}
|
|
3949
|
-
function buildNestedDataSchema(model, config, typeMap, schemaBuilder) {
|
|
4150
|
+
function buildNestedDataSchema(model, config, mode, typeMap, schemaBuilder) {
|
|
3950
4151
|
const modelFields = typeMap[model];
|
|
3951
4152
|
if (!modelFields)
|
|
3952
4153
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -3967,382 +4168,349 @@ function buildNestedDataSchema(model, config, typeMap, schemaBuilder) {
|
|
|
3967
4168
|
throw new ShapeError(
|
|
3968
4169
|
`updatedAt field "${fieldName}" cannot be used in nested data`
|
|
3969
4170
|
);
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
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
|
+
});
|
|
3977
4180
|
}
|
|
3978
|
-
return
|
|
4181
|
+
return import_zod10.z.object(fieldSchemas).strict();
|
|
3979
4182
|
}
|
|
3980
|
-
function
|
|
3981
|
-
|
|
3982
|
-
|
|
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) {
|
|
3983
4255
|
throw new ShapeError(
|
|
3984
|
-
`
|
|
4256
|
+
`createMany is only valid on to-many relations ("${ctx.model}.${ctx.fieldName}")`
|
|
3985
4257
|
);
|
|
3986
|
-
for (const key of Object.keys(config)) {
|
|
3987
|
-
if (!KNOWN_RELATION_WRITE_OPS.has(key)) {
|
|
3988
|
-
throw new ShapeError(
|
|
3989
|
-
`Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
|
|
3990
|
-
);
|
|
3991
|
-
}
|
|
3992
4258
|
}
|
|
3993
|
-
const
|
|
3994
|
-
|
|
3995
|
-
|
|
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) {
|
|
3996
4281
|
throw new ShapeError(
|
|
3997
|
-
`
|
|
4282
|
+
`disconnect on to-many relation "${ctx.model}.${ctx.fieldName}" requires unique selector config, not true`
|
|
3998
4283
|
);
|
|
3999
4284
|
}
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
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`
|
|
4005
4290
|
);
|
|
4006
|
-
opSchemas["connect"] = isList ? import_zod8.z.union([
|
|
4007
|
-
connectSchema,
|
|
4008
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(connectSchema))
|
|
4009
|
-
]).optional() : connectSchema.optional();
|
|
4010
4291
|
}
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
if (
|
|
4019
|
-
throw new ShapeError(
|
|
4020
|
-
`connectOrCreate on "${model}.${fieldName}" requires "where" object`
|
|
4021
|
-
);
|
|
4022
|
-
}
|
|
4023
|
-
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) {
|
|
4024
4300
|
throw new ShapeError(
|
|
4025
|
-
`
|
|
4301
|
+
`delete on to-many relation "${ctx.model}.${ctx.fieldName}" requires unique selector config, not true`
|
|
4026
4302
|
);
|
|
4027
4303
|
}
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
);
|
|
4034
|
-
const createSchema = buildNestedDataSchema(
|
|
4035
|
-
relatedModelName,
|
|
4036
|
-
coc.create,
|
|
4037
|
-
typeMap,
|
|
4038
|
-
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`
|
|
4039
4309
|
);
|
|
4040
|
-
const cocSchema = import_zod8.z.object({ where: whereSchema, create: createSchema }).strict();
|
|
4041
|
-
opSchemas["connectOrCreate"] = isList ? import_zod8.z.union([cocSchema, import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(cocSchema))]).optional() : cocSchema.optional();
|
|
4042
4310
|
}
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
typeMap,
|
|
4053
|
-
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}")`
|
|
4054
4320
|
);
|
|
4055
|
-
opSchemas["create"] = isList ? import_zod8.z.union([
|
|
4056
|
-
createSchema,
|
|
4057
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(createSchema))
|
|
4058
|
-
]).optional() : createSchema.optional();
|
|
4059
4321
|
}
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
}
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
relatedModelName,
|
|
4079
|
-
cmConfig.data,
|
|
4080
|
-
typeMap,
|
|
4081
|
-
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`
|
|
4082
4340
|
);
|
|
4083
|
-
const
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
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);
|
|
4090
4350
|
}
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
}
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
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);
|
|
4119
4387
|
}
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
throw new ShapeError(
|
|
4124
|
-
`delete on to-many relation "${model}.${fieldName}" requires field config, not true`
|
|
4125
|
-
);
|
|
4126
|
-
}
|
|
4127
|
-
opSchemas["delete"] = import_zod8.z.literal(true).optional();
|
|
4128
|
-
} else if (isPlainObject(config.delete)) {
|
|
4129
|
-
const deleteSchema = buildWhereFieldsSchema(
|
|
4130
|
-
relatedModelName,
|
|
4131
|
-
config.delete,
|
|
4132
|
-
typeMap,
|
|
4133
|
-
schemaBuilder
|
|
4134
|
-
);
|
|
4135
|
-
if (isList) {
|
|
4136
|
-
opSchemas["delete"] = import_zod8.z.union([
|
|
4137
|
-
deleteSchema,
|
|
4138
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(deleteSchema))
|
|
4139
|
-
]).optional();
|
|
4140
|
-
} else {
|
|
4141
|
-
opSchemas["delete"] = import_zod8.z.union([import_zod8.z.literal(true), deleteSchema]).optional();
|
|
4142
|
-
}
|
|
4143
|
-
} else {
|
|
4388
|
+
const hasWhereKey = "where" in cfg;
|
|
4389
|
+
if (hasWhereKey) {
|
|
4390
|
+
if (!isPlainObject(cfg.where)) {
|
|
4144
4391
|
throw new ShapeError(
|
|
4145
|
-
`
|
|
4392
|
+
`upsert on to-one "${ctx.model}.${ctx.fieldName}" has invalid "where": must be a plain object of unique selectors`
|
|
4146
4393
|
);
|
|
4147
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();
|
|
4148
4398
|
}
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
throw new ShapeError(
|
|
4157
|
-
`set config on "${model}.${fieldName}" must be an object of field names`
|
|
4158
|
-
);
|
|
4159
|
-
}
|
|
4160
|
-
const setSchema = buildWhereFieldsSchema(
|
|
4161
|
-
relatedModelName,
|
|
4162
|
-
config.set,
|
|
4163
|
-
typeMap,
|
|
4164
|
-
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}")`
|
|
4165
4406
|
);
|
|
4166
|
-
opSchemas["set"] = import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(setSchema)).optional();
|
|
4167
4407
|
}
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
}
|
|
4181
|
-
if (!updateConfig.data || !isPlainObject(updateConfig.data)) {
|
|
4182
|
-
throw new ShapeError(
|
|
4183
|
-
`update on to-many "${model}.${fieldName}" requires "data" object`
|
|
4184
|
-
);
|
|
4185
|
-
}
|
|
4186
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4187
|
-
relatedModelName,
|
|
4188
|
-
updateConfig.where,
|
|
4189
|
-
typeMap,
|
|
4190
|
-
schemaBuilder
|
|
4191
|
-
);
|
|
4192
|
-
const dataSchema = buildNestedDataSchema(
|
|
4193
|
-
relatedModelName,
|
|
4194
|
-
updateConfig.data,
|
|
4195
|
-
typeMap,
|
|
4196
|
-
schemaBuilder
|
|
4197
|
-
);
|
|
4198
|
-
const updateSchema = import_zod8.z.object({ where: whereSchema, data: dataSchema }).strict();
|
|
4199
|
-
opSchemas["update"] = import_zod8.z.union([
|
|
4200
|
-
updateSchema,
|
|
4201
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(updateSchema))
|
|
4202
|
-
]).optional();
|
|
4203
|
-
} else {
|
|
4204
|
-
const dataSchema = buildNestedDataSchema(
|
|
4205
|
-
relatedModelName,
|
|
4206
|
-
updateConfig,
|
|
4207
|
-
typeMap,
|
|
4208
|
-
schemaBuilder
|
|
4209
|
-
);
|
|
4210
|
-
opSchemas["update"] = dataSchema.optional();
|
|
4211
|
-
}
|
|
4212
|
-
}
|
|
4213
|
-
if (config.upsert !== void 0) {
|
|
4214
|
-
if (!isPlainObject(config.upsert)) {
|
|
4215
|
-
throw new ShapeError(
|
|
4216
|
-
`upsert config on "${model}.${fieldName}" must be an object`
|
|
4217
|
-
);
|
|
4218
|
-
}
|
|
4219
|
-
const upsertConfig = config.upsert;
|
|
4220
|
-
if (!upsertConfig.create || !isPlainObject(upsertConfig.create)) {
|
|
4221
|
-
throw new ShapeError(
|
|
4222
|
-
`upsert on "${model}.${fieldName}" requires "create" object`
|
|
4223
|
-
);
|
|
4224
|
-
}
|
|
4225
|
-
if (!upsertConfig.update || !isPlainObject(upsertConfig.update)) {
|
|
4226
|
-
throw new ShapeError(
|
|
4227
|
-
`upsert on "${model}.${fieldName}" requires "update" object`
|
|
4228
|
-
);
|
|
4229
|
-
}
|
|
4230
|
-
const createSchema = buildNestedDataSchema(
|
|
4231
|
-
relatedModelName,
|
|
4232
|
-
upsertConfig.create,
|
|
4233
|
-
typeMap,
|
|
4234
|
-
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`
|
|
4235
4421
|
);
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
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`
|
|
4241
4431
|
);
|
|
4242
|
-
if (isList) {
|
|
4243
|
-
if (!upsertConfig.where || !isPlainObject(upsertConfig.where)) {
|
|
4244
|
-
throw new ShapeError(
|
|
4245
|
-
`upsert on to-many "${model}.${fieldName}" requires "where" object`
|
|
4246
|
-
);
|
|
4247
|
-
}
|
|
4248
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4249
|
-
relatedModelName,
|
|
4250
|
-
upsertConfig.where,
|
|
4251
|
-
typeMap,
|
|
4252
|
-
schemaBuilder
|
|
4253
|
-
);
|
|
4254
|
-
const upsertSchema = import_zod8.z.object({
|
|
4255
|
-
where: whereSchema,
|
|
4256
|
-
create: createSchema,
|
|
4257
|
-
update: updateSchema
|
|
4258
|
-
}).strict();
|
|
4259
|
-
opSchemas["upsert"] = import_zod8.z.union([
|
|
4260
|
-
upsertSchema,
|
|
4261
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(upsertSchema))
|
|
4262
|
-
]).optional();
|
|
4263
|
-
} else {
|
|
4264
|
-
if (upsertConfig.where) {
|
|
4265
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4266
|
-
relatedModelName,
|
|
4267
|
-
upsertConfig.where,
|
|
4268
|
-
typeMap,
|
|
4269
|
-
schemaBuilder
|
|
4270
|
-
);
|
|
4271
|
-
const upsertSchema = import_zod8.z.object({
|
|
4272
|
-
where: whereSchema,
|
|
4273
|
-
create: createSchema,
|
|
4274
|
-
update: updateSchema
|
|
4275
|
-
}).strict();
|
|
4276
|
-
opSchemas["upsert"] = upsertSchema.optional();
|
|
4277
|
-
} else {
|
|
4278
|
-
const upsertSchema = import_zod8.z.object({ create: createSchema, update: updateSchema }).strict();
|
|
4279
|
-
opSchemas["upsert"] = upsertSchema.optional();
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
4432
|
}
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
`updateMany on "${model}.${fieldName}" requires "where" object`
|
|
4298
|
-
);
|
|
4299
|
-
}
|
|
4300
|
-
if (!umConfig.data || !isPlainObject(umConfig.data)) {
|
|
4301
|
-
throw new ShapeError(
|
|
4302
|
-
`updateMany on "${model}.${fieldName}" requires "data" object`
|
|
4303
|
-
);
|
|
4304
|
-
}
|
|
4305
|
-
const whereSchema = buildWhereFieldsSchema(
|
|
4306
|
-
relatedModelName,
|
|
4307
|
-
umConfig.where,
|
|
4308
|
-
typeMap,
|
|
4309
|
-
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}")`
|
|
4310
4447
|
);
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
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.`
|
|
4316
4456
|
);
|
|
4317
|
-
const umSchema = import_zod8.z.object({ where: whereSchema, data: dataSchema }).strict();
|
|
4318
|
-
opSchemas["updateMany"] = import_zod8.z.union([umSchema, import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(umSchema))]).optional();
|
|
4319
4457
|
}
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
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)) {
|
|
4327
4488
|
throw new ShapeError(
|
|
4328
|
-
`
|
|
4489
|
+
`Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
|
|
4329
4490
|
);
|
|
4330
4491
|
}
|
|
4331
|
-
|
|
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,
|
|
4332
4501
|
relatedModelName,
|
|
4333
|
-
|
|
4502
|
+
isList,
|
|
4503
|
+
config: opConfig,
|
|
4334
4504
|
typeMap,
|
|
4505
|
+
uniqueMap,
|
|
4506
|
+
enumMap,
|
|
4507
|
+
scalarBase,
|
|
4335
4508
|
schemaBuilder
|
|
4336
|
-
);
|
|
4337
|
-
opSchemas["deleteMany"] = import_zod8.z.union([
|
|
4338
|
-
filterSchema,
|
|
4339
|
-
import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(filterSchema)),
|
|
4340
|
-
import_zod8.z.object({}).strict()
|
|
4341
|
-
]).optional();
|
|
4509
|
+
});
|
|
4342
4510
|
}
|
|
4343
|
-
return
|
|
4511
|
+
return import_zod10.z.object(opSchemas).strict();
|
|
4344
4512
|
}
|
|
4345
|
-
function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDefaults) {
|
|
4513
|
+
function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults) {
|
|
4346
4514
|
const modelFields = typeMap[model];
|
|
4347
4515
|
if (!modelFields)
|
|
4348
4516
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -4354,11 +4522,23 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4354
4522
|
const fieldMeta = modelFields[fieldName];
|
|
4355
4523
|
if (!fieldMeta) {
|
|
4356
4524
|
if (isUnsupportedMarker(value)) {
|
|
4357
|
-
schemaMap[fieldName] = import_zod8.z.unknown().optional();
|
|
4358
4525
|
continue;
|
|
4359
4526
|
}
|
|
4360
4527
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
4361
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
|
+
}
|
|
4362
4542
|
if (fieldMeta.isRelation) {
|
|
4363
4543
|
if (!isPlainObject(value)) {
|
|
4364
4544
|
throw new ShapeError(
|
|
@@ -4372,6 +4552,9 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4372
4552
|
fieldMeta.isList,
|
|
4373
4553
|
value,
|
|
4374
4554
|
typeMap,
|
|
4555
|
+
uniqueMap,
|
|
4556
|
+
enumMap,
|
|
4557
|
+
scalarBase,
|
|
4375
4558
|
schemaBuilder
|
|
4376
4559
|
).optional();
|
|
4377
4560
|
continue;
|
|
@@ -4381,7 +4564,7 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4381
4564
|
`updatedAt field "${fieldName}" cannot be used in data shape`
|
|
4382
4565
|
);
|
|
4383
4566
|
if (typeof value === "function") {
|
|
4384
|
-
|
|
4567
|
+
const baseSchema = schemaBuilder.buildBaseFieldSchema(
|
|
4385
4568
|
model,
|
|
4386
4569
|
fieldName
|
|
4387
4570
|
);
|
|
@@ -4399,46 +4582,22 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4399
4582
|
`Inline refine for "${model}.${fieldName}" must return a Zod schema`
|
|
4400
4583
|
);
|
|
4401
4584
|
}
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
fieldSchema = fieldSchema.optional();
|
|
4410
|
-
}
|
|
4411
|
-
}
|
|
4412
|
-
} else {
|
|
4413
|
-
if (!fieldMeta.isRequired) {
|
|
4414
|
-
fieldSchema = fieldSchema.nullable().optional();
|
|
4415
|
-
} else {
|
|
4416
|
-
fieldSchema = fieldSchema.optional();
|
|
4417
|
-
}
|
|
4418
|
-
}
|
|
4419
|
-
schemaMap[fieldName] = fieldSchema;
|
|
4420
|
-
} else if (value === true) {
|
|
4421
|
-
let fieldSchema = schemaBuilder.buildFieldSchema(
|
|
4422
|
-
model,
|
|
4423
|
-
fieldName
|
|
4585
|
+
const handlesUndefined = schemaProducesValueForUndefined(
|
|
4586
|
+
refined
|
|
4587
|
+
);
|
|
4588
|
+
schemaMap[fieldName] = applyCreateUpdateNullability(
|
|
4589
|
+
fieldMeta,
|
|
4590
|
+
refined,
|
|
4591
|
+
{ mode, handlesUndefined }
|
|
4424
4592
|
);
|
|
4593
|
+
} else if (value === true) {
|
|
4594
|
+
const fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
|
|
4425
4595
|
const isZodDefaultField = zodDefaultSet !== void 0 && zodDefaultSet.has(fieldName);
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
fieldSchema = fieldSchema.optional();
|
|
4432
|
-
}
|
|
4433
|
-
}
|
|
4434
|
-
} else {
|
|
4435
|
-
if (!fieldMeta.isRequired) {
|
|
4436
|
-
fieldSchema = fieldSchema.nullable().optional();
|
|
4437
|
-
} else {
|
|
4438
|
-
fieldSchema = fieldSchema.optional();
|
|
4439
|
-
}
|
|
4440
|
-
}
|
|
4441
|
-
schemaMap[fieldName] = fieldSchema;
|
|
4596
|
+
schemaMap[fieldName] = applyCreateUpdateNullability(
|
|
4597
|
+
fieldMeta,
|
|
4598
|
+
fieldSchema,
|
|
4599
|
+
{ mode, handlesUndefined: isZodDefaultField }
|
|
4600
|
+
);
|
|
4442
4601
|
} else {
|
|
4443
4602
|
const actualValue = isForcedValue(value) ? value.value : value;
|
|
4444
4603
|
let fieldSchema = schemaBuilder.buildFieldSchema(
|
|
@@ -4482,7 +4641,7 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
|
|
|
4482
4641
|
}
|
|
4483
4642
|
}
|
|
4484
4643
|
return {
|
|
4485
|
-
schema:
|
|
4644
|
+
schema: import_zod10.z.object(schemaMap).strict(),
|
|
4486
4645
|
forced
|
|
4487
4646
|
};
|
|
4488
4647
|
}
|
|
@@ -4519,106 +4678,120 @@ function isGuardShape(obj) {
|
|
|
4519
4678
|
const keys = Object.keys(obj);
|
|
4520
4679
|
return keys.length === 0 || keys.every((k) => GUARD_SHAPE_KEYS.has(k));
|
|
4521
4680
|
}
|
|
4522
|
-
function
|
|
4523
|
-
|
|
4524
|
-
}
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
return value;
|
|
4528
|
-
if (Array.isArray(value))
|
|
4529
|
-
return value.map(toPlainObject);
|
|
4530
|
-
if (value instanceof Date)
|
|
4531
|
-
return value;
|
|
4532
|
-
if (value instanceof Uint8Array)
|
|
4533
|
-
return value;
|
|
4534
|
-
if (value instanceof RegExp)
|
|
4535
|
-
return value;
|
|
4536
|
-
if (typeof value.toFixed === "function" && typeof value.toNumber === "function")
|
|
4537
|
-
return value;
|
|
4538
|
-
const result = {};
|
|
4539
|
-
for (const [k, v] of Object.entries(value)) {
|
|
4540
|
-
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");
|
|
4541
4686
|
}
|
|
4542
|
-
return
|
|
4687
|
+
return body;
|
|
4543
4688
|
}
|
|
4544
|
-
function
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
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
|
+
}
|
|
4549
4695
|
}
|
|
4550
|
-
function resolveDynamicShape(
|
|
4551
|
-
|
|
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
|
+
}
|
|
4552
4702
|
let result;
|
|
4553
4703
|
try {
|
|
4554
|
-
result =
|
|
4704
|
+
result = shapeFn(ctx);
|
|
4555
4705
|
} catch (err) {
|
|
4556
4706
|
throw new ShapeError(
|
|
4557
|
-
`Dynamic
|
|
4707
|
+
`Dynamic ${context} function threw: ${err.message}`,
|
|
4558
4708
|
{ cause: err }
|
|
4559
4709
|
);
|
|
4560
4710
|
}
|
|
4561
|
-
if (!
|
|
4562
|
-
throw new ShapeError(
|
|
4711
|
+
if (!isGuardShape(result)) {
|
|
4712
|
+
throw new ShapeError(
|
|
4713
|
+
`Dynamic ${context} function must return a valid guard shape object`
|
|
4714
|
+
);
|
|
4563
4715
|
}
|
|
4564
4716
|
return result;
|
|
4565
4717
|
}
|
|
4566
|
-
function
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
return { shape: shape2, body: parsed2, matchedKey: "_default", wasDynamic: wasDynamic2 };
|
|
4572
|
-
}
|
|
4573
|
-
const namedMap = input;
|
|
4574
|
-
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) {
|
|
4575
4723
|
if (GUARD_SHAPE_KEYS.has(key)) {
|
|
4576
4724
|
throw new ShapeError(
|
|
4577
|
-
`Caller key "${key}" collides with reserved shape
|
|
4578
|
-
);
|
|
4579
|
-
}
|
|
4580
|
-
const val = namedMap[key];
|
|
4581
|
-
if (typeof val !== "function" && !isGuardShape(val)) {
|
|
4582
|
-
throw new ShapeError(
|
|
4583
|
-
`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.`
|
|
4584
4726
|
);
|
|
4585
4727
|
}
|
|
4586
4728
|
}
|
|
4587
|
-
const parsed = body === void 0 || body === null ? {} : requireBody(body);
|
|
4588
|
-
if ("caller" in parsed) {
|
|
4589
|
-
throw new CallerError(
|
|
4590
|
-
"Pass caller as second argument to .guard() or via context function, not in the request body."
|
|
4591
|
-
);
|
|
4592
|
-
}
|
|
4593
4729
|
if (typeof caller !== "string") {
|
|
4594
|
-
if ("default" in
|
|
4595
|
-
|
|
4596
|
-
const wasDynamic2 = typeof shapeOrFn2 === "function";
|
|
4597
|
-
const shape2 = wasDynamic2 ? resolveDynamicShape(shapeOrFn2, contextFn) : shapeOrFn2;
|
|
4598
|
-
return { shape: shape2, body: parsed, matchedKey: "default", wasDynamic: wasDynamic2 };
|
|
4730
|
+
if ("default" in input) {
|
|
4731
|
+
return resolveShapeEntry(input.default, body, contextFn, "default");
|
|
4599
4732
|
}
|
|
4600
|
-
const patterns2 = Object.keys(namedMap);
|
|
4601
4733
|
throw new CallerError(
|
|
4602
|
-
`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).`
|
|
4603
4735
|
);
|
|
4604
4736
|
}
|
|
4605
|
-
const
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
}
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
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
|
+
};
|
|
4617
4785
|
}
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
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
|
+
);
|
|
4622
4795
|
}
|
|
4623
4796
|
|
|
4624
4797
|
// src/runtime/model-guard.ts
|
|
@@ -4641,129 +4814,20 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
4641
4814
|
"updateManyAndReturn"
|
|
4642
4815
|
]);
|
|
4643
4816
|
var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set(["createMany", "createManyAndReturn"]);
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
);
|
|
4651
|
-
continue;
|
|
4652
|
-
}
|
|
4653
|
-
if (value === true) {
|
|
4654
|
-
result[key] = true;
|
|
4655
|
-
} else {
|
|
4656
|
-
const nested = {};
|
|
4657
|
-
if (value.select)
|
|
4658
|
-
nested.select = buildDefaultSelectInput(value.select);
|
|
4659
|
-
if (value.include) {
|
|
4660
|
-
nested.include = buildDefaultIncludeInput(value.include);
|
|
4661
|
-
}
|
|
4662
|
-
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
4663
|
-
}
|
|
4664
|
-
}
|
|
4665
|
-
return result;
|
|
4666
|
-
}
|
|
4667
|
-
function buildDefaultIncludeInput(config) {
|
|
4668
|
-
const result = {};
|
|
4669
|
-
for (const [key, value] of Object.entries(config)) {
|
|
4670
|
-
if (key === "_count") {
|
|
4671
|
-
result[key] = buildDefaultCountInput(
|
|
4672
|
-
value
|
|
4673
|
-
);
|
|
4674
|
-
continue;
|
|
4675
|
-
}
|
|
4676
|
-
if (value === true) {
|
|
4677
|
-
result[key] = true;
|
|
4678
|
-
} else {
|
|
4679
|
-
const nested = {};
|
|
4680
|
-
if (value.include) {
|
|
4681
|
-
nested.include = buildDefaultIncludeInput(value.include);
|
|
4682
|
-
}
|
|
4683
|
-
if (value.select)
|
|
4684
|
-
nested.select = buildDefaultSelectInput(value.select);
|
|
4685
|
-
result[key] = Object.keys(nested).length > 0 ? nested : true;
|
|
4686
|
-
}
|
|
4687
|
-
}
|
|
4688
|
-
return result;
|
|
4689
|
-
}
|
|
4690
|
-
function buildDefaultCountInput(config) {
|
|
4691
|
-
if (config === true)
|
|
4692
|
-
return true;
|
|
4693
|
-
if (!isPlainObject(config) || !config.select || !isPlainObject(config.select)) {
|
|
4694
|
-
return true;
|
|
4695
|
-
}
|
|
4696
|
-
const selectObj = config.select;
|
|
4697
|
-
const result = {};
|
|
4698
|
-
for (const key of Object.keys(selectObj)) {
|
|
4699
|
-
result[key] = true;
|
|
4700
|
-
}
|
|
4701
|
-
return { select: result };
|
|
4702
|
-
}
|
|
4703
|
-
function buildDefaultProjectionBody(shape) {
|
|
4704
|
-
if (shape.select) {
|
|
4705
|
-
return { select: buildDefaultSelectInput(shape.select) };
|
|
4706
|
-
}
|
|
4707
|
-
if (shape.include) {
|
|
4708
|
-
return { include: buildDefaultIncludeInput(shape.include) };
|
|
4709
|
-
}
|
|
4710
|
-
return {};
|
|
4711
|
-
}
|
|
4712
|
-
function applyClientProjectionOverrides(shapeDefault, clientProjection) {
|
|
4713
|
-
const result = { ...shapeDefault };
|
|
4714
|
-
for (const [key, clientValue] of Object.entries(clientProjection)) {
|
|
4715
|
-
const defaultValue = result[key];
|
|
4716
|
-
if (defaultValue === void 0) {
|
|
4717
|
-
result[key] = clientValue;
|
|
4718
|
-
continue;
|
|
4719
|
-
}
|
|
4720
|
-
if (clientValue === true) {
|
|
4721
|
-
result[key] = true;
|
|
4722
|
-
continue;
|
|
4723
|
-
}
|
|
4724
|
-
if (isPlainObject(clientValue)) {
|
|
4725
|
-
if (!isPlainObject(defaultValue)) {
|
|
4726
|
-
result[key] = clientValue;
|
|
4727
|
-
continue;
|
|
4728
|
-
}
|
|
4729
|
-
const merged = { ...defaultValue };
|
|
4730
|
-
const clientObj = clientValue;
|
|
4731
|
-
for (const [argKey, argValue] of Object.entries(clientObj)) {
|
|
4732
|
-
const defaultArgValue = merged[argKey];
|
|
4733
|
-
if ((argKey === "select" || argKey === "include") && isPlainObject(argValue) && isPlainObject(defaultArgValue)) {
|
|
4734
|
-
merged[argKey] = applyClientProjectionOverrides(
|
|
4735
|
-
defaultArgValue,
|
|
4736
|
-
argValue
|
|
4737
|
-
);
|
|
4738
|
-
} else {
|
|
4739
|
-
merged[argKey] = argValue;
|
|
4740
|
-
}
|
|
4741
|
-
}
|
|
4742
|
-
result[key] = merged;
|
|
4743
|
-
}
|
|
4744
|
-
}
|
|
4745
|
-
return result;
|
|
4746
|
-
}
|
|
4747
|
-
function hasClientControlledValues(obj) {
|
|
4748
|
-
for (const value of Object.values(obj)) {
|
|
4749
|
-
if (isForcedValue(value))
|
|
4750
|
-
continue;
|
|
4751
|
-
if (value === true)
|
|
4752
|
-
return true;
|
|
4753
|
-
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))
|
|
4754
4823
|
return true;
|
|
4755
|
-
}
|
|
4756
|
-
return false;
|
|
4757
|
-
}
|
|
4758
|
-
function checkIncludeForClientArgs(config) {
|
|
4759
|
-
for (const [key, value] of Object.entries(config)) {
|
|
4760
4824
|
if (key === "_count") {
|
|
4761
4825
|
if (value !== true && isPlainObject(value) && isPlainObject(value.select)) {
|
|
4762
4826
|
const selectObj = value.select;
|
|
4763
4827
|
for (const entryVal of Object.values(selectObj)) {
|
|
4764
4828
|
if (isPlainObject(entryVal) && entryVal.where) {
|
|
4765
4829
|
const w = entryVal.where;
|
|
4766
|
-
if (isPlainObject(w) && hasClientControlledValues(w))
|
|
4830
|
+
if (isPlainObject(w) && hasClientControlledValues(w, depth + 1))
|
|
4767
4831
|
return true;
|
|
4768
4832
|
}
|
|
4769
4833
|
}
|
|
@@ -4772,54 +4836,41 @@ function checkIncludeForClientArgs(config) {
|
|
|
4772
4836
|
}
|
|
4773
4837
|
if (value === true)
|
|
4774
4838
|
continue;
|
|
4775
|
-
|
|
4839
|
+
const nested = value;
|
|
4840
|
+
if (nested.orderBy || nested.cursor || nested.take || nested.skip)
|
|
4776
4841
|
return true;
|
|
4777
|
-
if (
|
|
4842
|
+
if (nested.where && isPlainObject(nested.where) && hasClientControlledValues(nested.where, depth + 1)) {
|
|
4778
4843
|
return true;
|
|
4779
4844
|
}
|
|
4780
|
-
if (
|
|
4845
|
+
if (nested.include && walkForClientContent(nested.include, predicate, depth + 1))
|
|
4781
4846
|
return true;
|
|
4782
|
-
if (
|
|
4847
|
+
if (nested.select && walkForClientContent(nested.select, predicate, depth + 1))
|
|
4783
4848
|
return true;
|
|
4784
4849
|
}
|
|
4785
4850
|
return false;
|
|
4786
4851
|
}
|
|
4787
|
-
function
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
for (const entryVal of Object.values(selectObj)) {
|
|
4793
|
-
if (isPlainObject(entryVal) && entryVal.where) {
|
|
4794
|
-
const w = entryVal.where;
|
|
4795
|
-
if (isPlainObject(w) && hasClientControlledValues(w))
|
|
4796
|
-
return true;
|
|
4797
|
-
}
|
|
4798
|
-
}
|
|
4799
|
-
}
|
|
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))
|
|
4800
4857
|
continue;
|
|
4801
|
-
}
|
|
4802
4858
|
if (value === true)
|
|
4803
|
-
continue;
|
|
4804
|
-
if (value.orderBy || value.cursor || value.take || value.skip)
|
|
4805
4859
|
return true;
|
|
4806
|
-
if (
|
|
4860
|
+
if (isPlainObject(value) && hasClientControlledValues(value, depth + 1)) {
|
|
4807
4861
|
return true;
|
|
4808
4862
|
}
|
|
4809
|
-
if (value.select && checkSelectForClientArgs(value.select))
|
|
4810
|
-
return true;
|
|
4811
|
-
if (value.include && checkIncludeForClientArgs(value.include))
|
|
4812
|
-
return true;
|
|
4813
4863
|
}
|
|
4814
4864
|
return false;
|
|
4815
4865
|
}
|
|
4816
4866
|
function hasNestedClientControlledArgs(shape) {
|
|
4867
|
+
const predicate = () => false;
|
|
4817
4868
|
if (shape.include) {
|
|
4818
|
-
if (
|
|
4869
|
+
if (walkForClientContent(shape.include, predicate, 0))
|
|
4819
4870
|
return true;
|
|
4820
4871
|
}
|
|
4821
4872
|
if (shape.select) {
|
|
4822
|
-
if (
|
|
4873
|
+
if (walkForClientContent(shape.select, predicate, 0))
|
|
4823
4874
|
return true;
|
|
4824
4875
|
}
|
|
4825
4876
|
return false;
|
|
@@ -4891,77 +4942,62 @@ function createModelGuardExtension(config) {
|
|
|
4891
4942
|
const whereBuiltCache = /* @__PURE__ */ new Map();
|
|
4892
4943
|
const projectionCache = /* @__PURE__ */ new Map();
|
|
4893
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
|
+
}
|
|
4894
4955
|
function getReadShape(method, queryShape, matchedKey, wasDynamic) {
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
const built = queryBuilder.buildShapeZodSchema(
|
|
4956
|
+
return memoize(
|
|
4957
|
+
readShapeCache,
|
|
4958
|
+
`${method}\0${matchedKey}`,
|
|
4959
|
+
wasDynamic,
|
|
4960
|
+
() => queryBuilder.buildShapeZodSchema(
|
|
4901
4961
|
modelName,
|
|
4902
4962
|
method,
|
|
4903
4963
|
queryShape
|
|
4904
|
-
)
|
|
4905
|
-
readShapeCache.set(cacheKey, built);
|
|
4906
|
-
return built;
|
|
4907
|
-
}
|
|
4908
|
-
return queryBuilder.buildShapeZodSchema(
|
|
4909
|
-
modelName,
|
|
4910
|
-
method,
|
|
4911
|
-
queryShape
|
|
4964
|
+
)
|
|
4912
4965
|
);
|
|
4913
4966
|
}
|
|
4914
4967
|
function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4968
|
+
const skipCache = wasDynamic || hasDataRefines(dataConfig);
|
|
4969
|
+
return memoize(
|
|
4970
|
+
dataSchemaCache,
|
|
4971
|
+
`${mode}\0${matchedKey}`,
|
|
4972
|
+
skipCache,
|
|
4973
|
+
() => buildDataSchema(
|
|
4921
4974
|
modelName,
|
|
4922
4975
|
dataConfig,
|
|
4923
4976
|
mode,
|
|
4924
4977
|
typeMap,
|
|
4978
|
+
uniqueMap,
|
|
4979
|
+
enumMap,
|
|
4980
|
+
scalarBase,
|
|
4925
4981
|
schemaBuilder,
|
|
4926
4982
|
zodDefaults
|
|
4927
|
-
)
|
|
4928
|
-
dataSchemaCache.set(cacheKey, built);
|
|
4929
|
-
return built;
|
|
4930
|
-
}
|
|
4931
|
-
return buildDataSchema(
|
|
4932
|
-
modelName,
|
|
4933
|
-
dataConfig,
|
|
4934
|
-
mode,
|
|
4935
|
-
typeMap,
|
|
4936
|
-
schemaBuilder,
|
|
4937
|
-
zodDefaults
|
|
4983
|
+
)
|
|
4938
4984
|
);
|
|
4939
4985
|
}
|
|
4940
4986
|
function getWhereBuilt(whereConfig, matchedKey, wasDynamic) {
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
return built;
|
|
4948
|
-
}
|
|
4949
|
-
return queryBuilder.buildWhereSchema(modelName, whereConfig);
|
|
4987
|
+
return memoize(
|
|
4988
|
+
whereBuiltCache,
|
|
4989
|
+
matchedKey,
|
|
4990
|
+
wasDynamic,
|
|
4991
|
+
() => queryBuilder.buildWhereSchema(modelName, whereConfig)
|
|
4992
|
+
);
|
|
4950
4993
|
}
|
|
4951
4994
|
function getUniqueWhereBuilt(whereConfig, matchedKey, wasDynamic) {
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
modelName,
|
|
4959
|
-
whereConfig
|
|
4960
|
-
);
|
|
4961
|
-
uniqueWhereCache.set(cacheKey, built);
|
|
4962
|
-
return built;
|
|
4963
|
-
}
|
|
4964
|
-
return queryBuilder.buildUniqueWhereSchema(modelName, whereConfig);
|
|
4995
|
+
return memoize(
|
|
4996
|
+
uniqueWhereCache,
|
|
4997
|
+
`unique\0${matchedKey}`,
|
|
4998
|
+
wasDynamic,
|
|
4999
|
+
() => queryBuilder.buildUniqueWhereSchema(modelName, whereConfig)
|
|
5000
|
+
);
|
|
4965
5001
|
}
|
|
4966
5002
|
function buildProjectionSchema(shape) {
|
|
4967
5003
|
const schemaFields = {};
|
|
@@ -4988,7 +5024,7 @@ function createModelGuardExtension(config) {
|
|
|
4988
5024
|
forcedSelectCountWhere = result.forcedCountWhere;
|
|
4989
5025
|
}
|
|
4990
5026
|
return {
|
|
4991
|
-
zodSchema:
|
|
5027
|
+
zodSchema: import_zod11.z.object(schemaFields).strict(),
|
|
4992
5028
|
forcedIncludeTree,
|
|
4993
5029
|
forcedSelectTree,
|
|
4994
5030
|
forcedIncludeCountWhere,
|
|
@@ -4996,16 +5032,12 @@ function createModelGuardExtension(config) {
|
|
|
4996
5032
|
};
|
|
4997
5033
|
}
|
|
4998
5034
|
function getProjection(shape, matchedKey, wasDynamic) {
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
projectionCache.set(cacheKey, built);
|
|
5006
|
-
return built;
|
|
5007
|
-
}
|
|
5008
|
-
return buildProjectionSchema(shape);
|
|
5035
|
+
return memoize(
|
|
5036
|
+
projectionCache,
|
|
5037
|
+
`projection\0${matchedKey}`,
|
|
5038
|
+
wasDynamic,
|
|
5039
|
+
() => buildProjectionSchema(shape)
|
|
5040
|
+
);
|
|
5009
5041
|
}
|
|
5010
5042
|
function resolveProjection(shape, parsed, method, matchedKey, wasDynamic) {
|
|
5011
5043
|
const hasBodyProjection = "select" in parsed || "include" in parsed;
|
|
@@ -5199,24 +5231,11 @@ function createModelGuardExtension(config) {
|
|
|
5199
5231
|
const hasShapeProjection = !!resolved.shape.select || !!resolved.shape.include;
|
|
5200
5232
|
if (!hasShapeProjection)
|
|
5201
5233
|
return resolved.body;
|
|
5202
|
-
const defaultProjection = buildDefaultProjectionBody(resolved.shape);
|
|
5203
5234
|
const hasBodyProjection = "select" in resolved.body || "include" in resolved.body;
|
|
5204
|
-
if (
|
|
5205
|
-
return
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
if ("select" in resolved.body && "select" in defaultProjection && isPlainObject(resolved.body.select) && isPlainObject(defaultProjection.select)) {
|
|
5209
|
-
merged.select = applyClientProjectionOverrides(
|
|
5210
|
-
defaultProjection.select,
|
|
5211
|
-
resolved.body.select
|
|
5212
|
-
);
|
|
5213
|
-
} else if ("include" in resolved.body && "include" in defaultProjection && isPlainObject(resolved.body.include) && isPlainObject(defaultProjection.include)) {
|
|
5214
|
-
merged.include = applyClientProjectionOverrides(
|
|
5215
|
-
defaultProjection.include,
|
|
5216
|
-
resolved.body.include
|
|
5217
|
-
);
|
|
5218
|
-
}
|
|
5219
|
-
return merged;
|
|
5235
|
+
if (hasBodyProjection)
|
|
5236
|
+
return resolved.body;
|
|
5237
|
+
const defaultProjection = buildDefaultProjectionBody(resolved.shape);
|
|
5238
|
+
return { ...resolved.body, ...defaultProjection };
|
|
5220
5239
|
}
|
|
5221
5240
|
function makeReadMethod(method) {
|
|
5222
5241
|
return (body) => {
|
|
@@ -5249,29 +5268,21 @@ function createModelGuardExtension(config) {
|
|
|
5249
5268
|
function makeCreateMethod(method) {
|
|
5250
5269
|
const isBatch = BATCH_CREATE_METHODS.has(method);
|
|
5251
5270
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_MANY_PROJECTION;
|
|
5255
|
-
} else if (isBatch) {
|
|
5256
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_MANY;
|
|
5257
|
-
} else if (supportsProjection) {
|
|
5258
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_PROJECTION;
|
|
5259
|
-
} else {
|
|
5260
|
-
allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE;
|
|
5261
|
-
}
|
|
5262
|
-
const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_CREATE_PROJECTION : VALID_SHAPE_KEYS_CREATE;
|
|
5271
|
+
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5272
|
+
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5263
5273
|
return (body) => {
|
|
5264
5274
|
const caller = resolveCaller();
|
|
5265
5275
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5266
5276
|
if (!resolved.shape.data) {
|
|
5267
5277
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5268
5278
|
}
|
|
5269
|
-
|
|
5279
|
+
validateAllowedKeys(
|
|
5270
5280
|
resolved.shape,
|
|
5271
5281
|
allowedShapeKeys,
|
|
5272
|
-
method
|
|
5282
|
+
method,
|
|
5283
|
+
"shape"
|
|
5273
5284
|
);
|
|
5274
|
-
|
|
5285
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, method, "body");
|
|
5275
5286
|
const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
|
|
5276
5287
|
validateCreateCompleteness(
|
|
5277
5288
|
modelName,
|
|
@@ -5330,20 +5341,21 @@ function createModelGuardExtension(config) {
|
|
|
5330
5341
|
const isUniqueWhere = method === "update";
|
|
5331
5342
|
const isBulk = BULK_MUTATION_METHODS.has(method);
|
|
5332
5343
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5333
|
-
const allowedBodyKeys = supportsProjection
|
|
5334
|
-
const allowedShapeKeys = supportsProjection
|
|
5344
|
+
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5345
|
+
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5335
5346
|
return (body) => {
|
|
5336
5347
|
const caller = resolveCaller();
|
|
5337
5348
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5338
5349
|
if (!resolved.shape.data) {
|
|
5339
5350
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
5340
5351
|
}
|
|
5341
|
-
|
|
5352
|
+
validateAllowedKeys(
|
|
5342
5353
|
resolved.shape,
|
|
5343
5354
|
allowedShapeKeys,
|
|
5344
|
-
method
|
|
5355
|
+
method,
|
|
5356
|
+
"shape"
|
|
5345
5357
|
);
|
|
5346
|
-
|
|
5358
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, method, "body");
|
|
5347
5359
|
if (isBulk && !resolved.shape.where) {
|
|
5348
5360
|
throw new ShapeError(
|
|
5349
5361
|
`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`
|
|
@@ -5411,20 +5423,21 @@ function createModelGuardExtension(config) {
|
|
|
5411
5423
|
const isUniqueWhere = method === "delete";
|
|
5412
5424
|
const isBulk = BULK_MUTATION_METHODS.has(method);
|
|
5413
5425
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5414
|
-
const allowedBodyKeys = supportsProjection
|
|
5415
|
-
const allowedShapeKeys = supportsProjection
|
|
5426
|
+
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5427
|
+
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5416
5428
|
return (body) => {
|
|
5417
5429
|
const caller = resolveCaller();
|
|
5418
5430
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5419
5431
|
if (resolved.shape.data) {
|
|
5420
5432
|
throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
|
|
5421
5433
|
}
|
|
5422
|
-
|
|
5434
|
+
validateAllowedKeys(
|
|
5423
5435
|
resolved.shape,
|
|
5424
5436
|
allowedShapeKeys,
|
|
5425
|
-
method
|
|
5437
|
+
method,
|
|
5438
|
+
"shape"
|
|
5426
5439
|
);
|
|
5427
|
-
|
|
5440
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, method, "body");
|
|
5428
5441
|
if (isBulk && !resolved.shape.where) {
|
|
5429
5442
|
throw new ShapeError(
|
|
5430
5443
|
`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`
|
|
@@ -5477,6 +5490,8 @@ function createModelGuardExtension(config) {
|
|
|
5477
5490
|
};
|
|
5478
5491
|
}
|
|
5479
5492
|
function makeUpsertMethod() {
|
|
5493
|
+
const allowedBodyKeys = getAllowedBodyKeys("upsert", true);
|
|
5494
|
+
const allowedShapeKeys = getAllowedShapeKeys("upsert", true);
|
|
5480
5495
|
return (body) => {
|
|
5481
5496
|
const caller = resolveCaller();
|
|
5482
5497
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
@@ -5494,15 +5509,17 @@ function createModelGuardExtension(config) {
|
|
|
5494
5509
|
if (!resolved.shape.where) {
|
|
5495
5510
|
throw new ShapeError('Guard shape requires "where" for upsert');
|
|
5496
5511
|
}
|
|
5497
|
-
|
|
5512
|
+
validateAllowedKeys(
|
|
5498
5513
|
resolved.shape,
|
|
5499
|
-
|
|
5500
|
-
"upsert"
|
|
5514
|
+
allowedShapeKeys,
|
|
5515
|
+
"upsert",
|
|
5516
|
+
"shape"
|
|
5501
5517
|
);
|
|
5502
|
-
|
|
5518
|
+
validateAllowedKeys(
|
|
5503
5519
|
resolved.body,
|
|
5504
|
-
|
|
5505
|
-
"upsert"
|
|
5520
|
+
allowedBodyKeys,
|
|
5521
|
+
"upsert",
|
|
5522
|
+
"body"
|
|
5506
5523
|
);
|
|
5507
5524
|
validateUniqueWhereShapeConfig(
|
|
5508
5525
|
modelName,
|
|
@@ -5592,12 +5609,7 @@ function createModelGuardExtension(config) {
|
|
|
5592
5609
|
try {
|
|
5593
5610
|
return fn(body);
|
|
5594
5611
|
} catch (err) {
|
|
5595
|
-
|
|
5596
|
-
throw new ShapeError(`Validation failed: ${formatZodError(err)}`, {
|
|
5597
|
-
cause: err
|
|
5598
|
-
});
|
|
5599
|
-
}
|
|
5600
|
-
throw err;
|
|
5612
|
+
throw toShapeError(err);
|
|
5601
5613
|
}
|
|
5602
5614
|
};
|
|
5603
5615
|
}
|
|
@@ -5630,6 +5642,15 @@ function createModelGuardExtension(config) {
|
|
|
5630
5642
|
}
|
|
5631
5643
|
|
|
5632
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
|
+
}
|
|
5633
5654
|
function createGuard(config) {
|
|
5634
5655
|
const scalarBase = createScalarBase(
|
|
5635
5656
|
config.guardConfig.strictDecimal ?? false
|
|
@@ -5651,14 +5672,6 @@ function createGuard(config) {
|
|
|
5651
5672
|
warn: (msg) => console.warn(msg)
|
|
5652
5673
|
};
|
|
5653
5674
|
const wrapZodErrors = config.wrapZodErrors ?? false;
|
|
5654
|
-
function rethrowZod(err) {
|
|
5655
|
-
if (err instanceof import_zod10.ZodError) {
|
|
5656
|
-
throw new ShapeError(`Validation failed: ${formatZodError(err)}`, {
|
|
5657
|
-
cause: err
|
|
5658
|
-
});
|
|
5659
|
-
}
|
|
5660
|
-
throw err;
|
|
5661
|
-
}
|
|
5662
5675
|
return {
|
|
5663
5676
|
input: (model, opts) => {
|
|
5664
5677
|
const result = schemaBuilder.buildInputSchema(model, opts);
|
|
@@ -5666,13 +5679,7 @@ function createGuard(config) {
|
|
|
5666
5679
|
return result;
|
|
5667
5680
|
return {
|
|
5668
5681
|
schema: result.schema,
|
|
5669
|
-
parse(
|
|
5670
|
-
try {
|
|
5671
|
-
return result.parse(data);
|
|
5672
|
-
} catch (err) {
|
|
5673
|
-
rethrowZod(err);
|
|
5674
|
-
}
|
|
5675
|
-
}
|
|
5682
|
+
parse: wrapParseFn(result.parse)
|
|
5676
5683
|
};
|
|
5677
5684
|
},
|
|
5678
5685
|
model: (model, opts) => schemaBuilder.buildModelSchema(model, opts),
|
|
@@ -5682,13 +5689,7 @@ function createGuard(config) {
|
|
|
5682
5689
|
return qs;
|
|
5683
5690
|
return {
|
|
5684
5691
|
schemas: qs.schemas,
|
|
5685
|
-
parse(
|
|
5686
|
-
try {
|
|
5687
|
-
return qs.parse(body, opts);
|
|
5688
|
-
} catch (err) {
|
|
5689
|
-
rethrowZod(err);
|
|
5690
|
-
}
|
|
5691
|
-
}
|
|
5692
|
+
parse: wrapParseFn(qs.parse)
|
|
5692
5693
|
};
|
|
5693
5694
|
},
|
|
5694
5695
|
extension: (contextFn) => {
|