prisma-guard 1.8.0 → 1.9.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.
@@ -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>;
@@ -1685,6 +1685,7 @@ var KNOWN_NESTED_INCLUDE_KEYS = /* @__PURE__ */ new Set([
1685
1685
  ]);
1686
1686
  var KNOWN_NESTED_SELECT_KEYS = /* @__PURE__ */ new Set([
1687
1687
  "select",
1688
+ "include",
1688
1689
  "where",
1689
1690
  "orderBy",
1690
1691
  "cursor",
@@ -1938,10 +1939,13 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
1938
1939
  KNOWN_NESTED_SELECT_KEYS,
1939
1940
  `nested select for "${fieldName}" on model "${model}"`
1940
1941
  );
1942
+ if (config.select && config.include) {
1943
+ throw new ShapeError(`Nested select for "${fieldName}" cannot define both "select" and "include".`);
1944
+ }
1941
1945
  if (!fieldMeta.isList) {
1942
1946
  if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
1943
1947
  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.`
1948
+ `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
1949
  );
1946
1950
  }
1947
1951
  }
@@ -1957,6 +1961,16 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
1957
1961
  relForced._countWherePlacement = "select";
1958
1962
  }
1959
1963
  }
1964
+ if (config.include) {
1965
+ const nested = buildIncludeSchema(fieldMeta.type, config.include, currentDepth + 1);
1966
+ nestedSchemas["include"] = nested.schema;
1967
+ if (Object.keys(nested.forcedTree).length > 0)
1968
+ relForced.include = nested.forcedTree;
1969
+ if (Object.keys(nested.forcedCountWhere).length > 0) {
1970
+ relForced._countWhere = nested.forcedCountWhere;
1971
+ relForced._countWherePlacement = "include";
1972
+ }
1973
+ }
1960
1974
  if (config.where) {
1961
1975
  const { schema: whereSchema, forced } = deps.buildWhereSchema(
1962
1976
  fieldMeta.type,
@@ -3066,6 +3080,8 @@ function buildDefaultSelectInput(config) {
3066
3080
  const nested = {};
3067
3081
  if (value.select)
3068
3082
  nested.select = buildDefaultSelectInput(value.select);
3083
+ if (value.include)
3084
+ nested.include = buildDefaultIncludeInput(value.include);
3069
3085
  result[key] = Object.keys(nested).length > 0 ? nested : true;
3070
3086
  }
3071
3087
  }
@@ -3114,6 +3130,41 @@ function buildDefaultProjectionBody(shape) {
3114
3130
  }
3115
3131
  return {};
3116
3132
  }
3133
+ function applyClientProjectionOverrides(shapeDefault, clientProjection) {
3134
+ const result = { ...shapeDefault };
3135
+ for (const [key, clientValue] of Object.entries(clientProjection)) {
3136
+ const defaultValue = result[key];
3137
+ if (defaultValue === void 0) {
3138
+ result[key] = clientValue;
3139
+ continue;
3140
+ }
3141
+ if (clientValue === true) {
3142
+ result[key] = true;
3143
+ continue;
3144
+ }
3145
+ if (isPlainObject(clientValue)) {
3146
+ if (!isPlainObject(defaultValue)) {
3147
+ result[key] = clientValue;
3148
+ continue;
3149
+ }
3150
+ const merged = { ...defaultValue };
3151
+ const clientObj = clientValue;
3152
+ for (const [argKey, argValue] of Object.entries(clientObj)) {
3153
+ const defaultArgValue = merged[argKey];
3154
+ if ((argKey === "select" || argKey === "include") && isPlainObject(argValue) && isPlainObject(defaultArgValue)) {
3155
+ merged[argKey] = applyClientProjectionOverrides(
3156
+ defaultArgValue,
3157
+ argValue
3158
+ );
3159
+ } else {
3160
+ merged[argKey] = argValue;
3161
+ }
3162
+ }
3163
+ result[key] = merged;
3164
+ }
3165
+ }
3166
+ return result;
3167
+ }
3117
3168
  function hasClientControlledValues(obj) {
3118
3169
  for (const value of Object.values(obj)) {
3119
3170
  if (isForcedValue(value))
@@ -3176,6 +3227,8 @@ function checkSelectForClientArgs(config) {
3176
3227
  return true;
3177
3228
  if (value.select && checkSelectForClientArgs(value.select))
3178
3229
  return true;
3230
+ if (value.include && checkIncludeForClientArgs(value.include))
3231
+ return true;
3179
3232
  }
3180
3233
  return false;
3181
3234
  }
@@ -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(