prisma-guard 1.28.1 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -1
- package/dist/generator/index.js +42 -33
- package/dist/generator/index.js.map +1 -1
- package/dist/runtime/index.cjs +293 -199
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +11 -2
- package/dist/runtime/index.d.ts +11 -2
- package/dist/runtime/index.js +293 -199
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
package/dist/runtime/index.js
CHANGED
|
@@ -212,7 +212,7 @@ function createScalarBase(strictDecimal) {
|
|
|
212
212
|
return {
|
|
213
213
|
String: () => z.string(),
|
|
214
214
|
Int: () => z.number().int(),
|
|
215
|
-
Float: () => z.number(),
|
|
215
|
+
Float: () => z.number().finite(),
|
|
216
216
|
Decimal: createDecimalFactory(strictDecimal),
|
|
217
217
|
BigInt: () => z.union([
|
|
218
218
|
z.bigint(),
|
|
@@ -276,6 +276,9 @@ function isPlainObject(v) {
|
|
|
276
276
|
const proto = Object.getPrototypeOf(v);
|
|
277
277
|
return proto === Object.prototype || proto === null;
|
|
278
278
|
}
|
|
279
|
+
function isObjectLike(v) {
|
|
280
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
281
|
+
}
|
|
279
282
|
function schemaProducesValueForUndefined(schema) {
|
|
280
283
|
const result = schema.safeParse(void 0);
|
|
281
284
|
return result.success && result.data !== void 0;
|
|
@@ -353,6 +356,19 @@ function requireConfigTrue(config, context) {
|
|
|
353
356
|
}
|
|
354
357
|
}
|
|
355
358
|
}
|
|
359
|
+
function requirePlainObjectConfig(value, message) {
|
|
360
|
+
if (!isPlainObject(value)) {
|
|
361
|
+
throw new ShapeError(message);
|
|
362
|
+
}
|
|
363
|
+
return value;
|
|
364
|
+
}
|
|
365
|
+
function assertAllowedKeys(value, allowed, makeError) {
|
|
366
|
+
for (const key of Object.keys(value)) {
|
|
367
|
+
if (!allowed.has(key)) {
|
|
368
|
+
throw new ShapeError(makeError(key));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
356
372
|
|
|
357
373
|
// src/runtime/zod-type-map.ts
|
|
358
374
|
var SCALAR_OPERATORS = {
|
|
@@ -416,24 +432,12 @@ var JSON_ARRAY_OPERATORS = /* @__PURE__ */ new Set([
|
|
|
416
432
|
"array_starts_with",
|
|
417
433
|
"array_ends_with"
|
|
418
434
|
]);
|
|
419
|
-
function getSupportedOperators(
|
|
420
|
-
|
|
421
|
-
let list;
|
|
422
|
-
let enumField;
|
|
423
|
-
if (typeof input === "string") {
|
|
424
|
-
fieldType = input;
|
|
425
|
-
list = isList;
|
|
426
|
-
enumField = isEnum;
|
|
427
|
-
} else {
|
|
428
|
-
fieldType = input.type;
|
|
429
|
-
list = input.isList;
|
|
430
|
-
enumField = input.isEnum === true;
|
|
431
|
-
}
|
|
432
|
-
if (list)
|
|
435
|
+
function getSupportedOperators(fieldMeta) {
|
|
436
|
+
if (fieldMeta.isList)
|
|
433
437
|
return [...SCALAR_LIST_OPERATORS];
|
|
434
|
-
if (
|
|
438
|
+
if (fieldMeta.isEnum === true)
|
|
435
439
|
return [...ENUM_OPERATORS];
|
|
436
|
-
const ops = SCALAR_OPERATORS[
|
|
440
|
+
const ops = SCALAR_OPERATORS[fieldMeta.type];
|
|
437
441
|
if (!ops)
|
|
438
442
|
return [];
|
|
439
443
|
return [...ops];
|
|
@@ -998,6 +1002,7 @@ function validateContext(ctx) {
|
|
|
998
1002
|
|
|
999
1003
|
// src/runtime/query-builder-where.ts
|
|
1000
1004
|
import { z as z5 } from "zod";
|
|
1005
|
+
import { inspect } from "util";
|
|
1001
1006
|
|
|
1002
1007
|
// src/shared/deep-clone.ts
|
|
1003
1008
|
function deepClone(value) {
|
|
@@ -1278,15 +1283,10 @@ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
|
|
|
1278
1283
|
try {
|
|
1279
1284
|
validated = built.zodSchema.parse(parseable);
|
|
1280
1285
|
} catch (err) {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
throw new ShapeError(`${context}: ${formatZodError(err)}`, {
|
|
1286
|
-
cause: err
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
|
-
throw err;
|
|
1286
|
+
wrapParseError(
|
|
1287
|
+
err,
|
|
1288
|
+
modelName ? `Invalid query on model "${modelName}"` : "Invalid query"
|
|
1289
|
+
);
|
|
1290
1290
|
}
|
|
1291
1291
|
if (hasWhereForced(built.forcedWhere)) {
|
|
1292
1292
|
validated.where = isUniqueMethod ? mergeUniqueWhereForced(
|
|
@@ -1603,37 +1603,8 @@ var JSON_STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
|
1603
1603
|
]);
|
|
1604
1604
|
var NEGATIVE_RELATION_OPS = /* @__PURE__ */ new Set(["none", "isNot"]);
|
|
1605
1605
|
var MAX_WHERE_DEPTH = 10;
|
|
1606
|
-
function
|
|
1607
|
-
|
|
1608
|
-
return `${value}n`;
|
|
1609
|
-
if (typeof value === "undefined")
|
|
1610
|
-
return "undefined";
|
|
1611
|
-
if (typeof value === "function")
|
|
1612
|
-
return "[function]";
|
|
1613
|
-
if (typeof value === "symbol")
|
|
1614
|
-
return value.toString();
|
|
1615
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
1616
|
-
try {
|
|
1617
|
-
const json = JSON.stringify(value, (_key, current) => {
|
|
1618
|
-
if (typeof current === "bigint")
|
|
1619
|
-
return `${current}n`;
|
|
1620
|
-
if (typeof current === "undefined")
|
|
1621
|
-
return "[undefined]";
|
|
1622
|
-
if (typeof current === "function")
|
|
1623
|
-
return "[function]";
|
|
1624
|
-
if (typeof current === "symbol")
|
|
1625
|
-
return current.toString();
|
|
1626
|
-
if (current && typeof current === "object") {
|
|
1627
|
-
if (seen.has(current))
|
|
1628
|
-
return "[Circular]";
|
|
1629
|
-
seen.add(current);
|
|
1630
|
-
}
|
|
1631
|
-
return current;
|
|
1632
|
-
});
|
|
1633
|
-
return json === void 0 ? String(value) : json;
|
|
1634
|
-
} catch {
|
|
1635
|
-
return String(value);
|
|
1636
|
-
}
|
|
1606
|
+
function formatValue(value) {
|
|
1607
|
+
return inspect(value, { depth: 3, breakLength: Infinity });
|
|
1637
1608
|
}
|
|
1638
1609
|
function mergeScalarConditions(target, source) {
|
|
1639
1610
|
for (const [field, ops] of Object.entries(source)) {
|
|
@@ -1654,7 +1625,7 @@ function mergeScalarConditions(target, source) {
|
|
|
1654
1625
|
const existingVal = existing[op];
|
|
1655
1626
|
if (!deepEqual(existingVal, val)) {
|
|
1656
1627
|
throw new ShapeError(
|
|
1657
|
-
`Conflicting forced where values for "${field}.${op}": shape defines both ${
|
|
1628
|
+
`Conflicting forced where values for "${field}.${op}": shape defines both ${formatValue(existingVal)} and ${formatValue(val)}`
|
|
1658
1629
|
);
|
|
1659
1630
|
}
|
|
1660
1631
|
}
|
|
@@ -2492,10 +2463,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2492
2463
|
`${fieldMeta.type} field "${fieldName}" cannot be used in having`
|
|
2493
2464
|
);
|
|
2494
2465
|
}
|
|
2495
|
-
const allowedOps = getSupportedOperators(
|
|
2496
|
-
fieldMeta.type,
|
|
2497
|
-
fieldMeta.isList
|
|
2498
|
-
);
|
|
2466
|
+
const allowedOps = getSupportedOperators(fieldMeta);
|
|
2499
2467
|
const opSchemas = {};
|
|
2500
2468
|
for (const op of allowedOps) {
|
|
2501
2469
|
opSchemas[op] = createOperatorSchema(
|
|
@@ -2672,20 +2640,27 @@ function buildDefaultProjectionBody(shape) {
|
|
|
2672
2640
|
|
|
2673
2641
|
// src/runtime/query-builder-projection.ts
|
|
2674
2642
|
var KNOWN_NESTED_KEYS = {
|
|
2675
|
-
include: /* @__PURE__ */ new Set([
|
|
2676
|
-
|
|
2643
|
+
include: /* @__PURE__ */ new Set([
|
|
2644
|
+
"where",
|
|
2645
|
+
"include",
|
|
2646
|
+
"select",
|
|
2647
|
+
"orderBy",
|
|
2648
|
+
"cursor",
|
|
2649
|
+
"take",
|
|
2650
|
+
"skip"
|
|
2651
|
+
]),
|
|
2652
|
+
select: /* @__PURE__ */ new Set([
|
|
2653
|
+
"select",
|
|
2654
|
+
"include",
|
|
2655
|
+
"where",
|
|
2656
|
+
"orderBy",
|
|
2657
|
+
"cursor",
|
|
2658
|
+
"take",
|
|
2659
|
+
"skip"
|
|
2660
|
+
])
|
|
2677
2661
|
};
|
|
2678
2662
|
var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
|
|
2679
2663
|
var MAX_PROJECTION_DEPTH = 10;
|
|
2680
|
-
function validateNestedKeys(keys, allowed, context) {
|
|
2681
|
-
for (const key of keys) {
|
|
2682
|
-
if (!allowed.has(key)) {
|
|
2683
|
-
throw new ShapeError(
|
|
2684
|
-
`Unknown key "${key}" in ${context}. Allowed: ${[...allowed].join(", ")}`
|
|
2685
|
-
);
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
}
|
|
2689
2664
|
function hasDefinedKeys(v) {
|
|
2690
2665
|
return Object.values(v).some((value) => value !== void 0);
|
|
2691
2666
|
}
|
|
@@ -2698,6 +2673,20 @@ function wrapRelationSchema(nestedObj, skeleton) {
|
|
|
2698
2673
|
collapsed
|
|
2699
2674
|
);
|
|
2700
2675
|
}
|
|
2676
|
+
function buildRelationWhere(relatedType, whereConfig, context, buildWhereSchema) {
|
|
2677
|
+
if (Object.keys(whereConfig).length === 0) {
|
|
2678
|
+
throw new ShapeError(
|
|
2679
|
+
`Empty "where" in ${context}. Define at least one field.`
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
const { schema, forced } = buildWhereSchema(relatedType, whereConfig);
|
|
2683
|
+
if (!schema && !hasWhereForced(forced)) {
|
|
2684
|
+
throw new ShapeError(
|
|
2685
|
+
`"where" in ${context} produced no schema and no forced conditions. Define at least one field.`
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
return { schema, forced };
|
|
2689
|
+
}
|
|
2701
2690
|
function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
2702
2691
|
function buildIncludeCountSchema(model, config) {
|
|
2703
2692
|
const modelFields = typeMap[model];
|
|
@@ -2711,13 +2700,11 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2711
2700
|
`Invalid _count config on model "${model}". Expected true or { select: { ... } }`
|
|
2712
2701
|
);
|
|
2713
2702
|
}
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
}
|
|
2720
|
-
}
|
|
2703
|
+
assertAllowedKeys(
|
|
2704
|
+
config,
|
|
2705
|
+
/* @__PURE__ */ new Set(["select"]),
|
|
2706
|
+
(key) => `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
|
|
2707
|
+
);
|
|
2721
2708
|
if (!isPlainObject(config.select)) {
|
|
2722
2709
|
throw new ShapeError(
|
|
2723
2710
|
`Invalid _count.select on model "${model}". Expected a plain object with relation field keys.`
|
|
@@ -2734,11 +2721,17 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2734
2721
|
for (const [fieldName, fieldConfig] of Object.entries(selectObj)) {
|
|
2735
2722
|
const fieldMeta = modelFields[fieldName];
|
|
2736
2723
|
if (!fieldMeta)
|
|
2737
|
-
throw new ShapeError(
|
|
2724
|
+
throw new ShapeError(
|
|
2725
|
+
`Unknown field "${fieldName}" on model "${model}" in _count.select`
|
|
2726
|
+
);
|
|
2738
2727
|
if (!fieldMeta.isRelation)
|
|
2739
|
-
throw new ShapeError(
|
|
2728
|
+
throw new ShapeError(
|
|
2729
|
+
`Field "${fieldName}" is not a relation on model "${model}" in _count.select`
|
|
2730
|
+
);
|
|
2740
2731
|
if (!fieldMeta.isList)
|
|
2741
|
-
throw new ShapeError(
|
|
2732
|
+
throw new ShapeError(
|
|
2733
|
+
`Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`
|
|
2734
|
+
);
|
|
2742
2735
|
if (fieldConfig === true) {
|
|
2743
2736
|
countSelectFields[fieldName] = z7.literal(true).optional();
|
|
2744
2737
|
continue;
|
|
@@ -2753,16 +2746,18 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2753
2746
|
`Empty config for _count.select.${fieldName} on model "${model}". Use true or { where: { ... } }.`
|
|
2754
2747
|
);
|
|
2755
2748
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2749
|
+
assertAllowedKeys(
|
|
2750
|
+
fieldConfig,
|
|
2758
2751
|
KNOWN_COUNT_SELECT_ENTRY_KEYS,
|
|
2759
|
-
`_count.select.${fieldName} on model "${model}"`
|
|
2752
|
+
(key) => `Unknown key "${key}" in _count.select.${fieldName} on model "${model}". Allowed: ${[...KNOWN_COUNT_SELECT_ENTRY_KEYS].join(", ")}`
|
|
2760
2753
|
);
|
|
2761
2754
|
if (fieldConfig.where) {
|
|
2762
2755
|
const relatedType = fieldMeta.type;
|
|
2763
|
-
const { schema: whereSchema, forced } =
|
|
2756
|
+
const { schema: whereSchema, forced } = buildRelationWhere(
|
|
2764
2757
|
relatedType,
|
|
2765
|
-
fieldConfig.where
|
|
2758
|
+
fieldConfig.where,
|
|
2759
|
+
`_count.select.${fieldName} on model "${model}"`,
|
|
2760
|
+
deps.buildWhereSchema
|
|
2766
2761
|
);
|
|
2767
2762
|
const nestedSchemas = {};
|
|
2768
2763
|
if (whereSchema)
|
|
@@ -2785,13 +2780,15 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2785
2780
|
forcedCountWhere
|
|
2786
2781
|
};
|
|
2787
2782
|
}
|
|
2788
|
-
function buildNestedRelSchemas(relatedType, config, depth) {
|
|
2783
|
+
function buildNestedRelSchemas(relatedType, config, depth, context) {
|
|
2789
2784
|
const nestedSchemas = {};
|
|
2790
2785
|
const relForced = {};
|
|
2791
2786
|
if (config.where) {
|
|
2792
|
-
const { schema: whereSchema, forced } =
|
|
2787
|
+
const { schema: whereSchema, forced } = buildRelationWhere(
|
|
2793
2788
|
relatedType,
|
|
2794
|
-
config.where
|
|
2789
|
+
config.where,
|
|
2790
|
+
context,
|
|
2791
|
+
deps.buildWhereSchema
|
|
2795
2792
|
);
|
|
2796
2793
|
if (whereSchema)
|
|
2797
2794
|
nestedSchemas["where"] = whereSchema;
|
|
@@ -2799,7 +2796,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2799
2796
|
relForced.where = forced;
|
|
2800
2797
|
}
|
|
2801
2798
|
if (config.include) {
|
|
2802
|
-
const nested = buildProjectionSchema(
|
|
2799
|
+
const nested = buildProjectionSchema(
|
|
2800
|
+
"include",
|
|
2801
|
+
relatedType,
|
|
2802
|
+
config.include,
|
|
2803
|
+
depth + 1
|
|
2804
|
+
);
|
|
2803
2805
|
nestedSchemas["include"] = nested.schema;
|
|
2804
2806
|
if (Object.keys(nested.forcedTree).length > 0)
|
|
2805
2807
|
relForced.include = nested.forcedTree;
|
|
@@ -2809,7 +2811,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2809
2811
|
}
|
|
2810
2812
|
}
|
|
2811
2813
|
if (config.select) {
|
|
2812
|
-
const nested = buildProjectionSchema(
|
|
2814
|
+
const nested = buildProjectionSchema(
|
|
2815
|
+
"select",
|
|
2816
|
+
relatedType,
|
|
2817
|
+
config.select,
|
|
2818
|
+
depth + 1
|
|
2819
|
+
);
|
|
2813
2820
|
nestedSchemas["select"] = nested.schema;
|
|
2814
2821
|
if (Object.keys(nested.forcedTree).length > 0)
|
|
2815
2822
|
relForced.select = nested.forcedTree;
|
|
@@ -2819,15 +2826,26 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2819
2826
|
}
|
|
2820
2827
|
}
|
|
2821
2828
|
if (config.orderBy) {
|
|
2822
|
-
nestedSchemas["orderBy"] = deps.buildOrderBySchema(
|
|
2829
|
+
nestedSchemas["orderBy"] = deps.buildOrderBySchema(
|
|
2830
|
+
relatedType,
|
|
2831
|
+
config.orderBy
|
|
2832
|
+
);
|
|
2823
2833
|
}
|
|
2824
2834
|
if (config.cursor) {
|
|
2825
|
-
nestedSchemas["cursor"] = deps.buildCursorSchema(
|
|
2835
|
+
nestedSchemas["cursor"] = deps.buildCursorSchema(
|
|
2836
|
+
relatedType,
|
|
2837
|
+
config.cursor
|
|
2838
|
+
);
|
|
2826
2839
|
}
|
|
2827
|
-
if (config.take) {
|
|
2840
|
+
if ("take" in config && config.take !== void 0) {
|
|
2828
2841
|
nestedSchemas["take"] = deps.buildTakeSchema(config.take);
|
|
2829
2842
|
}
|
|
2830
|
-
if (config.skip) {
|
|
2843
|
+
if ("skip" in config && config.skip !== void 0) {
|
|
2844
|
+
if (config.skip !== true) {
|
|
2845
|
+
throw new ShapeError(
|
|
2846
|
+
`Nested "skip" in ${context} must be true`
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2831
2849
|
nestedSchemas["skip"] = z7.number().int().min(0).optional();
|
|
2832
2850
|
}
|
|
2833
2851
|
return { nestedSchemas, relForced };
|
|
@@ -2853,28 +2871,43 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2853
2871
|
let topLevelForcedCountWhere = {};
|
|
2854
2872
|
for (const [fieldName, config] of Object.entries(projectionConfig)) {
|
|
2855
2873
|
if (fieldName === "_count") {
|
|
2856
|
-
const countResult = buildIncludeCountSchema(
|
|
2874
|
+
const countResult = buildIncludeCountSchema(
|
|
2875
|
+
model,
|
|
2876
|
+
config
|
|
2877
|
+
);
|
|
2857
2878
|
fieldSchemas["_count"] = countResult.schema;
|
|
2858
2879
|
topLevelForcedCountWhere = countResult.forcedCountWhere;
|
|
2859
2880
|
continue;
|
|
2860
2881
|
}
|
|
2861
2882
|
const fieldMeta = modelFields[fieldName];
|
|
2862
2883
|
if (!fieldMeta)
|
|
2863
|
-
throw new ShapeError(
|
|
2884
|
+
throw new ShapeError(
|
|
2885
|
+
`Unknown field "${fieldName}" on model "${model}"`
|
|
2886
|
+
);
|
|
2864
2887
|
if (mode === "include" && !fieldMeta.isRelation) {
|
|
2865
|
-
throw new ShapeError(
|
|
2888
|
+
throw new ShapeError(
|
|
2889
|
+
`Field "${fieldName}" is not a relation on model "${model}"`
|
|
2890
|
+
);
|
|
2866
2891
|
}
|
|
2867
2892
|
if (config === true) {
|
|
2868
2893
|
fieldSchemas[fieldName] = z7.literal(true).optional();
|
|
2869
2894
|
continue;
|
|
2870
2895
|
}
|
|
2871
2896
|
if (mode === "select" && !fieldMeta.isRelation) {
|
|
2872
|
-
throw new ShapeError(
|
|
2897
|
+
throw new ShapeError(
|
|
2898
|
+
`Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`
|
|
2899
|
+
);
|
|
2873
2900
|
}
|
|
2874
2901
|
const contextLabel = `nested ${mode} for "${fieldName}" on model "${model}"`;
|
|
2875
|
-
|
|
2902
|
+
assertAllowedKeys(
|
|
2903
|
+
config,
|
|
2904
|
+
allowedNestedKeys,
|
|
2905
|
+
(key) => `Unknown key "${key}" in ${contextLabel}. Allowed: ${[...allowedNestedKeys].join(", ")}`
|
|
2906
|
+
);
|
|
2876
2907
|
if (config.select && config.include) {
|
|
2877
|
-
throw new ShapeError(
|
|
2908
|
+
throw new ShapeError(
|
|
2909
|
+
`Nested ${mode} for "${fieldName}" cannot define both "select" and "include".`
|
|
2910
|
+
);
|
|
2878
2911
|
}
|
|
2879
2912
|
if (!fieldMeta.isList) {
|
|
2880
2913
|
if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
|
|
@@ -2883,7 +2916,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2883
2916
|
);
|
|
2884
2917
|
}
|
|
2885
2918
|
}
|
|
2886
|
-
const { nestedSchemas, relForced } = buildNestedRelSchemas(
|
|
2919
|
+
const { nestedSchemas, relForced } = buildNestedRelSchemas(
|
|
2920
|
+
fieldMeta.type,
|
|
2921
|
+
config,
|
|
2922
|
+
currentDepth,
|
|
2923
|
+
contextLabel
|
|
2924
|
+
);
|
|
2887
2925
|
const nestedObj = z7.object(nestedSchemas).strict();
|
|
2888
2926
|
fieldSchemas[fieldName] = wrapRelationSchema(
|
|
2889
2927
|
nestedObj,
|
|
@@ -2908,7 +2946,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
|
|
|
2908
2946
|
function buildSelectSchema(model, selectConfig, depth) {
|
|
2909
2947
|
return buildProjectionSchema("select", model, selectConfig, depth);
|
|
2910
2948
|
}
|
|
2911
|
-
return {
|
|
2949
|
+
return {
|
|
2950
|
+
buildIncludeSchema,
|
|
2951
|
+
buildSelectSchema,
|
|
2952
|
+
buildIncludeCountSchema,
|
|
2953
|
+
buildProjectionSchema
|
|
2954
|
+
};
|
|
2912
2955
|
}
|
|
2913
2956
|
|
|
2914
2957
|
// src/shared/operation-shape-keys.ts
|
|
@@ -2924,10 +2967,10 @@ var OPERATION_SHAPE_KEYS = {
|
|
|
2924
2967
|
groupBy: ["where", "orderBy", "by", "having", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
|
|
2925
2968
|
create: ["data", "include", "select"],
|
|
2926
2969
|
createMany: ["data", "skipDuplicates"],
|
|
2927
|
-
createManyAndReturn: ["data", "select", "skipDuplicates"],
|
|
2970
|
+
createManyAndReturn: ["data", "select", "include", "skipDuplicates"],
|
|
2928
2971
|
update: ["where", "data", "include", "select"],
|
|
2929
2972
|
updateMany: ["where", "data"],
|
|
2930
|
-
updateManyAndReturn: ["where", "data", "select"],
|
|
2973
|
+
updateManyAndReturn: ["where", "data", "select", "include"],
|
|
2931
2974
|
upsert: ["where", "create", "update", "include", "select"],
|
|
2932
2975
|
delete: ["where", "include", "select"],
|
|
2933
2976
|
deleteMany: ["where"]
|
|
@@ -3241,7 +3284,17 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3241
3284
|
let forcedIncludeCountWhere = {};
|
|
3242
3285
|
let forcedSelectCountWhere = {};
|
|
3243
3286
|
if (shape.where) {
|
|
3287
|
+
if (Object.keys(shape.where).length === 0) {
|
|
3288
|
+
throw new ShapeError(
|
|
3289
|
+
`Empty "where" in shape for model "${model}" method "${method}". Define at least one field.`
|
|
3290
|
+
);
|
|
3291
|
+
}
|
|
3244
3292
|
const builtWhere = UNIQUE_WHERE_METHODS.has(method) ? whereBuilder.buildUniqueWhereSchema(model, shape.where) : whereBuilder.buildWhereSchema(model, shape.where);
|
|
3293
|
+
if (!builtWhere.schema && !hasWhereForced(builtWhere.forced)) {
|
|
3294
|
+
throw new ShapeError(
|
|
3295
|
+
`"where" in shape for model "${model}" method "${method}" produced no schema and no forced conditions.`
|
|
3296
|
+
);
|
|
3297
|
+
}
|
|
3245
3298
|
if (builtWhere.schema) {
|
|
3246
3299
|
schemaFields.where = builtWhere.schema;
|
|
3247
3300
|
}
|
|
@@ -4043,27 +4096,19 @@ function validateRelationOpKeys(actual, opKey, model, field, opLabel) {
|
|
|
4043
4096
|
const allowed = RELATION_OP_ALLOWED_KEYS[opKey];
|
|
4044
4097
|
if (!allowed)
|
|
4045
4098
|
return;
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
}
|
|
4052
|
-
}
|
|
4099
|
+
assertAllowedKeys(
|
|
4100
|
+
actual,
|
|
4101
|
+
allowed,
|
|
4102
|
+
(key) => `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
|
|
4103
|
+
);
|
|
4053
4104
|
}
|
|
4054
4105
|
function validateAllowedKeys(value, allowed, method, kind) {
|
|
4055
|
-
|
|
4056
|
-
if (
|
|
4057
|
-
|
|
4058
|
-
throw new ShapeError(
|
|
4059
|
-
`Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`
|
|
4060
|
-
);
|
|
4061
|
-
}
|
|
4062
|
-
throw new ShapeError(
|
|
4063
|
-
`Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
|
|
4064
|
-
);
|
|
4106
|
+
assertAllowedKeys(value, allowed, (key) => {
|
|
4107
|
+
if (kind === "body") {
|
|
4108
|
+
return `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`;
|
|
4065
4109
|
}
|
|
4066
|
-
|
|
4110
|
+
return `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`;
|
|
4111
|
+
});
|
|
4067
4112
|
}
|
|
4068
4113
|
function validateCreateCompleteness(modelName, dataConfig, typeMap, scopeFks, zodDefaults) {
|
|
4069
4114
|
const modelFields = typeMap[modelName];
|
|
@@ -4150,18 +4195,10 @@ function buildNestedDataSchema(model, config, mode, typeMap, schemaBuilder) {
|
|
|
4150
4195
|
}
|
|
4151
4196
|
return z10.object(fieldSchemas).strict();
|
|
4152
4197
|
}
|
|
4153
|
-
function requirePlainObjectConfig(value, message) {
|
|
4154
|
-
if (!isPlainObject(value))
|
|
4155
|
-
throw new ShapeError(message);
|
|
4156
|
-
return value;
|
|
4157
|
-
}
|
|
4158
4198
|
function requireNestedObject(cfg, key, message) {
|
|
4159
|
-
|
|
4160
|
-
if (!v || !isPlainObject(v))
|
|
4161
|
-
throw new ShapeError(message);
|
|
4162
|
-
return v;
|
|
4199
|
+
return requirePlainObjectConfig(cfg[key], message);
|
|
4163
4200
|
}
|
|
4164
|
-
function
|
|
4201
|
+
function buildRelatedUniqueSelector(ctx, cfg, context) {
|
|
4165
4202
|
return buildUniqueSelectorSchema(
|
|
4166
4203
|
ctx.model,
|
|
4167
4204
|
ctx.fieldName,
|
|
@@ -4174,7 +4211,7 @@ function buildUniqueSelector(ctx, cfg, context) {
|
|
|
4174
4211
|
context
|
|
4175
4212
|
);
|
|
4176
4213
|
}
|
|
4177
|
-
function
|
|
4214
|
+
function buildRelatedNestedData(ctx, cfg, mode) {
|
|
4178
4215
|
return buildNestedDataSchema(
|
|
4179
4216
|
ctx.relatedModelName,
|
|
4180
4217
|
cfg,
|
|
@@ -4188,7 +4225,7 @@ var handleConnect = (ctx) => {
|
|
|
4188
4225
|
ctx.config,
|
|
4189
4226
|
`connect config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
|
|
4190
4227
|
);
|
|
4191
|
-
const schema =
|
|
4228
|
+
const schema = buildRelatedUniqueSelector(ctx, cfg, "connect");
|
|
4192
4229
|
return wrapRelationOp(ctx.isList, schema);
|
|
4193
4230
|
};
|
|
4194
4231
|
var handleConnectOrCreate = (ctx) => {
|
|
@@ -4207,8 +4244,8 @@ var handleConnectOrCreate = (ctx) => {
|
|
|
4207
4244
|
"create",
|
|
4208
4245
|
`connectOrCreate on "${ctx.model}.${ctx.fieldName}" requires "create" object`
|
|
4209
4246
|
);
|
|
4210
|
-
const whereSchema =
|
|
4211
|
-
const createSchema =
|
|
4247
|
+
const whereSchema = buildRelatedUniqueSelector(ctx, where, "connectOrCreate.where");
|
|
4248
|
+
const createSchema = buildRelatedNestedData(ctx, create, "create");
|
|
4212
4249
|
const cocSchema = z10.object({ where: whereSchema, create: createSchema }).strict();
|
|
4213
4250
|
return wrapRelationOp(ctx.isList, cocSchema);
|
|
4214
4251
|
};
|
|
@@ -4217,7 +4254,7 @@ var handleCreate = (ctx) => {
|
|
|
4217
4254
|
ctx.config,
|
|
4218
4255
|
`create config on "${ctx.model}.${ctx.fieldName}" must be an object of field names`
|
|
4219
4256
|
);
|
|
4220
|
-
const createSchema =
|
|
4257
|
+
const createSchema = buildRelatedNestedData(ctx, cfg, "create");
|
|
4221
4258
|
return wrapRelationOp(ctx.isList, createSchema);
|
|
4222
4259
|
};
|
|
4223
4260
|
var handleCreateMany = (ctx) => {
|
|
@@ -4236,7 +4273,7 @@ var handleCreateMany = (ctx) => {
|
|
|
4236
4273
|
"data",
|
|
4237
4274
|
`createMany on "${ctx.model}.${ctx.fieldName}" requires "data" object`
|
|
4238
4275
|
);
|
|
4239
|
-
const dataSchema =
|
|
4276
|
+
const dataSchema = buildRelatedNestedData(ctx, data, "create");
|
|
4240
4277
|
const cmSchemaFields = {
|
|
4241
4278
|
data: z10.preprocess(coerceToArray, z10.array(dataSchema))
|
|
4242
4279
|
};
|
|
@@ -4259,7 +4296,7 @@ var handleDisconnect = (ctx) => {
|
|
|
4259
4296
|
`disconnect config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
|
|
4260
4297
|
);
|
|
4261
4298
|
}
|
|
4262
|
-
const schema =
|
|
4299
|
+
const schema = buildRelatedUniqueSelector(ctx, ctx.config, "disconnect");
|
|
4263
4300
|
if (ctx.isList)
|
|
4264
4301
|
return wrapRelationOp(true, schema);
|
|
4265
4302
|
return z10.union([z10.literal(true), schema]).optional();
|
|
@@ -4278,7 +4315,7 @@ var handleDelete = (ctx) => {
|
|
|
4278
4315
|
`delete config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
|
|
4279
4316
|
);
|
|
4280
4317
|
}
|
|
4281
|
-
const schema =
|
|
4318
|
+
const schema = buildRelatedUniqueSelector(ctx, ctx.config, "delete");
|
|
4282
4319
|
if (ctx.isList)
|
|
4283
4320
|
return wrapRelationOp(true, schema);
|
|
4284
4321
|
return z10.union([z10.literal(true), schema]).optional();
|
|
@@ -4293,7 +4330,7 @@ var handleSet = (ctx) => {
|
|
|
4293
4330
|
ctx.config,
|
|
4294
4331
|
`set config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
|
|
4295
4332
|
);
|
|
4296
|
-
const schema =
|
|
4333
|
+
const schema = buildRelatedUniqueSelector(ctx, cfg, "set");
|
|
4297
4334
|
return wrapRelationOp(true, schema);
|
|
4298
4335
|
};
|
|
4299
4336
|
var handleUpdate = (ctx) => {
|
|
@@ -4313,12 +4350,12 @@ var handleUpdate = (ctx) => {
|
|
|
4313
4350
|
"data",
|
|
4314
4351
|
`update on to-many "${ctx.model}.${ctx.fieldName}" requires "data" object`
|
|
4315
4352
|
);
|
|
4316
|
-
const whereSchema =
|
|
4317
|
-
const dataSchema2 =
|
|
4353
|
+
const whereSchema = buildRelatedUniqueSelector(ctx, where, "update.where");
|
|
4354
|
+
const dataSchema2 = buildRelatedNestedData(ctx, data, "update");
|
|
4318
4355
|
const updateSchema = z10.object({ where: whereSchema, data: dataSchema2 }).strict();
|
|
4319
4356
|
return wrapRelationOp(true, updateSchema);
|
|
4320
4357
|
}
|
|
4321
|
-
const dataSchema =
|
|
4358
|
+
const dataSchema = buildRelatedNestedData(ctx, cfg, "update");
|
|
4322
4359
|
return dataSchema.optional();
|
|
4323
4360
|
};
|
|
4324
4361
|
var handleUpsert = (ctx) => {
|
|
@@ -4343,15 +4380,15 @@ var handleUpsert = (ctx) => {
|
|
|
4343
4380
|
"update",
|
|
4344
4381
|
`upsert on "${ctx.model}.${ctx.fieldName}" requires "update" object`
|
|
4345
4382
|
);
|
|
4346
|
-
const createSchema =
|
|
4347
|
-
const updateSchema =
|
|
4383
|
+
const createSchema = buildRelatedNestedData(ctx, create, "create");
|
|
4384
|
+
const updateSchema = buildRelatedNestedData(ctx, update, "update");
|
|
4348
4385
|
if (ctx.isList) {
|
|
4349
4386
|
const where = requireNestedObject(
|
|
4350
4387
|
cfg,
|
|
4351
4388
|
"where",
|
|
4352
4389
|
`upsert on to-many "${ctx.model}.${ctx.fieldName}" requires "where" object`
|
|
4353
4390
|
);
|
|
4354
|
-
const whereSchema =
|
|
4391
|
+
const whereSchema = buildRelatedUniqueSelector(ctx, where, "upsert.where");
|
|
4355
4392
|
const upsertSchema2 = z10.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
|
|
4356
4393
|
return wrapRelationOp(true, upsertSchema2);
|
|
4357
4394
|
}
|
|
@@ -4362,7 +4399,7 @@ var handleUpsert = (ctx) => {
|
|
|
4362
4399
|
`upsert on to-one "${ctx.model}.${ctx.fieldName}" has invalid "where": must be a plain object of unique selectors`
|
|
4363
4400
|
);
|
|
4364
4401
|
}
|
|
4365
|
-
const whereSchema =
|
|
4402
|
+
const whereSchema = buildRelatedUniqueSelector(ctx, cfg.where, "upsert.where");
|
|
4366
4403
|
const upsertSchema2 = z10.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
|
|
4367
4404
|
return upsertSchema2.optional();
|
|
4368
4405
|
}
|
|
@@ -4406,7 +4443,7 @@ var handleUpdateMany = (ctx) => {
|
|
|
4406
4443
|
ctx.typeMap,
|
|
4407
4444
|
ctx.schemaBuilder
|
|
4408
4445
|
);
|
|
4409
|
-
const dataSchema =
|
|
4446
|
+
const dataSchema = buildRelatedNestedData(ctx, data, "update");
|
|
4410
4447
|
const umSchema = z10.object({ where: whereSchema, data: dataSchema }).strict();
|
|
4411
4448
|
return wrapRelationOp(true, umSchema);
|
|
4412
4449
|
};
|
|
@@ -4453,17 +4490,21 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
|
|
|
4453
4490
|
throw new ShapeError(
|
|
4454
4491
|
`Unknown related model "${relatedModelName}" for field "${model}.${fieldName}"`
|
|
4455
4492
|
);
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4493
|
+
assertAllowedKeys(
|
|
4494
|
+
config,
|
|
4495
|
+
KNOWN_RELATION_WRITE_OPS,
|
|
4496
|
+
(key) => `Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
|
|
4497
|
+
);
|
|
4498
|
+
const definedEntries = Object.entries(config).filter(
|
|
4499
|
+
([, opConfig]) => opConfig !== void 0
|
|
4500
|
+
);
|
|
4501
|
+
if (definedEntries.length === 0) {
|
|
4502
|
+
throw new ShapeError(
|
|
4503
|
+
`Empty relation write config on "${model}.${fieldName}". Define at least one operation: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
|
|
4504
|
+
);
|
|
4462
4505
|
}
|
|
4463
4506
|
const opSchemas = {};
|
|
4464
|
-
for (const [op, opConfig] of
|
|
4465
|
-
if (opConfig === void 0)
|
|
4466
|
-
continue;
|
|
4507
|
+
for (const [op, opConfig] of definedEntries) {
|
|
4467
4508
|
const handler = RELATION_OP_HANDLERS[op];
|
|
4468
4509
|
opSchemas[op] = handler({
|
|
4469
4510
|
model,
|
|
@@ -4480,7 +4521,7 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
|
|
|
4480
4521
|
}
|
|
4481
4522
|
return z10.object(opSchemas).strict();
|
|
4482
4523
|
}
|
|
4483
|
-
function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults) {
|
|
4524
|
+
function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults, allowRelationWrites) {
|
|
4484
4525
|
const modelFields = typeMap[model];
|
|
4485
4526
|
if (!modelFields)
|
|
4486
4527
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
@@ -4510,6 +4551,11 @@ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, s
|
|
|
4510
4551
|
continue;
|
|
4511
4552
|
}
|
|
4512
4553
|
if (fieldMeta.isRelation) {
|
|
4554
|
+
if (!allowRelationWrites) {
|
|
4555
|
+
throw new ShapeError(
|
|
4556
|
+
`Field "${fieldName}" on model "${model}" is a relation. Relation writes are not supported for this method.`
|
|
4557
|
+
);
|
|
4558
|
+
}
|
|
4513
4559
|
if (!isPlainObject(value)) {
|
|
4514
4560
|
throw new ShapeError(
|
|
4515
4561
|
`Relation field "${fieldName}" on model "${model}" requires a relation write config object`
|
|
@@ -4623,13 +4669,8 @@ function validateAndMergeData(bodyData, cached, method, modelName) {
|
|
|
4623
4669
|
try {
|
|
4624
4670
|
validated = cached.schema.parse(bodyData);
|
|
4625
4671
|
} catch (err) {
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
if (err && typeof err === "object" && "issues" in err) {
|
|
4629
|
-
const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
|
|
4630
|
-
throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
|
|
4631
|
-
}
|
|
4632
|
-
throw err;
|
|
4672
|
+
const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
|
|
4673
|
+
wrapParseError(err, context);
|
|
4633
4674
|
}
|
|
4634
4675
|
return { ...validated, ...deepClone(cached.forced) };
|
|
4635
4676
|
}
|
|
@@ -4784,6 +4825,8 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
4784
4825
|
"updateManyAndReturn"
|
|
4785
4826
|
]);
|
|
4786
4827
|
var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set(["createMany", "createManyAndReturn"]);
|
|
4828
|
+
var RELATION_WRITE_CREATE_METHODS = /* @__PURE__ */ new Set(["create"]);
|
|
4829
|
+
var RELATION_WRITE_UPDATE_METHODS = /* @__PURE__ */ new Set(["update"]);
|
|
4787
4830
|
var MAX_PROJECTION_WALK_DEPTH = 10;
|
|
4788
4831
|
function walkForClientContent(obj, predicate, depth) {
|
|
4789
4832
|
if (depth > MAX_PROJECTION_WALK_DEPTH)
|
|
@@ -4809,12 +4852,23 @@ function walkForClientContent(obj, predicate, depth) {
|
|
|
4809
4852
|
const nested = value;
|
|
4810
4853
|
if (nested.orderBy || nested.cursor || nested.take || nested.skip)
|
|
4811
4854
|
return true;
|
|
4812
|
-
if (nested.where && isPlainObject(nested.where) && hasClientControlledValues(
|
|
4855
|
+
if (nested.where && isPlainObject(nested.where) && hasClientControlledValues(
|
|
4856
|
+
nested.where,
|
|
4857
|
+
depth + 1
|
|
4858
|
+
)) {
|
|
4813
4859
|
return true;
|
|
4814
4860
|
}
|
|
4815
|
-
if (nested.include && walkForClientContent(
|
|
4861
|
+
if (nested.include && walkForClientContent(
|
|
4862
|
+
nested.include,
|
|
4863
|
+
predicate,
|
|
4864
|
+
depth + 1
|
|
4865
|
+
))
|
|
4816
4866
|
return true;
|
|
4817
|
-
if (nested.select && walkForClientContent(
|
|
4867
|
+
if (nested.select && walkForClientContent(
|
|
4868
|
+
nested.select,
|
|
4869
|
+
predicate,
|
|
4870
|
+
depth + 1
|
|
4871
|
+
))
|
|
4818
4872
|
return true;
|
|
4819
4873
|
}
|
|
4820
4874
|
return false;
|
|
@@ -4836,11 +4890,19 @@ function hasClientControlledValues(obj, depth = 0) {
|
|
|
4836
4890
|
function hasNestedClientControlledArgs(shape) {
|
|
4837
4891
|
const predicate = () => false;
|
|
4838
4892
|
if (shape.include) {
|
|
4839
|
-
if (walkForClientContent(
|
|
4893
|
+
if (walkForClientContent(
|
|
4894
|
+
shape.include,
|
|
4895
|
+
predicate,
|
|
4896
|
+
0
|
|
4897
|
+
))
|
|
4840
4898
|
return true;
|
|
4841
4899
|
}
|
|
4842
4900
|
if (shape.select) {
|
|
4843
|
-
if (walkForClientContent(
|
|
4901
|
+
if (walkForClientContent(
|
|
4902
|
+
shape.select,
|
|
4903
|
+
predicate,
|
|
4904
|
+
0
|
|
4905
|
+
))
|
|
4844
4906
|
return true;
|
|
4845
4907
|
}
|
|
4846
4908
|
return false;
|
|
@@ -4934,11 +4996,11 @@ function createModelGuardExtension(config) {
|
|
|
4934
4996
|
)
|
|
4935
4997
|
);
|
|
4936
4998
|
}
|
|
4937
|
-
function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
|
|
4999
|
+
function getDataSchema(mode, dataConfig, matchedKey, wasDynamic, allowRelationWrites) {
|
|
4938
5000
|
const skipCache = wasDynamic || hasDataRefines(dataConfig);
|
|
4939
5001
|
return memoize(
|
|
4940
5002
|
dataSchemaCache,
|
|
4941
|
-
`${mode}\0${matchedKey}`,
|
|
5003
|
+
`${mode}\0${matchedKey}\0${allowRelationWrites ? "r" : "n"}`,
|
|
4942
5004
|
skipCache,
|
|
4943
5005
|
() => buildDataSchema(
|
|
4944
5006
|
modelName,
|
|
@@ -4949,7 +5011,8 @@ function createModelGuardExtension(config) {
|
|
|
4949
5011
|
enumMap,
|
|
4950
5012
|
scalarBase,
|
|
4951
5013
|
schemaBuilder,
|
|
4952
|
-
zodDefaults
|
|
5014
|
+
zodDefaults,
|
|
5015
|
+
allowRelationWrites
|
|
4953
5016
|
)
|
|
4954
5017
|
);
|
|
4955
5018
|
}
|
|
@@ -5137,15 +5200,13 @@ function createModelGuardExtension(config) {
|
|
|
5137
5200
|
let result = {};
|
|
5138
5201
|
if (built.schema) {
|
|
5139
5202
|
if (bodyWhere !== void 0 && bodyWhere !== null) {
|
|
5140
|
-
if (!
|
|
5203
|
+
if (!isObjectLike(bodyWhere)) {
|
|
5141
5204
|
throw new ShapeError(
|
|
5142
|
-
`Invalid "where" on model "${modelName}": unique where must be
|
|
5205
|
+
`Invalid "where" on model "${modelName}": unique where must be an object`
|
|
5143
5206
|
);
|
|
5144
5207
|
}
|
|
5145
|
-
const
|
|
5146
|
-
|
|
5147
|
-
built.forced
|
|
5148
|
-
) : { ...bodyWhere };
|
|
5208
|
+
const bodyWhereObj = { ...bodyWhere };
|
|
5209
|
+
const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(bodyWhereObj, built.forced) : bodyWhereObj;
|
|
5149
5210
|
try {
|
|
5150
5211
|
result = built.schema.parse(sanitized);
|
|
5151
5212
|
} catch (err) {
|
|
@@ -5157,11 +5218,9 @@ function createModelGuardExtension(config) {
|
|
|
5157
5218
|
}
|
|
5158
5219
|
}
|
|
5159
5220
|
} else if (bodyWhere !== void 0 && bodyWhere !== null) {
|
|
5160
|
-
if (
|
|
5161
|
-
const
|
|
5162
|
-
|
|
5163
|
-
built.forced
|
|
5164
|
-
) : { ...bodyWhere };
|
|
5221
|
+
if (isObjectLike(bodyWhere)) {
|
|
5222
|
+
const bodyWhereObj = { ...bodyWhere };
|
|
5223
|
+
const sanitized = hasWhereForced(built.forced) ? stripUniqueWhereForcedInput(bodyWhereObj, built.forced) : bodyWhereObj;
|
|
5165
5224
|
if (Object.keys(sanitized).length > 0) {
|
|
5166
5225
|
throw new ShapeError(
|
|
5167
5226
|
`Unique where on model "${modelName}" contains only forced values. Client where input is not accepted.`
|
|
@@ -5169,7 +5228,7 @@ function createModelGuardExtension(config) {
|
|
|
5169
5228
|
}
|
|
5170
5229
|
} else {
|
|
5171
5230
|
throw new ShapeError(
|
|
5172
|
-
`Invalid "where" on model "${modelName}": unique where must be
|
|
5231
|
+
`Invalid "where" on model "${modelName}": unique where must be an object`
|
|
5173
5232
|
);
|
|
5174
5233
|
}
|
|
5175
5234
|
}
|
|
@@ -5207,6 +5266,39 @@ function createModelGuardExtension(config) {
|
|
|
5207
5266
|
const defaultProjection = buildDefaultProjectionBody(resolved.shape);
|
|
5208
5267
|
return { ...resolved.body, ...defaultProjection };
|
|
5209
5268
|
}
|
|
5269
|
+
function makeResolveMethod() {
|
|
5270
|
+
const WRITE_KEYS = ["data", "create", "update"];
|
|
5271
|
+
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
|
|
5272
|
+
return (body) => {
|
|
5273
|
+
const caller = resolveCaller();
|
|
5274
|
+
const resolved = resolveShape(input, body, contextFn, caller);
|
|
5275
|
+
for (const key of WRITE_KEYS) {
|
|
5276
|
+
if (hasOwn(resolved.shape, key)) {
|
|
5277
|
+
throw new ShapeError(
|
|
5278
|
+
`.resolve() is a read-only planning helper. Guard shape contains write key "${key}". Use the corresponding write method instead.`
|
|
5279
|
+
);
|
|
5280
|
+
}
|
|
5281
|
+
}
|
|
5282
|
+
for (const key of WRITE_KEYS) {
|
|
5283
|
+
if (hasOwn(resolved.body, key)) {
|
|
5284
|
+
throw new ShapeError(
|
|
5285
|
+
`.resolve() is a read-only planning helper. Request body contains write key "${key}".`
|
|
5286
|
+
);
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
const effectiveReadBody = buildEffectiveReadBody({
|
|
5290
|
+
shape: resolved.shape,
|
|
5291
|
+
body: resolved.body
|
|
5292
|
+
});
|
|
5293
|
+
return {
|
|
5294
|
+
shape: resolved.shape,
|
|
5295
|
+
body: resolved.body,
|
|
5296
|
+
effectiveReadBody,
|
|
5297
|
+
matchedKey: resolved.matchedKey,
|
|
5298
|
+
wasDynamic: resolved.wasDynamic
|
|
5299
|
+
};
|
|
5300
|
+
};
|
|
5301
|
+
}
|
|
5210
5302
|
function makeReadMethod(method) {
|
|
5211
5303
|
return (body) => {
|
|
5212
5304
|
const caller = resolveCaller();
|
|
@@ -5240,6 +5332,7 @@ function createModelGuardExtension(config) {
|
|
|
5240
5332
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5241
5333
|
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5242
5334
|
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5335
|
+
const allowRelationWrites = RELATION_WRITE_CREATE_METHODS.has(method);
|
|
5243
5336
|
return (body) => {
|
|
5244
5337
|
const caller = resolveCaller();
|
|
5245
5338
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
@@ -5265,7 +5358,8 @@ function createModelGuardExtension(config) {
|
|
|
5265
5358
|
"create",
|
|
5266
5359
|
resolved.shape.data,
|
|
5267
5360
|
resolved.matchedKey,
|
|
5268
|
-
resolved.wasDynamic
|
|
5361
|
+
resolved.wasDynamic,
|
|
5362
|
+
allowRelationWrites
|
|
5269
5363
|
);
|
|
5270
5364
|
let args;
|
|
5271
5365
|
if (method === "create") {
|
|
@@ -5313,6 +5407,7 @@ function createModelGuardExtension(config) {
|
|
|
5313
5407
|
const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
|
|
5314
5408
|
const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
|
|
5315
5409
|
const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
|
|
5410
|
+
const allowRelationWrites = RELATION_WRITE_UPDATE_METHODS.has(method);
|
|
5316
5411
|
return (body) => {
|
|
5317
5412
|
const caller = resolveCaller();
|
|
5318
5413
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
@@ -5335,7 +5430,8 @@ function createModelGuardExtension(config) {
|
|
|
5335
5430
|
"update",
|
|
5336
5431
|
resolved.shape.data,
|
|
5337
5432
|
resolved.matchedKey,
|
|
5338
|
-
resolved.wasDynamic
|
|
5433
|
+
resolved.wasDynamic,
|
|
5434
|
+
allowRelationWrites
|
|
5339
5435
|
);
|
|
5340
5436
|
const data = validateAndMergeData(
|
|
5341
5437
|
resolved.body.data,
|
|
@@ -5485,12 +5581,7 @@ function createModelGuardExtension(config) {
|
|
|
5485
5581
|
"upsert",
|
|
5486
5582
|
"shape"
|
|
5487
5583
|
);
|
|
5488
|
-
validateAllowedKeys(
|
|
5489
|
-
resolved.body,
|
|
5490
|
-
allowedBodyKeys,
|
|
5491
|
-
"upsert",
|
|
5492
|
-
"body"
|
|
5493
|
-
);
|
|
5584
|
+
validateAllowedKeys(resolved.body, allowedBodyKeys, "upsert", "body");
|
|
5494
5585
|
validateUniqueWhereShapeConfig(
|
|
5495
5586
|
modelName,
|
|
5496
5587
|
resolved.shape.where,
|
|
@@ -5508,7 +5599,8 @@ function createModelGuardExtension(config) {
|
|
|
5508
5599
|
"create",
|
|
5509
5600
|
resolved.shape.create,
|
|
5510
5601
|
`upsert:create\0${resolved.matchedKey}`,
|
|
5511
|
-
resolved.wasDynamic
|
|
5602
|
+
resolved.wasDynamic,
|
|
5603
|
+
true
|
|
5512
5604
|
);
|
|
5513
5605
|
const createData = validateAndMergeData(
|
|
5514
5606
|
resolved.body.create,
|
|
@@ -5520,7 +5612,8 @@ function createModelGuardExtension(config) {
|
|
|
5520
5612
|
"update",
|
|
5521
5613
|
resolved.shape.update,
|
|
5522
5614
|
`upsert:update\0${resolved.matchedKey}`,
|
|
5523
|
-
resolved.wasDynamic
|
|
5615
|
+
resolved.wasDynamic,
|
|
5616
|
+
true
|
|
5524
5617
|
);
|
|
5525
5618
|
const updateData = validateAndMergeData(
|
|
5526
5619
|
resolved.body.update,
|
|
@@ -5553,6 +5646,7 @@ function createModelGuardExtension(config) {
|
|
|
5553
5646
|
};
|
|
5554
5647
|
}
|
|
5555
5648
|
return {
|
|
5649
|
+
resolve: makeResolveMethod(),
|
|
5556
5650
|
findMany: makeReadMethod("findMany"),
|
|
5557
5651
|
findFirst: makeReadMethod("findFirst"),
|
|
5558
5652
|
findFirstOrThrow: makeReadMethod("findFirstOrThrow"),
|