prisma-guard 1.8.0 → 1.9.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.
@@ -84,6 +84,7 @@ interface NestedIncludeArgs {
84
84
  }
85
85
  interface NestedSelectArgs {
86
86
  select?: Record<string, true | NestedSelectArgs>;
87
+ include?: Record<string, true | NestedIncludeArgs>;
87
88
  where?: Record<string, unknown>;
88
89
  orderBy?: Record<string, OrderByFieldConfig>;
89
90
  cursor?: Record<string, true>;
@@ -84,6 +84,7 @@ interface NestedIncludeArgs {
84
84
  }
85
85
  interface NestedSelectArgs {
86
86
  select?: Record<string, true | NestedSelectArgs>;
87
+ include?: Record<string, true | NestedIncludeArgs>;
87
88
  where?: Record<string, unknown>;
88
89
  orderBy?: Record<string, OrderByFieldConfig>;
89
90
  cursor?: Record<string, true>;
@@ -132,7 +132,7 @@ import { z as z3 } from "zod";
132
132
  // src/runtime/zod-type-map.ts
133
133
  import { z as z2 } from "zod";
134
134
  var SCALAR_OPERATORS = {
135
- String: /* @__PURE__ */ new Set(["equals", "not", "contains", "startsWith", "endsWith", "in", "notIn"]),
135
+ String: /* @__PURE__ */ new Set(["equals", "not", "contains", "startsWith", "endsWith", "in", "notIn", "gt", "gte", "lt", "lte"]),
136
136
  Int: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
137
137
  Float: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
138
138
  Decimal: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
@@ -708,6 +708,9 @@ function applyBuiltShape(built, body, isUniqueMethod) {
708
708
  const hasWhereInSchema = "where" in built.zodSchema.shape;
709
709
  if (isPlainObject(body)) {
710
710
  const bodyObj = body;
711
+ if ("select" in bodyObj && "include" in bodyObj) {
712
+ throw new ShapeError('Request cannot define both "include" and "select"');
713
+ }
711
714
  if ("where" in bodyObj) {
712
715
  if (!hasWhereInSchema) {
713
716
  const { where: _, ...rest } = bodyObj;
@@ -1685,6 +1688,7 @@ var KNOWN_NESTED_INCLUDE_KEYS = /* @__PURE__ */ new Set([
1685
1688
  ]);
1686
1689
  var KNOWN_NESTED_SELECT_KEYS = /* @__PURE__ */ new Set([
1687
1690
  "select",
1691
+ "include",
1688
1692
  "where",
1689
1693
  "orderBy",
1690
1694
  "cursor",
@@ -1938,10 +1942,13 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
1938
1942
  KNOWN_NESTED_SELECT_KEYS,
1939
1943
  `nested select for "${fieldName}" on model "${model}"`
1940
1944
  );
1945
+ if (config.select && config.include) {
1946
+ throw new ShapeError(`Nested select for "${fieldName}" cannot define both "select" and "include".`);
1947
+ }
1941
1948
  if (!fieldMeta.isList) {
1942
1949
  if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
1943
1950
  throw new ShapeError(
1944
- `Relation "${fieldName}" on model "${model}" is to-one. Only "select" is supported for to-one nested reads, not where/orderBy/cursor/take/skip.`
1951
+ `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.`
1945
1952
  );
1946
1953
  }
1947
1954
  }
@@ -1957,6 +1964,16 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
1957
1964
  relForced._countWherePlacement = "select";
1958
1965
  }
1959
1966
  }
1967
+ if (config.include) {
1968
+ const nested = buildIncludeSchema(fieldMeta.type, config.include, currentDepth + 1);
1969
+ nestedSchemas["include"] = nested.schema;
1970
+ if (Object.keys(nested.forcedTree).length > 0)
1971
+ relForced.include = nested.forcedTree;
1972
+ if (Object.keys(nested.forcedCountWhere).length > 0) {
1973
+ relForced._countWhere = nested.forcedCountWhere;
1974
+ relForced._countWherePlacement = "include";
1975
+ }
1976
+ }
1960
1977
  if (config.where) {
1961
1978
  const { schema: whereSchema, forced } = deps.buildWhereSchema(
1962
1979
  fieldMeta.type,
@@ -2096,11 +2113,6 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2096
2113
  if (UNIQUE_WHERE_METHODS.has(method) && !shape.where) {
2097
2114
  throw new ShapeError(`${method} shape must define "where"`);
2098
2115
  }
2099
- if (shape.include && shape.select) {
2100
- throw new ShapeError(
2101
- 'Shape config cannot define both "include" and "select".'
2102
- );
2103
- }
2104
2116
  if (method === "groupBy" && !shape.by)
2105
2117
  throw new ShapeError('groupBy shape must define "by"');
2106
2118
  if (method === "groupBy" && (shape.include || shape.select)) {
@@ -3066,6 +3078,8 @@ function buildDefaultSelectInput(config) {
3066
3078
  const nested = {};
3067
3079
  if (value.select)
3068
3080
  nested.select = buildDefaultSelectInput(value.select);
3081
+ if (value.include)
3082
+ nested.include = buildDefaultIncludeInput(value.include);
3069
3083
  result[key] = Object.keys(nested).length > 0 ? nested : true;
3070
3084
  }
3071
3085
  }
@@ -3114,6 +3128,41 @@ function buildDefaultProjectionBody(shape) {
3114
3128
  }
3115
3129
  return {};
3116
3130
  }
3131
+ function applyClientProjectionOverrides(shapeDefault, clientProjection) {
3132
+ const result = { ...shapeDefault };
3133
+ for (const [key, clientValue] of Object.entries(clientProjection)) {
3134
+ const defaultValue = result[key];
3135
+ if (defaultValue === void 0) {
3136
+ result[key] = clientValue;
3137
+ continue;
3138
+ }
3139
+ if (clientValue === true) {
3140
+ result[key] = true;
3141
+ continue;
3142
+ }
3143
+ if (isPlainObject(clientValue)) {
3144
+ if (!isPlainObject(defaultValue)) {
3145
+ result[key] = clientValue;
3146
+ continue;
3147
+ }
3148
+ const merged = { ...defaultValue };
3149
+ const clientObj = clientValue;
3150
+ for (const [argKey, argValue] of Object.entries(clientObj)) {
3151
+ const defaultArgValue = merged[argKey];
3152
+ if ((argKey === "select" || argKey === "include") && isPlainObject(argValue) && isPlainObject(defaultArgValue)) {
3153
+ merged[argKey] = applyClientProjectionOverrides(
3154
+ defaultArgValue,
3155
+ argValue
3156
+ );
3157
+ } else {
3158
+ merged[argKey] = argValue;
3159
+ }
3160
+ }
3161
+ result[key] = merged;
3162
+ }
3163
+ }
3164
+ return result;
3165
+ }
3117
3166
  function hasClientControlledValues(obj) {
3118
3167
  for (const value of Object.values(obj)) {
3119
3168
  if (isForcedValue(value))
@@ -3176,6 +3225,8 @@ function checkSelectForClientArgs(config) {
3176
3225
  return true;
3177
3226
  if (value.select && checkSelectForClientArgs(value.select))
3178
3227
  return true;
3228
+ if (value.include && checkIncludeForClientArgs(value.include))
3229
+ return true;
3179
3230
  }
3180
3231
  return false;
3181
3232
  }
@@ -3311,9 +3362,6 @@ function createModelGuardExtension(config) {
3311
3362
  return queryBuilder.buildWhereSchema(modelName, whereConfig);
3312
3363
  }
3313
3364
  function buildProjectionSchema(shape) {
3314
- if (shape.select && shape.include) {
3315
- throw new ShapeError('Shape cannot define both "select" and "include"');
3316
- }
3317
3365
  const schemaFields = {};
3318
3366
  let forcedIncludeTree = {};
3319
3367
  let forcedSelectTree = {};
@@ -3365,6 +3413,11 @@ function createModelGuardExtension(config) {
3365
3413
  `Guard shape does not define "select" or "include" for ${method} return projection`
3366
3414
  );
3367
3415
  }
3416
+ if ("select" in parsed && "include" in parsed) {
3417
+ throw new ShapeError(
3418
+ 'Request body cannot define both "select" and "include"'
3419
+ );
3420
+ }
3368
3421
  if (!hasShapeProjection)
3369
3422
  return {};
3370
3423
  if (!hasBodyProjection && !enforceProjection)
@@ -3458,6 +3511,29 @@ function createModelGuardExtension(config) {
3458
3511
  }
3459
3512
  return where;
3460
3513
  }
3514
+ function buildEffectiveReadBody(resolved) {
3515
+ const hasShapeProjection = !!resolved.shape.select || !!resolved.shape.include;
3516
+ if (!hasShapeProjection)
3517
+ return resolved.body;
3518
+ const defaultProjection = buildDefaultProjectionBody(resolved.shape);
3519
+ const hasBodyProjection = "select" in resolved.body || "include" in resolved.body;
3520
+ if (!hasBodyProjection) {
3521
+ return { ...resolved.body, ...defaultProjection };
3522
+ }
3523
+ const merged = { ...resolved.body };
3524
+ if ("select" in resolved.body && "select" in defaultProjection && isPlainObject(resolved.body.select) && isPlainObject(defaultProjection.select)) {
3525
+ merged.select = applyClientProjectionOverrides(
3526
+ defaultProjection.select,
3527
+ resolved.body.select
3528
+ );
3529
+ } else if ("include" in resolved.body && "include" in defaultProjection && isPlainObject(resolved.body.include) && isPlainObject(defaultProjection.include)) {
3530
+ merged.include = applyClientProjectionOverrides(
3531
+ defaultProjection.include,
3532
+ resolved.body.include
3533
+ );
3534
+ }
3535
+ return merged;
3536
+ }
3461
3537
  function makeReadMethod(method) {
3462
3538
  return (body) => {
3463
3539
  const caller = resolveCaller();
@@ -3473,17 +3549,7 @@ function createModelGuardExtension(config) {
3473
3549
  resolved.wasDynamic
3474
3550
  );
3475
3551
  const isUnique = UNIQUE_READ_METHODS.has(method);
3476
- let effectiveBody = resolved.body;
3477
- const hasShapeProjection = !!resolved.shape.select || !!resolved.shape.include;
3478
- if (hasShapeProjection) {
3479
- const hasBodyProjection = "select" in resolved.body || "include" in resolved.body;
3480
- if (!hasBodyProjection) {
3481
- effectiveBody = {
3482
- ...resolved.body,
3483
- ...buildDefaultProjectionBody(resolved.shape)
3484
- };
3485
- }
3486
- }
3552
+ const effectiveBody = buildEffectiveReadBody(resolved);
3487
3553
  const args = applyBuiltShape(built, effectiveBody, isUnique);
3488
3554
  if (isUnique && args.where) {
3489
3555
  validateResolvedUniqueWhere(