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