prisma-guard 1.3.1 → 1.4.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/dist/runtime/index.cjs +535 -103
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +4 -3
- package/dist/runtime/index.d.ts +4 -3
- package/dist/runtime/index.js +535 -103
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
package/dist/runtime/index.js
CHANGED
|
@@ -704,7 +704,24 @@ function mergeUniqueWhereForced(where, forced) {
|
|
|
704
704
|
return result;
|
|
705
705
|
}
|
|
706
706
|
function applyBuiltShape(built, body, isUniqueMethod) {
|
|
707
|
-
|
|
707
|
+
let parseable = body;
|
|
708
|
+
if (built.forcedOnlyWhereKeys.size > 0 && isPlainObject(body)) {
|
|
709
|
+
const bodyObj = body;
|
|
710
|
+
if (isPlainObject(bodyObj.where)) {
|
|
711
|
+
const where = { ...bodyObj.where };
|
|
712
|
+
let stripped = false;
|
|
713
|
+
for (const key of built.forcedOnlyWhereKeys) {
|
|
714
|
+
if (key in where) {
|
|
715
|
+
delete where[key];
|
|
716
|
+
stripped = true;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (stripped) {
|
|
720
|
+
parseable = { ...bodyObj, where };
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
const validated = built.zodSchema.parse(parseable);
|
|
708
725
|
if (hasWhereForced(built.forcedWhere)) {
|
|
709
726
|
validated.where = isUniqueMethod ? mergeUniqueWhereForced(
|
|
710
727
|
validated.where,
|
|
@@ -928,7 +945,12 @@ function validateUniqueEquality(model, where, method, uniqueMap, typeMap) {
|
|
|
928
945
|
|
|
929
946
|
// src/runtime/query-builder-where.ts
|
|
930
947
|
var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
|
|
931
|
-
var STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
948
|
+
var STRING_MODE_OPS = /* @__PURE__ */ new Set([
|
|
949
|
+
"contains",
|
|
950
|
+
"startsWith",
|
|
951
|
+
"endsWith",
|
|
952
|
+
"equals"
|
|
953
|
+
]);
|
|
932
954
|
var MAX_WHERE_DEPTH = 10;
|
|
933
955
|
function safeStringify(v) {
|
|
934
956
|
if (typeof v === "bigint")
|
|
@@ -998,9 +1020,7 @@ function mergeScalarConditions(target, source) {
|
|
|
998
1020
|
continue;
|
|
999
1021
|
}
|
|
1000
1022
|
if (!forcedValuesEqual(existing, ops)) {
|
|
1001
|
-
throw new ShapeError(
|
|
1002
|
-
`Conflicting forced where values for "${field}"`
|
|
1003
|
-
);
|
|
1023
|
+
throw new ShapeError(`Conflicting forced where values for "${field}"`);
|
|
1004
1024
|
}
|
|
1005
1025
|
}
|
|
1006
1026
|
}
|
|
@@ -1014,8 +1034,14 @@ function mergeRelationForcedMaps(target, source) {
|
|
|
1014
1034
|
if (!target[relName][op]) {
|
|
1015
1035
|
target[relName][op] = forced;
|
|
1016
1036
|
} else {
|
|
1017
|
-
mergeScalarConditions(
|
|
1018
|
-
|
|
1037
|
+
mergeScalarConditions(
|
|
1038
|
+
target[relName][op].conditions,
|
|
1039
|
+
forced.conditions
|
|
1040
|
+
);
|
|
1041
|
+
mergeRelationForcedMaps(
|
|
1042
|
+
target[relName][op].relations,
|
|
1043
|
+
forced.relations
|
|
1044
|
+
);
|
|
1019
1045
|
}
|
|
1020
1046
|
}
|
|
1021
1047
|
}
|
|
@@ -1067,20 +1093,38 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1067
1093
|
`${fieldMeta.type} field "${key}" cannot be used in where filters`
|
|
1068
1094
|
);
|
|
1069
1095
|
}
|
|
1070
|
-
processScalarField(
|
|
1096
|
+
processScalarField(
|
|
1097
|
+
key,
|
|
1098
|
+
value,
|
|
1099
|
+
model,
|
|
1100
|
+
fieldMeta,
|
|
1101
|
+
fieldSchemas,
|
|
1102
|
+
scalarConditions
|
|
1103
|
+
);
|
|
1071
1104
|
}
|
|
1072
1105
|
const schema = Object.keys(fieldSchemas).length > 0 ? z4.object(fieldSchemas).strict().optional() : null;
|
|
1106
|
+
const forcedOnlyKeys = /* @__PURE__ */ new Set();
|
|
1107
|
+
for (const key of Object.keys(whereConfig)) {
|
|
1108
|
+
if (COMBINATOR_KEYS.has(key))
|
|
1109
|
+
continue;
|
|
1110
|
+
if (!(key in fieldSchemas)) {
|
|
1111
|
+
forcedOnlyKeys.add(key);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1073
1114
|
return {
|
|
1074
1115
|
schema,
|
|
1075
1116
|
forced: {
|
|
1076
1117
|
conditions: scalarConditions,
|
|
1077
1118
|
relations: relationForced
|
|
1078
|
-
}
|
|
1119
|
+
},
|
|
1120
|
+
forcedOnlyKeys
|
|
1079
1121
|
};
|
|
1080
1122
|
}
|
|
1081
1123
|
function processCombinator(key, value, model, fieldSchemas, parentConditions, parentRelations, depth) {
|
|
1082
1124
|
if (!isPlainObject(value)) {
|
|
1083
|
-
throw new ShapeError(
|
|
1125
|
+
throw new ShapeError(
|
|
1126
|
+
`"${key}" in where shape must be an object defining allowed fields`
|
|
1127
|
+
);
|
|
1084
1128
|
}
|
|
1085
1129
|
const result = buildWhereSchema(model, value, depth + 1);
|
|
1086
1130
|
if (!result.schema && !hasWhereForced(result.forced)) {
|
|
@@ -1121,7 +1165,9 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1121
1165
|
}
|
|
1122
1166
|
function processRelationFilter(key, value, fieldMeta, model, fieldSchemas, parentRelations, depth) {
|
|
1123
1167
|
if (!isPlainObject(value)) {
|
|
1124
|
-
throw new ShapeError(
|
|
1168
|
+
throw new ShapeError(
|
|
1169
|
+
`Relation filter for "${key}" must be an object with operators (some, every, none, is, isNot)`
|
|
1170
|
+
);
|
|
1125
1171
|
}
|
|
1126
1172
|
const allowedOps = fieldMeta.isList ? TO_MANY_RELATION_OPS : TO_ONE_RELATION_OPS;
|
|
1127
1173
|
if (Object.keys(value).length === 0) {
|
|
@@ -1154,7 +1200,9 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1154
1200
|
if (!hasWhereForced(nested.forced)) {
|
|
1155
1201
|
opSchemas[op] = nested.schema.refine(
|
|
1156
1202
|
(v) => v === void 0 || Object.keys(v).length > 0,
|
|
1157
|
-
{
|
|
1203
|
+
{
|
|
1204
|
+
message: `Relation filter "${key}.${op}" requires at least one condition`
|
|
1205
|
+
}
|
|
1158
1206
|
);
|
|
1159
1207
|
} else {
|
|
1160
1208
|
opSchemas[op] = nested.schema;
|
|
@@ -1175,7 +1223,9 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1175
1223
|
const opObjSchema = z4.object(opSchemas).strict();
|
|
1176
1224
|
if (Object.keys(opForced).length === 0) {
|
|
1177
1225
|
fieldSchemas[key] = opObjSchema.refine(
|
|
1178
|
-
(v) => clientOpKeys.some(
|
|
1226
|
+
(v) => clientOpKeys.some(
|
|
1227
|
+
(k) => v[k] !== void 0
|
|
1228
|
+
),
|
|
1179
1229
|
{ message: `At least one relation operator required for "${key}"` }
|
|
1180
1230
|
).optional();
|
|
1181
1231
|
} else {
|
|
@@ -1199,7 +1249,12 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1199
1249
|
const clientOpKeys = [];
|
|
1200
1250
|
for (const [op, opValue] of Object.entries(operators)) {
|
|
1201
1251
|
if (opValue === true) {
|
|
1202
|
-
opSchemas[op] = createOperatorSchema(
|
|
1252
|
+
opSchemas[op] = createOperatorSchema(
|
|
1253
|
+
fieldMeta,
|
|
1254
|
+
op,
|
|
1255
|
+
enumMap,
|
|
1256
|
+
scalarBase
|
|
1257
|
+
).optional();
|
|
1203
1258
|
hasClientOps = true;
|
|
1204
1259
|
clientOpKeys.push(op);
|
|
1205
1260
|
if (fieldMeta.type === "String" && !fieldMeta.isList && STRING_MODE_OPS.has(op)) {
|
|
@@ -1207,7 +1262,12 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1207
1262
|
}
|
|
1208
1263
|
} else {
|
|
1209
1264
|
const actualOpValue = isForcedValue(opValue) ? opValue.value : opValue;
|
|
1210
|
-
const opSchema = createOperatorSchema(
|
|
1265
|
+
const opSchema = createOperatorSchema(
|
|
1266
|
+
fieldMeta,
|
|
1267
|
+
op,
|
|
1268
|
+
enumMap,
|
|
1269
|
+
scalarBase
|
|
1270
|
+
);
|
|
1211
1271
|
let parsed;
|
|
1212
1272
|
try {
|
|
1213
1273
|
parsed = opSchema.parse(actualOpValue);
|
|
@@ -1230,8 +1290,12 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
|
|
|
1230
1290
|
if (hasClientOps) {
|
|
1231
1291
|
const opObj = z4.object(opSchemas).strict();
|
|
1232
1292
|
fieldSchemas[fieldName] = opObj.refine(
|
|
1233
|
-
(v) => clientOpKeys.some(
|
|
1234
|
-
|
|
1293
|
+
(v) => clientOpKeys.some(
|
|
1294
|
+
(k) => v[k] !== void 0
|
|
1295
|
+
),
|
|
1296
|
+
{
|
|
1297
|
+
message: `At least one operator required for where field "${fieldName}"`
|
|
1298
|
+
}
|
|
1235
1299
|
).optional();
|
|
1236
1300
|
}
|
|
1237
1301
|
if (Object.keys(fieldForced).length > 0) {
|
|
@@ -1254,23 +1318,80 @@ function requireConfigTrue(config, context) {
|
|
|
1254
1318
|
}
|
|
1255
1319
|
}
|
|
1256
1320
|
function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
1321
|
+
const sortEnum = z5.enum(["asc", "desc"]);
|
|
1322
|
+
const nullsEnum = z5.enum(["first", "last"]);
|
|
1323
|
+
const sortWithNulls = z5.object({ sort: sortEnum, nulls: nullsEnum.optional() }).strict();
|
|
1324
|
+
const scalarOrderSchema = z5.union([sortEnum, sortWithNulls]);
|
|
1325
|
+
function validateScalarOrderByField(fieldName, model, modelFields) {
|
|
1326
|
+
const fieldMeta = modelFields[fieldName];
|
|
1327
|
+
if (!fieldMeta)
|
|
1328
|
+
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
1329
|
+
if (fieldMeta.isRelation)
|
|
1330
|
+
throw new ShapeError(`Relation field "${fieldName}" in orderBy requires a nested config object, not true`);
|
|
1331
|
+
if (fieldMeta.type === "Json")
|
|
1332
|
+
throw new ShapeError(`Json field "${fieldName}" cannot be used in orderBy`);
|
|
1333
|
+
if (fieldMeta.isList)
|
|
1334
|
+
throw new ShapeError(`List field "${fieldName}" cannot be used in orderBy`);
|
|
1335
|
+
}
|
|
1257
1336
|
function buildOrderBySchema(model, orderByConfig) {
|
|
1258
1337
|
const modelFields = typeMap[model];
|
|
1259
1338
|
if (!modelFields)
|
|
1260
1339
|
throw new ShapeError(`Unknown model: ${model}`);
|
|
1261
|
-
requireConfigTrue(orderByConfig, `orderBy on model "${model}"`);
|
|
1262
1340
|
const fieldSchemas = {};
|
|
1263
|
-
for (const fieldName of Object.
|
|
1341
|
+
for (const [fieldName, config] of Object.entries(orderByConfig)) {
|
|
1264
1342
|
const fieldMeta = modelFields[fieldName];
|
|
1265
1343
|
if (!fieldMeta)
|
|
1266
1344
|
throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
|
|
1267
|
-
if (
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1345
|
+
if (config === true) {
|
|
1346
|
+
validateScalarOrderByField(fieldName, model, modelFields);
|
|
1347
|
+
fieldSchemas[fieldName] = scalarOrderSchema.optional();
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
if (typeof config !== "object" || config === null) {
|
|
1351
|
+
throw new ShapeError(`Invalid orderBy config for "${fieldName}" on model "${model}": expected true or a nested config object`);
|
|
1352
|
+
}
|
|
1353
|
+
if (!fieldMeta.isRelation) {
|
|
1354
|
+
throw new ShapeError(`Scalar field "${fieldName}" in orderBy does not accept nested config`);
|
|
1355
|
+
}
|
|
1356
|
+
if (Object.keys(config).length === 0) {
|
|
1357
|
+
throw new ShapeError(`Empty orderBy config for relation "${fieldName}" on model "${model}". Define at least one nested field.`);
|
|
1358
|
+
}
|
|
1359
|
+
if (fieldMeta.isList) {
|
|
1360
|
+
const relKeys = Object.keys(config);
|
|
1361
|
+
if (relKeys.length !== 1 || relKeys[0] !== "_count") {
|
|
1362
|
+
throw new ShapeError(`To-many relation "${fieldName}" in orderBy only supports { _count: true }`);
|
|
1363
|
+
}
|
|
1364
|
+
if (config._count !== true) {
|
|
1365
|
+
throw new ShapeError(`_count in orderBy for "${fieldName}" must be true`);
|
|
1366
|
+
}
|
|
1367
|
+
fieldSchemas[fieldName] = z5.object({ _count: sortEnum }).strict().optional();
|
|
1368
|
+
continue;
|
|
1369
|
+
}
|
|
1370
|
+
const relatedModel = fieldMeta.type;
|
|
1371
|
+
const relatedFields = typeMap[relatedModel];
|
|
1372
|
+
if (!relatedFields)
|
|
1373
|
+
throw new ShapeError(`Related model "${relatedModel}" not found in type map`);
|
|
1374
|
+
const nestedSchemas = {};
|
|
1375
|
+
for (const [nestedField, nestedVal] of Object.entries(config)) {
|
|
1376
|
+
if (nestedVal !== true) {
|
|
1377
|
+
throw new ShapeError(`Nested orderBy field "${nestedField}" on relation "${fieldName}" must be true`);
|
|
1378
|
+
}
|
|
1379
|
+
const nestedMeta = relatedFields[nestedField];
|
|
1380
|
+
if (!nestedMeta)
|
|
1381
|
+
throw new ShapeError(`Unknown field "${nestedField}" on model "${relatedModel}" in orderBy`);
|
|
1382
|
+
if (nestedMeta.isRelation)
|
|
1383
|
+
throw new ShapeError(`Nested relation "${nestedField}" in orderBy on "${fieldName}" is not supported`);
|
|
1384
|
+
if (nestedMeta.type === "Json")
|
|
1385
|
+
throw new ShapeError(`Json field "${nestedField}" cannot be used in orderBy`);
|
|
1386
|
+
if (nestedMeta.isList)
|
|
1387
|
+
throw new ShapeError(`List field "${nestedField}" cannot be used in orderBy`);
|
|
1388
|
+
nestedSchemas[nestedField] = scalarOrderSchema.optional();
|
|
1389
|
+
}
|
|
1390
|
+
const nestedKeys = Object.keys(nestedSchemas);
|
|
1391
|
+
fieldSchemas[fieldName] = z5.object(nestedSchemas).strict().refine(
|
|
1392
|
+
(v) => nestedKeys.some((k) => v[k] !== void 0),
|
|
1393
|
+
{ message: `orderBy for relation "${fieldName}" must specify at least one field` }
|
|
1394
|
+
).optional();
|
|
1274
1395
|
}
|
|
1275
1396
|
const fieldKeys = Object.keys(fieldSchemas);
|
|
1276
1397
|
const singleSchema = z5.object(fieldSchemas).strict().refine(
|
|
@@ -1840,19 +1961,77 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
|
|
|
1840
1961
|
|
|
1841
1962
|
// src/runtime/query-builder.ts
|
|
1842
1963
|
var METHOD_ALLOWED_ARGS = {
|
|
1843
|
-
findMany: /* @__PURE__ */ new Set([
|
|
1844
|
-
|
|
1845
|
-
|
|
1964
|
+
findMany: /* @__PURE__ */ new Set([
|
|
1965
|
+
"where",
|
|
1966
|
+
"include",
|
|
1967
|
+
"select",
|
|
1968
|
+
"orderBy",
|
|
1969
|
+
"cursor",
|
|
1970
|
+
"take",
|
|
1971
|
+
"skip",
|
|
1972
|
+
"distinct"
|
|
1973
|
+
]),
|
|
1974
|
+
findFirst: /* @__PURE__ */ new Set([
|
|
1975
|
+
"where",
|
|
1976
|
+
"include",
|
|
1977
|
+
"select",
|
|
1978
|
+
"orderBy",
|
|
1979
|
+
"cursor",
|
|
1980
|
+
"take",
|
|
1981
|
+
"skip",
|
|
1982
|
+
"distinct"
|
|
1983
|
+
]),
|
|
1984
|
+
findFirstOrThrow: /* @__PURE__ */ new Set([
|
|
1985
|
+
"where",
|
|
1986
|
+
"include",
|
|
1987
|
+
"select",
|
|
1988
|
+
"orderBy",
|
|
1989
|
+
"cursor",
|
|
1990
|
+
"take",
|
|
1991
|
+
"skip",
|
|
1992
|
+
"distinct"
|
|
1993
|
+
]),
|
|
1846
1994
|
findUnique: /* @__PURE__ */ new Set(["where", "include", "select"]),
|
|
1847
1995
|
findUniqueOrThrow: /* @__PURE__ */ new Set(["where", "include", "select"]),
|
|
1848
1996
|
count: /* @__PURE__ */ new Set(["where", "select", "cursor", "orderBy", "skip", "take"]),
|
|
1849
|
-
aggregate: /* @__PURE__ */ new Set([
|
|
1850
|
-
|
|
1997
|
+
aggregate: /* @__PURE__ */ new Set([
|
|
1998
|
+
"where",
|
|
1999
|
+
"orderBy",
|
|
2000
|
+
"cursor",
|
|
2001
|
+
"take",
|
|
2002
|
+
"skip",
|
|
2003
|
+
"_count",
|
|
2004
|
+
"_avg",
|
|
2005
|
+
"_sum",
|
|
2006
|
+
"_min",
|
|
2007
|
+
"_max"
|
|
2008
|
+
]),
|
|
2009
|
+
groupBy: /* @__PURE__ */ new Set([
|
|
2010
|
+
"where",
|
|
2011
|
+
"by",
|
|
2012
|
+
"having",
|
|
2013
|
+
"_count",
|
|
2014
|
+
"_avg",
|
|
2015
|
+
"_sum",
|
|
2016
|
+
"_min",
|
|
2017
|
+
"_max",
|
|
2018
|
+
"orderBy",
|
|
2019
|
+
"take",
|
|
2020
|
+
"skip"
|
|
2021
|
+
])
|
|
1851
2022
|
};
|
|
1852
|
-
var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
|
|
2023
|
+
var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
|
|
2024
|
+
"findUnique",
|
|
2025
|
+
"findUniqueOrThrow"
|
|
2026
|
+
]);
|
|
1853
2027
|
function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
1854
2028
|
const whereBuilder = createWhereBuilder(typeMap, enumMap, scalarBase);
|
|
1855
|
-
const argsBuilder = createArgsBuilder(
|
|
2029
|
+
const argsBuilder = createArgsBuilder(
|
|
2030
|
+
typeMap,
|
|
2031
|
+
enumMap,
|
|
2032
|
+
uniqueMap,
|
|
2033
|
+
scalarBase
|
|
2034
|
+
);
|
|
1856
2035
|
const projectionBuilder = createProjectionBuilder(typeMap, enumMap, {
|
|
1857
2036
|
buildWhereSchema: whereBuilder.buildWhereSchema,
|
|
1858
2037
|
buildOrderBySchema: argsBuilder.buildOrderBySchema,
|
|
@@ -1877,7 +2056,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1877
2056
|
throw new ShapeError(`${method} shape must define "where"`);
|
|
1878
2057
|
}
|
|
1879
2058
|
if (shape.include && shape.select) {
|
|
1880
|
-
throw new ShapeError(
|
|
2059
|
+
throw new ShapeError(
|
|
2060
|
+
'Shape config cannot define both "include" and "select".'
|
|
2061
|
+
);
|
|
1881
2062
|
}
|
|
1882
2063
|
if (method === "groupBy" && !shape.by)
|
|
1883
2064
|
throw new ShapeError('groupBy shape must define "by"');
|
|
@@ -1893,7 +2074,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1893
2074
|
const bySet = new Set(shape.by);
|
|
1894
2075
|
for (const fieldName of Object.keys(shape.orderBy)) {
|
|
1895
2076
|
if (!bySet.has(fieldName)) {
|
|
1896
|
-
throw new ShapeError(
|
|
2077
|
+
throw new ShapeError(
|
|
2078
|
+
`orderBy field "${fieldName}" must be included in "by" for groupBy`
|
|
2079
|
+
);
|
|
1897
2080
|
}
|
|
1898
2081
|
}
|
|
1899
2082
|
}
|
|
@@ -1901,7 +2084,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1901
2084
|
const bySet = new Set(shape.by);
|
|
1902
2085
|
for (const fieldName of Object.keys(shape.having)) {
|
|
1903
2086
|
if (!bySet.has(fieldName)) {
|
|
1904
|
-
throw new ShapeError(
|
|
2087
|
+
throw new ShapeError(
|
|
2088
|
+
`having field "${fieldName}" must be included in "by" for groupBy`
|
|
2089
|
+
);
|
|
1905
2090
|
}
|
|
1906
2091
|
}
|
|
1907
2092
|
}
|
|
@@ -1918,7 +2103,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1918
2103
|
requireContext(ctx, "shape function");
|
|
1919
2104
|
const result = shapeOrFn(ctx);
|
|
1920
2105
|
if (!isPlainObject(result)) {
|
|
1921
|
-
throw new ShapeError(
|
|
2106
|
+
throw new ShapeError(
|
|
2107
|
+
"Dynamic shape function must return a plain object"
|
|
2108
|
+
);
|
|
1922
2109
|
}
|
|
1923
2110
|
return result;
|
|
1924
2111
|
}
|
|
@@ -1929,15 +2116,20 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1929
2116
|
validateUniqueWhere(model, method, shape);
|
|
1930
2117
|
const schemaFields = {};
|
|
1931
2118
|
let forcedWhere = EMPTY_WHERE_FORCED;
|
|
2119
|
+
let forcedOnlyWhereKeys = /* @__PURE__ */ new Set();
|
|
1932
2120
|
let forcedIncludeTree = {};
|
|
1933
2121
|
let forcedSelectTree = {};
|
|
1934
2122
|
let forcedIncludeCountWhere = {};
|
|
1935
2123
|
let forcedSelectCountWhere = {};
|
|
1936
2124
|
if (shape.where) {
|
|
1937
|
-
const { schema, forced } = whereBuilder.buildWhereSchema(
|
|
2125
|
+
const { schema, forced, forcedOnlyKeys } = whereBuilder.buildWhereSchema(
|
|
2126
|
+
model,
|
|
2127
|
+
shape.where
|
|
2128
|
+
);
|
|
1938
2129
|
if (schema)
|
|
1939
2130
|
schemaFields["where"] = schema;
|
|
1940
2131
|
forcedWhere = forced;
|
|
2132
|
+
forcedOnlyWhereKeys = forcedOnlyKeys;
|
|
1941
2133
|
}
|
|
1942
2134
|
if (shape.include) {
|
|
1943
2135
|
const result = projectionBuilder.buildIncludeSchema(model, shape.include);
|
|
@@ -1947,7 +2139,10 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1947
2139
|
}
|
|
1948
2140
|
if (shape.select) {
|
|
1949
2141
|
if (method === "count") {
|
|
1950
|
-
schemaFields["select"] = argsBuilder.buildCountSelectSchema(
|
|
2142
|
+
schemaFields["select"] = argsBuilder.buildCountSelectSchema(
|
|
2143
|
+
model,
|
|
2144
|
+
shape.select
|
|
2145
|
+
);
|
|
1951
2146
|
} else {
|
|
1952
2147
|
const result = projectionBuilder.buildSelectSchema(model, shape.select);
|
|
1953
2148
|
schemaFields["select"] = result.schema;
|
|
@@ -1956,9 +2151,15 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1956
2151
|
}
|
|
1957
2152
|
}
|
|
1958
2153
|
if (shape.orderBy)
|
|
1959
|
-
schemaFields["orderBy"] = argsBuilder.buildOrderBySchema(
|
|
2154
|
+
schemaFields["orderBy"] = argsBuilder.buildOrderBySchema(
|
|
2155
|
+
model,
|
|
2156
|
+
shape.orderBy
|
|
2157
|
+
);
|
|
1960
2158
|
if (shape.cursor)
|
|
1961
|
-
schemaFields["cursor"] = argsBuilder.buildCursorSchema(
|
|
2159
|
+
schemaFields["cursor"] = argsBuilder.buildCursorSchema(
|
|
2160
|
+
model,
|
|
2161
|
+
shape.cursor
|
|
2162
|
+
);
|
|
1962
2163
|
if (shape.take)
|
|
1963
2164
|
schemaFields["take"] = argsBuilder.buildTakeSchema(shape.take);
|
|
1964
2165
|
if (shape.skip !== void 0) {
|
|
@@ -1968,24 +2169,51 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
1968
2169
|
schemaFields["skip"] = z7.number().int().min(0).optional();
|
|
1969
2170
|
}
|
|
1970
2171
|
if (shape.distinct)
|
|
1971
|
-
schemaFields["distinct"] = argsBuilder.buildDistinctSchema(
|
|
2172
|
+
schemaFields["distinct"] = argsBuilder.buildDistinctSchema(
|
|
2173
|
+
model,
|
|
2174
|
+
shape.distinct
|
|
2175
|
+
);
|
|
1972
2176
|
if (shape._count)
|
|
1973
|
-
schemaFields["_count"] = argsBuilder.buildCountFieldSchema(
|
|
2177
|
+
schemaFields["_count"] = argsBuilder.buildCountFieldSchema(
|
|
2178
|
+
model,
|
|
2179
|
+
shape._count,
|
|
2180
|
+
"_count"
|
|
2181
|
+
);
|
|
1974
2182
|
if (shape._avg)
|
|
1975
|
-
schemaFields["_avg"] = argsBuilder.buildAggregateFieldSchema(
|
|
2183
|
+
schemaFields["_avg"] = argsBuilder.buildAggregateFieldSchema(
|
|
2184
|
+
model,
|
|
2185
|
+
"_avg",
|
|
2186
|
+
shape._avg
|
|
2187
|
+
);
|
|
1976
2188
|
if (shape._sum)
|
|
1977
|
-
schemaFields["_sum"] = argsBuilder.buildAggregateFieldSchema(
|
|
2189
|
+
schemaFields["_sum"] = argsBuilder.buildAggregateFieldSchema(
|
|
2190
|
+
model,
|
|
2191
|
+
"_sum",
|
|
2192
|
+
shape._sum
|
|
2193
|
+
);
|
|
1978
2194
|
if (shape._min)
|
|
1979
|
-
schemaFields["_min"] = argsBuilder.buildAggregateFieldSchema(
|
|
2195
|
+
schemaFields["_min"] = argsBuilder.buildAggregateFieldSchema(
|
|
2196
|
+
model,
|
|
2197
|
+
"_min",
|
|
2198
|
+
shape._min
|
|
2199
|
+
);
|
|
1980
2200
|
if (shape._max)
|
|
1981
|
-
schemaFields["_max"] = argsBuilder.buildAggregateFieldSchema(
|
|
2201
|
+
schemaFields["_max"] = argsBuilder.buildAggregateFieldSchema(
|
|
2202
|
+
model,
|
|
2203
|
+
"_max",
|
|
2204
|
+
shape._max
|
|
2205
|
+
);
|
|
1982
2206
|
if (shape.by)
|
|
1983
2207
|
schemaFields["by"] = argsBuilder.buildBySchema(model, shape.by);
|
|
1984
2208
|
if (shape.having)
|
|
1985
|
-
schemaFields["having"] = argsBuilder.buildHavingSchema(
|
|
2209
|
+
schemaFields["having"] = argsBuilder.buildHavingSchema(
|
|
2210
|
+
model,
|
|
2211
|
+
shape.having
|
|
2212
|
+
);
|
|
1986
2213
|
return {
|
|
1987
2214
|
zodSchema: z7.object(schemaFields).strict(),
|
|
1988
2215
|
forcedWhere,
|
|
2216
|
+
forcedOnlyWhereKeys,
|
|
1989
2217
|
forcedIncludeTree,
|
|
1990
2218
|
forcedSelectTree,
|
|
1991
2219
|
forcedIncludeCountWhere,
|
|
@@ -2002,17 +2230,27 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2002
2230
|
const isSingle = typeof config === "function" || isShapeConfig(config);
|
|
2003
2231
|
const builtCache = /* @__PURE__ */ new Map();
|
|
2004
2232
|
if (isSingle && typeof config !== "function") {
|
|
2005
|
-
builtCache.set(
|
|
2233
|
+
builtCache.set(
|
|
2234
|
+
"_default",
|
|
2235
|
+
buildShapeZodSchema(model, method, config)
|
|
2236
|
+
);
|
|
2006
2237
|
}
|
|
2007
2238
|
if (!isSingle) {
|
|
2008
2239
|
for (const key of Object.keys(config)) {
|
|
2009
2240
|
if (SHAPE_CONFIG_KEYS.has(key)) {
|
|
2010
|
-
throw new ShapeError(
|
|
2241
|
+
throw new ShapeError(
|
|
2242
|
+
`Caller key "${key}" collides with reserved shape config key. Rename the caller path.`
|
|
2243
|
+
);
|
|
2011
2244
|
}
|
|
2012
2245
|
}
|
|
2013
|
-
for (const [key, shapeOrFn] of Object.entries(
|
|
2246
|
+
for (const [key, shapeOrFn] of Object.entries(
|
|
2247
|
+
config
|
|
2248
|
+
)) {
|
|
2014
2249
|
if (typeof shapeOrFn !== "function") {
|
|
2015
|
-
builtCache.set(
|
|
2250
|
+
builtCache.set(
|
|
2251
|
+
key,
|
|
2252
|
+
buildShapeZodSchema(model, method, shapeOrFn)
|
|
2253
|
+
);
|
|
2016
2254
|
}
|
|
2017
2255
|
}
|
|
2018
2256
|
}
|
|
@@ -2041,14 +2279,21 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
2041
2279
|
}
|
|
2042
2280
|
const caller = opts?.caller;
|
|
2043
2281
|
if (typeof caller !== "string") {
|
|
2044
|
-
const allowed = Object.keys(
|
|
2282
|
+
const allowed = Object.keys(
|
|
2283
|
+
config
|
|
2284
|
+
);
|
|
2045
2285
|
throw new CallerError(
|
|
2046
2286
|
`Missing caller. This query uses named shape routing with keys: ${allowed.map((k) => `"${k}"`).join(", ")}. Provide caller via opts.caller.`
|
|
2047
2287
|
);
|
|
2048
2288
|
}
|
|
2049
|
-
const matched = matchCaller(
|
|
2289
|
+
const matched = matchCaller(
|
|
2290
|
+
config,
|
|
2291
|
+
caller
|
|
2292
|
+
);
|
|
2050
2293
|
if (!matched) {
|
|
2051
|
-
const allowed = Object.keys(
|
|
2294
|
+
const allowed = Object.keys(
|
|
2295
|
+
config
|
|
2296
|
+
);
|
|
2052
2297
|
throw new CallerError(
|
|
2053
2298
|
`Unknown caller: "${caller}". Allowed: ${allowed.map((k) => `"${k}"`).join(", ")}`
|
|
2054
2299
|
);
|
|
@@ -2681,7 +2926,10 @@ function resolveShape(input, body, contextFn, caller) {
|
|
|
2681
2926
|
|
|
2682
2927
|
// src/runtime/model-guard.ts
|
|
2683
2928
|
var UNIQUE_MUTATION_METHODS = /* @__PURE__ */ new Set(["update", "delete", "upsert"]);
|
|
2684
|
-
var UNIQUE_READ_METHODS = /* @__PURE__ */ new Set([
|
|
2929
|
+
var UNIQUE_READ_METHODS = /* @__PURE__ */ new Set([
|
|
2930
|
+
"findUnique",
|
|
2931
|
+
"findUniqueOrThrow"
|
|
2932
|
+
]);
|
|
2685
2933
|
var BULK_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
2686
2934
|
"updateMany",
|
|
2687
2935
|
"updateManyAndReturn",
|
|
@@ -2695,15 +2943,14 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
2695
2943
|
"createManyAndReturn",
|
|
2696
2944
|
"updateManyAndReturn"
|
|
2697
2945
|
]);
|
|
2698
|
-
var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set([
|
|
2699
|
-
"createMany",
|
|
2700
|
-
"createManyAndReturn"
|
|
2701
|
-
]);
|
|
2946
|
+
var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set(["createMany", "createManyAndReturn"]);
|
|
2702
2947
|
function buildDefaultSelectInput(config) {
|
|
2703
2948
|
const result = {};
|
|
2704
2949
|
for (const [key, value] of Object.entries(config)) {
|
|
2705
2950
|
if (key === "_count") {
|
|
2706
|
-
result[key] = buildDefaultCountInput(
|
|
2951
|
+
result[key] = buildDefaultCountInput(
|
|
2952
|
+
value
|
|
2953
|
+
);
|
|
2707
2954
|
continue;
|
|
2708
2955
|
}
|
|
2709
2956
|
if (value === true) {
|
|
@@ -2721,7 +2968,9 @@ function buildDefaultIncludeInput(config) {
|
|
|
2721
2968
|
const result = {};
|
|
2722
2969
|
for (const [key, value] of Object.entries(config)) {
|
|
2723
2970
|
if (key === "_count") {
|
|
2724
|
-
result[key] = buildDefaultCountInput(
|
|
2971
|
+
result[key] = buildDefaultCountInput(
|
|
2972
|
+
value
|
|
2973
|
+
);
|
|
2725
2974
|
continue;
|
|
2726
2975
|
}
|
|
2727
2976
|
if (value === true) {
|
|
@@ -2835,12 +3084,32 @@ function hasNestedClientControlledArgs(shape) {
|
|
|
2835
3084
|
return false;
|
|
2836
3085
|
}
|
|
2837
3086
|
function createModelGuardExtension(config) {
|
|
2838
|
-
const {
|
|
3087
|
+
const {
|
|
3088
|
+
typeMap,
|
|
3089
|
+
enumMap,
|
|
3090
|
+
zodChains,
|
|
3091
|
+
zodDefaults,
|
|
3092
|
+
uniqueMap,
|
|
3093
|
+
scopeMap,
|
|
3094
|
+
guardConfig,
|
|
3095
|
+
contextFn
|
|
3096
|
+
} = config;
|
|
2839
3097
|
const wrapZodErrors = config.wrapZodErrors ?? false;
|
|
2840
3098
|
const enforceProjection = guardConfig.enforceProjection ?? false;
|
|
2841
3099
|
const scalarBase = createScalarBase(guardConfig.strictDecimal ?? false);
|
|
2842
|
-
const schemaBuilder = createSchemaBuilder(
|
|
2843
|
-
|
|
3100
|
+
const schemaBuilder = createSchemaBuilder(
|
|
3101
|
+
typeMap,
|
|
3102
|
+
zodChains,
|
|
3103
|
+
enumMap,
|
|
3104
|
+
scalarBase,
|
|
3105
|
+
zodDefaults
|
|
3106
|
+
);
|
|
3107
|
+
const queryBuilder = createQueryBuilder(
|
|
3108
|
+
typeMap,
|
|
3109
|
+
enumMap,
|
|
3110
|
+
uniqueMap,
|
|
3111
|
+
scalarBase
|
|
3112
|
+
);
|
|
2844
3113
|
const modelScopeFks = /* @__PURE__ */ new Map();
|
|
2845
3114
|
for (const [model, entries] of Object.entries(scopeMap)) {
|
|
2846
3115
|
const fks = /* @__PURE__ */ new Set();
|
|
@@ -2858,7 +3127,9 @@ function createModelGuardExtension(config) {
|
|
|
2858
3127
|
function createGuardedMethods(modelName, modelDelegate, input, explicitCaller) {
|
|
2859
3128
|
function callDelegate(method, args) {
|
|
2860
3129
|
if (typeof modelDelegate[method] !== "function") {
|
|
2861
|
-
throw new ShapeError(
|
|
3130
|
+
throw new ShapeError(
|
|
3131
|
+
`Method "${method}" is not available on this model`
|
|
3132
|
+
);
|
|
2862
3133
|
}
|
|
2863
3134
|
return modelDelegate[method](args);
|
|
2864
3135
|
}
|
|
@@ -2881,11 +3152,19 @@ function createModelGuardExtension(config) {
|
|
|
2881
3152
|
const cached = readShapeCache.get(cacheKey);
|
|
2882
3153
|
if (cached)
|
|
2883
3154
|
return cached;
|
|
2884
|
-
const built = queryBuilder.buildShapeZodSchema(
|
|
3155
|
+
const built = queryBuilder.buildShapeZodSchema(
|
|
3156
|
+
modelName,
|
|
3157
|
+
method,
|
|
3158
|
+
queryShape
|
|
3159
|
+
);
|
|
2885
3160
|
readShapeCache.set(cacheKey, built);
|
|
2886
3161
|
return built;
|
|
2887
3162
|
}
|
|
2888
|
-
return queryBuilder.buildShapeZodSchema(
|
|
3163
|
+
return queryBuilder.buildShapeZodSchema(
|
|
3164
|
+
modelName,
|
|
3165
|
+
method,
|
|
3166
|
+
queryShape
|
|
3167
|
+
);
|
|
2889
3168
|
}
|
|
2890
3169
|
function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
|
|
2891
3170
|
if (!wasDynamic && !hasDataRefines(dataConfig)) {
|
|
@@ -2893,11 +3172,25 @@ function createModelGuardExtension(config) {
|
|
|
2893
3172
|
const cached = dataSchemaCache.get(cacheKey);
|
|
2894
3173
|
if (cached)
|
|
2895
3174
|
return cached;
|
|
2896
|
-
const built = buildDataSchema(
|
|
3175
|
+
const built = buildDataSchema(
|
|
3176
|
+
modelName,
|
|
3177
|
+
dataConfig,
|
|
3178
|
+
mode,
|
|
3179
|
+
typeMap,
|
|
3180
|
+
schemaBuilder,
|
|
3181
|
+
zodDefaults
|
|
3182
|
+
);
|
|
2897
3183
|
dataSchemaCache.set(cacheKey, built);
|
|
2898
3184
|
return built;
|
|
2899
3185
|
}
|
|
2900
|
-
return buildDataSchema(
|
|
3186
|
+
return buildDataSchema(
|
|
3187
|
+
modelName,
|
|
3188
|
+
dataConfig,
|
|
3189
|
+
mode,
|
|
3190
|
+
typeMap,
|
|
3191
|
+
schemaBuilder,
|
|
3192
|
+
zodDefaults
|
|
3193
|
+
);
|
|
2901
3194
|
}
|
|
2902
3195
|
function getWhereBuilt(whereConfig, matchedKey, wasDynamic) {
|
|
2903
3196
|
if (!wasDynamic) {
|
|
@@ -3016,12 +3309,28 @@ function createModelGuardExtension(config) {
|
|
|
3016
3309
|
const built = getWhereBuilt(shape.where, matchedKey, wasDynamic);
|
|
3017
3310
|
let validatedWhere;
|
|
3018
3311
|
if (built.schema) {
|
|
3019
|
-
|
|
3312
|
+
let sanitizedWhere = bodyWhere;
|
|
3313
|
+
if (built.forcedOnlyKeys.size > 0 && isPlainObject(bodyWhere)) {
|
|
3314
|
+
const w = { ...bodyWhere };
|
|
3315
|
+
for (const key of built.forcedOnlyKeys) {
|
|
3316
|
+
delete w[key];
|
|
3317
|
+
}
|
|
3318
|
+
sanitizedWhere = w;
|
|
3319
|
+
}
|
|
3320
|
+
validatedWhere = built.schema.parse(sanitizedWhere);
|
|
3020
3321
|
} else if (bodyWhere !== void 0) {
|
|
3021
3322
|
if (bodyWhere === null || !isPlainObject(bodyWhere) || Object.keys(bodyWhere).length > 0) {
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3323
|
+
let hasOnlyForcedKeys = false;
|
|
3324
|
+
if (isPlainObject(bodyWhere) && built.forcedOnlyKeys.size > 0) {
|
|
3325
|
+
hasOnlyForcedKeys = Object.keys(bodyWhere).every(
|
|
3326
|
+
(k) => built.forcedOnlyKeys.has(k)
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
if (!hasOnlyForcedKeys) {
|
|
3330
|
+
throw new ShapeError(
|
|
3331
|
+
"Guard shape where contains only forced conditions. Client where input is not accepted."
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3025
3334
|
}
|
|
3026
3335
|
}
|
|
3027
3336
|
if (hasWhereForced(built.forced)) {
|
|
@@ -3030,7 +3339,13 @@ function createModelGuardExtension(config) {
|
|
|
3030
3339
|
return validatedWhere ?? {};
|
|
3031
3340
|
}
|
|
3032
3341
|
function requireWhere(shape, bodyWhere, method, preserveUnique, matchedKey, wasDynamic) {
|
|
3033
|
-
const where = buildWhereFromShape(
|
|
3342
|
+
const where = buildWhereFromShape(
|
|
3343
|
+
shape,
|
|
3344
|
+
bodyWhere,
|
|
3345
|
+
preserveUnique,
|
|
3346
|
+
matchedKey,
|
|
3347
|
+
wasDynamic
|
|
3348
|
+
);
|
|
3034
3349
|
if (Object.keys(where).length === 0) {
|
|
3035
3350
|
throw new ShapeError(`${method} requires a where condition`);
|
|
3036
3351
|
}
|
|
@@ -3044,7 +3359,12 @@ function createModelGuardExtension(config) {
|
|
|
3044
3359
|
throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
|
|
3045
3360
|
}
|
|
3046
3361
|
const { data: _, ...queryShape } = resolved.shape;
|
|
3047
|
-
const built = getReadShape(
|
|
3362
|
+
const built = getReadShape(
|
|
3363
|
+
method,
|
|
3364
|
+
queryShape,
|
|
3365
|
+
resolved.matchedKey,
|
|
3366
|
+
resolved.wasDynamic
|
|
3367
|
+
);
|
|
3048
3368
|
const isUnique = UNIQUE_READ_METHODS.has(method);
|
|
3049
3369
|
const args = applyBuiltShape(built, resolved.body, isUnique);
|
|
3050
3370
|
if (isUnique && args.where) {
|
|
@@ -3077,14 +3397,33 @@ function createModelGuardExtension(config) {
|
|
|
3077
3397
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
3078
3398
|
if (!resolved.shape.data)
|
|
3079
3399
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
3080
|
-
validateMutationShapeKeys(
|
|
3400
|
+
validateMutationShapeKeys(
|
|
3401
|
+
resolved.shape,
|
|
3402
|
+
allowedShapeKeys,
|
|
3403
|
+
method
|
|
3404
|
+
);
|
|
3081
3405
|
validateMutationBodyKeys(resolved.body, allowedBodyKeys, method);
|
|
3082
3406
|
const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
|
|
3083
|
-
validateCreateCompleteness(
|
|
3084
|
-
|
|
3407
|
+
validateCreateCompleteness(
|
|
3408
|
+
modelName,
|
|
3409
|
+
resolved.shape.data,
|
|
3410
|
+
typeMap,
|
|
3411
|
+
fks,
|
|
3412
|
+
zodDefaults
|
|
3413
|
+
);
|
|
3414
|
+
const dataSchema = getDataSchema(
|
|
3415
|
+
"create",
|
|
3416
|
+
resolved.shape.data,
|
|
3417
|
+
resolved.matchedKey,
|
|
3418
|
+
resolved.wasDynamic
|
|
3419
|
+
);
|
|
3085
3420
|
let args;
|
|
3086
3421
|
if (method === "create") {
|
|
3087
|
-
const data = validateAndMergeData(
|
|
3422
|
+
const data = validateAndMergeData(
|
|
3423
|
+
resolved.body.data,
|
|
3424
|
+
dataSchema,
|
|
3425
|
+
method
|
|
3426
|
+
);
|
|
3088
3427
|
args = { data };
|
|
3089
3428
|
} else {
|
|
3090
3429
|
if (!Array.isArray(resolved.body.data))
|
|
@@ -3103,7 +3442,13 @@ function createModelGuardExtension(config) {
|
|
|
3103
3442
|
args.skipDuplicates = resolved.body.skipDuplicates;
|
|
3104
3443
|
}
|
|
3105
3444
|
if (supportsProjection) {
|
|
3106
|
-
const projectionArgs = resolveProjection(
|
|
3445
|
+
const projectionArgs = resolveProjection(
|
|
3446
|
+
resolved.shape,
|
|
3447
|
+
resolved.body,
|
|
3448
|
+
method,
|
|
3449
|
+
resolved.matchedKey,
|
|
3450
|
+
resolved.wasDynamic
|
|
3451
|
+
);
|
|
3107
3452
|
Object.assign(args, projectionArgs);
|
|
3108
3453
|
}
|
|
3109
3454
|
return callDelegate(method, args);
|
|
@@ -3120,24 +3465,60 @@ function createModelGuardExtension(config) {
|
|
|
3120
3465
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
3121
3466
|
if (!resolved.shape.data)
|
|
3122
3467
|
throw new ShapeError(`Guard shape requires "data" for ${method}`);
|
|
3123
|
-
validateMutationShapeKeys(
|
|
3468
|
+
validateMutationShapeKeys(
|
|
3469
|
+
resolved.shape,
|
|
3470
|
+
allowedShapeKeys,
|
|
3471
|
+
method
|
|
3472
|
+
);
|
|
3124
3473
|
validateMutationBodyKeys(resolved.body, allowedBodyKeys, method);
|
|
3125
3474
|
if (isBulk && !resolved.shape.where) {
|
|
3126
|
-
throw new ShapeError(
|
|
3475
|
+
throw new ShapeError(
|
|
3476
|
+
`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`
|
|
3477
|
+
);
|
|
3127
3478
|
}
|
|
3128
3479
|
maybeValidateUniqueWhere(modelName, resolved.shape, method);
|
|
3129
|
-
const dataSchema = getDataSchema(
|
|
3130
|
-
|
|
3131
|
-
|
|
3480
|
+
const dataSchema = getDataSchema(
|
|
3481
|
+
"update",
|
|
3482
|
+
resolved.shape.data,
|
|
3483
|
+
resolved.matchedKey,
|
|
3484
|
+
resolved.wasDynamic
|
|
3485
|
+
);
|
|
3486
|
+
const data = validateAndMergeData(
|
|
3487
|
+
resolved.body.data,
|
|
3488
|
+
dataSchema,
|
|
3489
|
+
method
|
|
3490
|
+
);
|
|
3491
|
+
const where = isUniqueWhere ? requireWhere(
|
|
3492
|
+
resolved.shape,
|
|
3493
|
+
resolved.body.where,
|
|
3494
|
+
method,
|
|
3495
|
+
true,
|
|
3496
|
+
resolved.matchedKey,
|
|
3497
|
+
resolved.wasDynamic
|
|
3498
|
+
) : buildWhereFromShape(
|
|
3499
|
+
resolved.shape,
|
|
3500
|
+
resolved.body.where,
|
|
3501
|
+
false,
|
|
3502
|
+
resolved.matchedKey,
|
|
3503
|
+
resolved.wasDynamic
|
|
3504
|
+
);
|
|
3132
3505
|
if (isBulk && Object.keys(where).length === 0) {
|
|
3133
|
-
throw new ShapeError(
|
|
3506
|
+
throw new ShapeError(
|
|
3507
|
+
`${method} requires at least one where condition`
|
|
3508
|
+
);
|
|
3134
3509
|
}
|
|
3135
3510
|
if (isUniqueWhere) {
|
|
3136
3511
|
validateResolvedUniqueWhere(modelName, where, method, uniqueMap);
|
|
3137
3512
|
}
|
|
3138
3513
|
const args = { data, where };
|
|
3139
3514
|
if (supportsProjection) {
|
|
3140
|
-
const projectionArgs = resolveProjection(
|
|
3515
|
+
const projectionArgs = resolveProjection(
|
|
3516
|
+
resolved.shape,
|
|
3517
|
+
resolved.body,
|
|
3518
|
+
method,
|
|
3519
|
+
resolved.matchedKey,
|
|
3520
|
+
resolved.wasDynamic
|
|
3521
|
+
);
|
|
3141
3522
|
Object.assign(args, projectionArgs);
|
|
3142
3523
|
}
|
|
3143
3524
|
return callDelegate(method, args);
|
|
@@ -3154,22 +3535,49 @@ function createModelGuardExtension(config) {
|
|
|
3154
3535
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
3155
3536
|
if (resolved.shape.data)
|
|
3156
3537
|
throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
|
|
3157
|
-
validateMutationShapeKeys(
|
|
3538
|
+
validateMutationShapeKeys(
|
|
3539
|
+
resolved.shape,
|
|
3540
|
+
allowedShapeKeys,
|
|
3541
|
+
method
|
|
3542
|
+
);
|
|
3158
3543
|
validateMutationBodyKeys(resolved.body, allowedBodyKeys, method);
|
|
3159
3544
|
if (isBulk && !resolved.shape.where) {
|
|
3160
|
-
throw new ShapeError(
|
|
3545
|
+
throw new ShapeError(
|
|
3546
|
+
`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`
|
|
3547
|
+
);
|
|
3161
3548
|
}
|
|
3162
3549
|
maybeValidateUniqueWhere(modelName, resolved.shape, method);
|
|
3163
|
-
const where = isUniqueWhere ? requireWhere(
|
|
3550
|
+
const where = isUniqueWhere ? requireWhere(
|
|
3551
|
+
resolved.shape,
|
|
3552
|
+
resolved.body.where,
|
|
3553
|
+
method,
|
|
3554
|
+
true,
|
|
3555
|
+
resolved.matchedKey,
|
|
3556
|
+
resolved.wasDynamic
|
|
3557
|
+
) : buildWhereFromShape(
|
|
3558
|
+
resolved.shape,
|
|
3559
|
+
resolved.body.where,
|
|
3560
|
+
false,
|
|
3561
|
+
resolved.matchedKey,
|
|
3562
|
+
resolved.wasDynamic
|
|
3563
|
+
);
|
|
3164
3564
|
if (isBulk && Object.keys(where).length === 0) {
|
|
3165
|
-
throw new ShapeError(
|
|
3565
|
+
throw new ShapeError(
|
|
3566
|
+
`${method} requires at least one where condition`
|
|
3567
|
+
);
|
|
3166
3568
|
}
|
|
3167
3569
|
if (isUniqueWhere) {
|
|
3168
3570
|
validateResolvedUniqueWhere(modelName, where, method, uniqueMap);
|
|
3169
3571
|
}
|
|
3170
3572
|
const args = { where };
|
|
3171
3573
|
if (supportsProjection) {
|
|
3172
|
-
const projectionArgs = resolveProjection(
|
|
3574
|
+
const projectionArgs = resolveProjection(
|
|
3575
|
+
resolved.shape,
|
|
3576
|
+
resolved.body,
|
|
3577
|
+
method,
|
|
3578
|
+
resolved.matchedKey,
|
|
3579
|
+
resolved.wasDynamic
|
|
3580
|
+
);
|
|
3173
3581
|
Object.assign(args, projectionArgs);
|
|
3174
3582
|
}
|
|
3175
3583
|
return callDelegate(method, args);
|
|
@@ -3180,7 +3588,9 @@ function createModelGuardExtension(config) {
|
|
|
3180
3588
|
const caller = resolveCaller();
|
|
3181
3589
|
const resolved = resolveShape(input, body, contextFn, caller);
|
|
3182
3590
|
if (resolved.shape.data) {
|
|
3183
|
-
throw new ShapeError(
|
|
3591
|
+
throw new ShapeError(
|
|
3592
|
+
'Guard shape "data" is not valid for upsert. Use "create" and "update" instead.'
|
|
3593
|
+
);
|
|
3184
3594
|
}
|
|
3185
3595
|
if (!resolved.shape.create) {
|
|
3186
3596
|
throw new ShapeError('Guard shape requires "create" for upsert');
|
|
@@ -3196,24 +3606,42 @@ function createModelGuardExtension(config) {
|
|
|
3196
3606
|
VALID_SHAPE_KEYS_UPSERT,
|
|
3197
3607
|
"upsert"
|
|
3198
3608
|
);
|
|
3199
|
-
validateMutationBodyKeys(
|
|
3609
|
+
validateMutationBodyKeys(
|
|
3610
|
+
resolved.body,
|
|
3611
|
+
ALLOWED_BODY_KEYS_UPSERT,
|
|
3612
|
+
"upsert"
|
|
3613
|
+
);
|
|
3200
3614
|
maybeValidateUniqueWhere(modelName, resolved.shape, "upsert");
|
|
3201
3615
|
const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
|
|
3202
|
-
validateCreateCompleteness(
|
|
3616
|
+
validateCreateCompleteness(
|
|
3617
|
+
modelName,
|
|
3618
|
+
resolved.shape.create,
|
|
3619
|
+
typeMap,
|
|
3620
|
+
fks,
|
|
3621
|
+
zodDefaults
|
|
3622
|
+
);
|
|
3203
3623
|
const createDataSchema = getDataSchema(
|
|
3204
3624
|
"create",
|
|
3205
3625
|
resolved.shape.create,
|
|
3206
3626
|
`upsert:create\0${resolved.matchedKey}`,
|
|
3207
3627
|
resolved.wasDynamic
|
|
3208
3628
|
);
|
|
3209
|
-
const createData = validateAndMergeData(
|
|
3629
|
+
const createData = validateAndMergeData(
|
|
3630
|
+
resolved.body.create,
|
|
3631
|
+
createDataSchema,
|
|
3632
|
+
"upsert (create)"
|
|
3633
|
+
);
|
|
3210
3634
|
const updateDataSchema = getDataSchema(
|
|
3211
3635
|
"update",
|
|
3212
3636
|
resolved.shape.update,
|
|
3213
3637
|
`upsert:update\0${resolved.matchedKey}`,
|
|
3214
3638
|
resolved.wasDynamic
|
|
3215
3639
|
);
|
|
3216
|
-
const updateData = validateAndMergeData(
|
|
3640
|
+
const updateData = validateAndMergeData(
|
|
3641
|
+
resolved.body.update,
|
|
3642
|
+
updateDataSchema,
|
|
3643
|
+
"upsert (update)"
|
|
3644
|
+
);
|
|
3217
3645
|
const where = requireWhere(
|
|
3218
3646
|
resolved.shape,
|
|
3219
3647
|
resolved.body.where,
|
|
@@ -3267,10 +3695,9 @@ function createModelGuardExtension(config) {
|
|
|
3267
3695
|
return fn(body);
|
|
3268
3696
|
} catch (err) {
|
|
3269
3697
|
if (err instanceof z9.ZodError) {
|
|
3270
|
-
throw new ShapeError(
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
);
|
|
3698
|
+
throw new ShapeError(`Validation failed: ${formatZodError(err)}`, {
|
|
3699
|
+
cause: err
|
|
3700
|
+
});
|
|
3274
3701
|
}
|
|
3275
3702
|
throw err;
|
|
3276
3703
|
}
|
|
@@ -3289,7 +3716,12 @@ function createModelGuardExtension(config) {
|
|
|
3289
3716
|
`Could not resolve Prisma delegate for model "${modelName}" (key: "${delegateKey}")`
|
|
3290
3717
|
);
|
|
3291
3718
|
}
|
|
3292
|
-
const methods = createGuardedMethods(
|
|
3719
|
+
const methods = createGuardedMethods(
|
|
3720
|
+
modelName,
|
|
3721
|
+
modelDelegate,
|
|
3722
|
+
input,
|
|
3723
|
+
caller
|
|
3724
|
+
);
|
|
3293
3725
|
if (!wrapZodErrors)
|
|
3294
3726
|
return methods;
|
|
3295
3727
|
return wrapMethods(methods);
|