@pothos/plugin-prisma 3.53.0 → 3.55.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +63 -1
  3. package/dts/connection-helpers.d.ts +3 -3
  4. package/dts/connection-helpers.d.ts.map +1 -1
  5. package/dts/global-types.d.ts +15 -4
  6. package/dts/global-types.d.ts.map +1 -1
  7. package/dts/index.d.ts +3 -1
  8. package/dts/index.d.ts.map +1 -1
  9. package/dts/interface-ref.d.ts +10 -0
  10. package/dts/interface-ref.d.ts.map +1 -0
  11. package/dts/model-loader.d.ts +7 -7
  12. package/dts/model-loader.d.ts.map +1 -1
  13. package/dts/prisma-field-builder.d.ts +4 -4
  14. package/dts/prisma-field-builder.d.ts.map +1 -1
  15. package/dts/types.d.ts +23 -7
  16. package/dts/types.d.ts.map +1 -1
  17. package/dts/util/datamodel.d.ts +3 -3
  18. package/dts/util/datamodel.d.ts.map +1 -1
  19. package/dts/util/map-query.d.ts +2 -1
  20. package/dts/util/map-query.d.ts.map +1 -1
  21. package/dts/util/usage.d.ts +4 -0
  22. package/dts/util/usage.d.ts.map +1 -0
  23. package/esm/connection-helpers.d.ts +3 -3
  24. package/esm/connection-helpers.d.ts.map +1 -1
  25. package/esm/connection-helpers.js.map +1 -1
  26. package/esm/field-builder.js +59 -17
  27. package/esm/field-builder.js.map +1 -1
  28. package/esm/global-types.d.ts +21 -10
  29. package/esm/global-types.d.ts.map +1 -1
  30. package/esm/global-types.js.map +1 -1
  31. package/esm/index.d.ts +3 -1
  32. package/esm/index.d.ts.map +1 -1
  33. package/esm/index.js +48 -3
  34. package/esm/index.js.map +1 -1
  35. package/esm/interface-ref.d.ts +10 -0
  36. package/esm/interface-ref.d.ts.map +1 -0
  37. package/esm/interface-ref.js +26 -0
  38. package/esm/interface-ref.js.map +1 -0
  39. package/esm/model-loader.d.ts +7 -7
  40. package/esm/model-loader.d.ts.map +1 -1
  41. package/esm/model-loader.js.map +1 -1
  42. package/esm/prisma-field-builder.d.ts +4 -4
  43. package/esm/prisma-field-builder.d.ts.map +1 -1
  44. package/esm/prisma-field-builder.js +3 -3
  45. package/esm/prisma-field-builder.js.map +1 -1
  46. package/esm/schema-builder.js +27 -0
  47. package/esm/schema-builder.js.map +1 -1
  48. package/esm/types.d.ts +25 -9
  49. package/esm/types.d.ts.map +1 -1
  50. package/esm/util/datamodel.d.ts +3 -3
  51. package/esm/util/datamodel.d.ts.map +1 -1
  52. package/esm/util/datamodel.js +3 -2
  53. package/esm/util/datamodel.js.map +1 -1
  54. package/esm/util/map-query.d.ts +2 -1
  55. package/esm/util/map-query.d.ts.map +1 -1
  56. package/esm/util/map-query.js +21 -14
  57. package/esm/util/map-query.js.map +1 -1
  58. package/esm/util/usage.d.ts +4 -0
  59. package/esm/util/usage.d.ts.map +1 -0
  60. package/esm/util/usage.js +29 -0
  61. package/esm/util/usage.js.map +1 -0
  62. package/lib/connection-helpers.js.map +1 -1
  63. package/lib/field-builder.js +62 -21
  64. package/lib/field-builder.js.map +1 -1
  65. package/lib/index.js +50 -2
  66. package/lib/index.js.map +1 -1
  67. package/lib/interface-ref.js +36 -0
  68. package/lib/interface-ref.js.map +1 -0
  69. package/lib/model-loader.js.map +1 -1
  70. package/lib/prisma-field-builder.js +3 -3
  71. package/lib/prisma-field-builder.js.map +1 -1
  72. package/lib/schema-builder.js +27 -0
  73. package/lib/schema-builder.js.map +1 -1
  74. package/lib/util/datamodel.js +3 -2
  75. package/lib/util/datamodel.js.map +1 -1
  76. package/lib/util/map-query.js +20 -13
  77. package/lib/util/map-query.js.map +1 -1
  78. package/lib/util/usage.js +51 -0
  79. package/lib/util/usage.js.map +1 -0
  80. package/package.json +2 -2
  81. package/src/connection-helpers.ts +6 -6
  82. package/src/field-builder.ts +90 -15
  83. package/src/global-types.ts +39 -11
  84. package/src/index.ts +56 -2
  85. package/src/interface-ref.ts +18 -0
  86. package/src/model-loader.ts +13 -7
  87. package/src/prisma-field-builder.ts +7 -10
  88. package/src/schema-builder.ts +44 -1
  89. package/src/types.ts +66 -9
  90. package/src/util/datamodel.ts +8 -3
  91. package/src/util/map-query.ts +38 -14
  92. package/src/util/usage.ts +33 -0
package/src/types.ts CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  typeBrandKey,
22
22
  TypeParam,
23
23
  } from '@pothos/core';
24
- import { PrismaObjectRef } from './object-ref';
24
+ import { PrismaInterfaceRef, PrismaRef } from './interface-ref';
25
25
  import type { PrismaObjectFieldBuilder } from './prisma-field-builder';
26
26
 
27
27
  export interface PrismaDelegate {
@@ -228,6 +228,60 @@ export type PrismaObjectTypeOptions<
228
228
  > = PrismaObjectRefOptions<Types, Model, FindUnique, Include, Select, Shape> &
229
229
  PrismaObjectImplementationOptions<Types, Model, Interfaces, FindUnique, Select, Shape>;
230
230
 
231
+ export type PrismaInterfaceRefOptions<
232
+ Types extends SchemaTypes,
233
+ Model extends PrismaModelTypes,
234
+ FindUnique,
235
+ Include,
236
+ Select,
237
+ Shape extends object,
238
+ > = NameOrVariant &
239
+ (
240
+ | {
241
+ include?: Include & Model['Include'];
242
+ select?: never;
243
+ findUnique?: FindUnique &
244
+ (((parent: Shape, context: Types['Context']) => Model['WhereUnique']) | null);
245
+ }
246
+ | {
247
+ select: Model['Select'] & Select;
248
+ include?: never;
249
+ findUnique?: (parent: Shape, context: Types['Context']) => Model['WhereUnique'];
250
+ }
251
+ );
252
+
253
+ export type PrismaInterfaceImplementationOptions<
254
+ Types extends SchemaTypes,
255
+ Model extends PrismaModelTypes,
256
+ Interfaces extends InterfaceParam<Types>[],
257
+ FindUnique,
258
+ Select,
259
+ Shape extends object,
260
+ > = Omit<
261
+ PothosSchemaTypes.InterfaceTypeOptions<Types, Shape, Interfaces>,
262
+ 'fields' | 'description'
263
+ > & {
264
+ description?: string | false;
265
+ fields?: PrismaObjectFieldsShape<
266
+ Types,
267
+ Model,
268
+ FindUnique extends null ? true : false,
269
+ Shape & (FindUnique extends null ? {} : { [prismaModelName]?: Model['Name'] }),
270
+ Select
271
+ >;
272
+ };
273
+
274
+ export type PrismaInterfaceTypeOptions<
275
+ Types extends SchemaTypes,
276
+ Model extends PrismaModelTypes,
277
+ Interfaces extends InterfaceParam<Types>[],
278
+ FindUnique,
279
+ Include,
280
+ Select,
281
+ Shape extends object,
282
+ > = PrismaInterfaceRefOptions<Types, Model, FindUnique, Include, Select, Shape> &
283
+ PrismaInterfaceImplementationOptions<Types, Model, Interfaces, FindUnique, Select, Shape>;
284
+
231
285
  type NameOrVariant =
232
286
  | {
233
287
  name?: never;
@@ -394,14 +448,14 @@ export type RelatedFieldOptions<
394
448
  >;
395
449
  }) & {
396
450
  description?: string | false;
397
- type?: PrismaObjectRef<TypesForRelation<Types, Model, Field>>;
451
+ type?: PrismaRef<TypesForRelation<Types, Model, Field>>;
398
452
  query?: QueryForField<Types, Args, Model['Include'][Field & keyof Model['Include']]>;
399
453
  };
400
454
 
401
455
  export type VariantFieldOptions<
402
456
  Types extends SchemaTypes,
403
457
  Model extends PrismaModelTypes,
404
- Variant extends PrismaObjectRef<Model>,
458
+ Variant extends PrismaRef<Model>,
405
459
  Args extends InputFieldMap,
406
460
  isNull,
407
461
  Shape,
@@ -458,10 +512,10 @@ export type PrismaFieldOptions<
458
512
  Types extends SchemaTypes,
459
513
  ParentShape,
460
514
  Type extends
461
- | PrismaObjectRef<PrismaModelTypes>
515
+ | PrismaRef<PrismaModelTypes>
462
516
  | keyof Types['PrismaTypes']
463
517
  | [keyof Types['PrismaTypes']]
464
- | [PrismaObjectRef<PrismaModelTypes>],
518
+ | [PrismaRef<PrismaModelTypes>],
465
519
  Model extends PrismaModelTypes,
466
520
  Param extends TypeParam<Types>,
467
521
  Args extends InputFieldMap,
@@ -494,10 +548,10 @@ export type PrismaFieldWithInputOptions<
494
548
  Args extends Record<string, InputFieldRef<unknown, 'Arg'>>,
495
549
  Fields extends Record<string, InputFieldRef<unknown, 'InputObject'>>,
496
550
  Type extends
497
- | PrismaObjectRef<PrismaModelTypes>
551
+ | PrismaRef<PrismaModelTypes>
498
552
  | keyof Types['PrismaTypes']
499
553
  | [keyof Types['PrismaTypes']]
500
- | [PrismaObjectRef<PrismaModelTypes>],
554
+ | [PrismaRef<PrismaModelTypes>],
501
555
  Model extends PrismaModelTypes,
502
556
  Param extends TypeParam<Types>,
503
557
  Nullable extends FieldNullability<Param>,
@@ -562,7 +616,10 @@ export type PrismaFieldResolver<
562
616
  export type PrismaConnectionFieldOptions<
563
617
  Types extends SchemaTypes,
564
618
  ParentShape,
565
- Type extends PrismaObjectRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
619
+ Type extends
620
+ | PrismaRef<PrismaModelTypes>
621
+ | PrismaInterfaceRef<PrismaModelTypes>
622
+ | keyof Types['PrismaTypes'],
566
623
  Model extends PrismaModelTypes,
567
624
  Param extends OutputType<Types>,
568
625
  Nullable extends boolean,
@@ -665,7 +722,7 @@ export type RelatedConnectionOptions<
665
722
  ? {
666
723
  description?: string | false;
667
724
  query?: QueryForField<Types, Args, Model['Include'][Field & keyof Model['Include']]>;
668
- type?: PrismaObjectRef<TypesForRelation<Types, Model, Field>>;
725
+ type?: PrismaRef<TypesForRelation<Types, Model, Field>>;
669
726
  cursor: CursorFromRelation<Model, Field>;
670
727
  defaultSize?: number | ((args: ConnectionArgs, ctx: Types['Context']) => number);
671
728
  maxSize?: number | ((args: ConnectionArgs, ctx: Types['Context']) => number);
@@ -1,9 +1,10 @@
1
1
  import { ObjectRef, PothosSchemaError, SchemaTypes } from '@pothos/core';
2
+ import { PrismaInterfaceRef, PrismaRef } from '../interface-ref';
2
3
  import { PrismaObjectRef } from '../object-ref';
3
4
  import { PrismaClient, PrismaDelegate, PrismaModelTypes } from '../types';
4
5
  import { getDMMF } from './get-client';
5
6
 
6
- export const refMap = new WeakMap<object, Map<string, PrismaObjectRef<PrismaModelTypes>>>();
7
+ export const refMap = new WeakMap<object, Map<string, PrismaRef<PrismaModelTypes>>>();
7
8
  export const findUniqueMap = new WeakMap<
8
9
  object,
9
10
  Map<ObjectRef<unknown>, ((args: unknown, ctx: {}) => unknown) | null>
@@ -17,14 +18,18 @@ export const includeForRefMap = new WeakMap<
17
18
  export function getRefFromModel<Types extends SchemaTypes>(
18
19
  name: string,
19
20
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
20
- ): PrismaObjectRef<PrismaModelTypes> {
21
+ type: 'object' | 'interface' = 'object',
22
+ ): PrismaRef<PrismaModelTypes> {
21
23
  if (!refMap.has(builder)) {
22
24
  refMap.set(builder, new Map());
23
25
  }
24
26
  const cache = refMap.get(builder)!;
25
27
 
26
28
  if (!cache.has(name)) {
27
- cache.set(name, new PrismaObjectRef(name, name));
29
+ cache.set(
30
+ name,
31
+ type === 'object' ? new PrismaObjectRef(name, name) : new PrismaInterfaceRef(name, name),
32
+ );
28
33
  }
29
34
 
30
35
  return cache.get(name)!;
@@ -6,10 +6,12 @@ import {
6
6
  getArgumentValues,
7
7
  getNamedType,
8
8
  GraphQLField,
9
+ GraphQLInterfaceType,
9
10
  GraphQLNamedType,
10
11
  GraphQLObjectType,
11
12
  GraphQLResolveInfo,
12
13
  InlineFragmentNode,
14
+ isInterfaceType,
13
15
  isObjectType,
14
16
  Kind,
15
17
  SelectionSetNode,
@@ -31,6 +33,7 @@ import {
31
33
  SelectionState,
32
34
  selectionToQuery,
33
35
  } from './selections';
36
+ import { wrapWithUsageCheck } from './usage';
34
37
 
35
38
  function addTypeSelectionsForField(
36
39
  type: GraphQLNamedType,
@@ -83,7 +86,7 @@ function addTypeSelectionsForField(
83
86
  return;
84
87
  }
85
88
 
86
- if (!isObjectType(type)) {
89
+ if (!(isObjectType(type) || isInterfaceType(type))) {
87
90
  return;
88
91
  }
89
92
 
@@ -142,7 +145,7 @@ function resolveIndirectInclude(
142
145
  for (const sel of selection.selectionSet.selections) {
143
146
  switch (sel.kind) {
144
147
  case Kind.FIELD:
145
- if (sel.name.value === include.name && isObjectType(type)) {
148
+ if (sel.name.value === include.name && (isObjectType(type) || isInterfaceType(type))) {
146
149
  const returnType = getNamedType(type.getFields()[sel.name.value].type);
147
150
 
148
151
  resolveIndirectInclude(
@@ -195,13 +198,14 @@ function resolveIndirectInclude(
195
198
  }
196
199
 
197
200
  function addNestedSelections(
198
- type: GraphQLObjectType,
201
+ type: GraphQLObjectType | GraphQLInterfaceType,
199
202
  context: object,
200
203
  info: GraphQLResolveInfo,
201
204
  state: SelectionState,
202
205
  selections: SelectionSetNode,
203
206
  indirectPath: string[],
204
207
  ) {
208
+ let parentType = type;
205
209
  for (const selection of selections.selections) {
206
210
  switch (selection.kind) {
207
211
  case Kind.FIELD:
@@ -209,12 +213,19 @@ function addNestedSelections(
209
213
 
210
214
  continue;
211
215
  case Kind.FRAGMENT_SPREAD:
212
- if (info.fragments[selection.name.value].typeCondition.name.value !== type.name) {
216
+ parentType = info.schema.getType(
217
+ info.fragments[selection.name.value].typeCondition.name.value,
218
+ )! as GraphQLObjectType;
219
+ if (
220
+ isObjectType(type)
221
+ ? parentType.name !== type.name
222
+ : parentType.extensions?.pothosPrismaModel !== type.extensions.pothosPrismaModel
223
+ ) {
213
224
  continue;
214
225
  }
215
226
 
216
227
  addNestedSelections(
217
- type,
228
+ parentType,
218
229
  context,
219
230
  info,
220
231
  state,
@@ -225,11 +236,18 @@ function addNestedSelections(
225
236
  continue;
226
237
 
227
238
  case Kind.INLINE_FRAGMENT:
228
- if (selection.typeCondition && selection.typeCondition.name.value !== type.name) {
239
+ parentType = selection.typeCondition
240
+ ? (info.schema.getType(selection.typeCondition.name.value) as GraphQLObjectType)
241
+ : type;
242
+ if (
243
+ isObjectType(type)
244
+ ? parentType.name !== type.name
245
+ : parentType.extensions?.pothosPrismaModel !== type.extensions.pothosPrismaModel
246
+ ) {
229
247
  continue;
230
248
  }
231
249
 
232
- addNestedSelections(type, context, info, state, selection.selectionSet, indirectPath);
250
+ addNestedSelections(parentType, context, info, state, selection.selectionSet, indirectPath);
233
251
 
234
252
  continue;
235
253
 
@@ -242,7 +260,7 @@ function addNestedSelections(
242
260
  }
243
261
 
244
262
  function addFieldSelection(
245
- type: GraphQLObjectType,
263
+ type: GraphQLObjectType | GraphQLInterfaceType,
246
264
  context: object,
247
265
  info: GraphQLResolveInfo,
248
266
  state: SelectionState,
@@ -370,6 +388,7 @@ export function queryFromInfo<T extends SelectionMap['select'] | undefined = und
370
388
  select,
371
389
  path = [],
372
390
  paths = [],
391
+ withUsageCheck = false,
373
392
  }: {
374
393
  context: object;
375
394
  info: GraphQLResolveInfo;
@@ -377,6 +396,7 @@ export function queryFromInfo<T extends SelectionMap['select'] | undefined = und
377
396
  select?: T;
378
397
  path?: string[];
379
398
  paths?: string[][];
399
+ withUsageCheck?: boolean;
380
400
  }): { select: T } | { include?: {} } {
381
401
  const returnType = getNamedType(info.returnType);
382
402
  const type = typeName ? info.schema.getTypeMap()[typeName] : returnType;
@@ -437,7 +457,9 @@ export function queryFromInfo<T extends SelectionMap['select'] | undefined = und
437
457
 
438
458
  setLoaderMappings(context, info, state.mappings);
439
459
 
440
- return selectionToQuery(state) as { select: T };
460
+ const query = selectionToQuery(state) as { select: T };
461
+
462
+ return withUsageCheck ? wrapWithUsageCheck(query) : query;
441
463
  }
442
464
 
443
465
  export function selectionStateFromInfo(
@@ -449,8 +471,10 @@ export function selectionStateFromInfo(
449
471
 
450
472
  const state = createStateForType(type, info);
451
473
 
452
- if (!isObjectType(type)) {
453
- throw new PothosValidationError('Prisma plugin can only resolve includes for object types');
474
+ if (!(isObjectType(type) || isInterfaceType(type))) {
475
+ throw new PothosValidationError(
476
+ 'Prisma plugin can only resolve includes for object and interface types',
477
+ );
454
478
  }
455
479
 
456
480
  addFieldSelection(type, context, info, state, info.fieldNodes[0], []);
@@ -498,7 +522,7 @@ function normalizeInclude(path: string[], type: GraphQLNamedType): IndirectInclu
498
522
 
499
523
  const normalized: { name: string; type: string }[] = [];
500
524
 
501
- if (!isObjectType(currentType)) {
525
+ if (!(isObjectType(currentType) || isInterfaceType(currentType))) {
502
526
  throw new PothosValidationError(`Expected ${currentType} to be an Object type`);
503
527
  }
504
528
 
@@ -511,8 +535,8 @@ function normalizeInclude(path: string[], type: GraphQLNamedType): IndirectInclu
511
535
 
512
536
  currentType = getNamedType(field.type);
513
537
 
514
- if (!isObjectType(currentType)) {
515
- throw new PothosValidationError(`Expected ${currentType} to be an Object type`);
538
+ if (!(isObjectType(currentType) || isInterfaceType(currentType))) {
539
+ throw new PothosValidationError(`Expected ${currentType} to be an Object or Interface type`);
516
540
  }
517
541
 
518
542
  normalized.push({ name: fieldName, type: currentType.name });
@@ -0,0 +1,33 @@
1
+ export const usageSymbol = Symbol.for('Pothos.isUsed');
2
+
3
+ export function wrapWithUsageCheck<T extends Object>(obj: T): T {
4
+ const result = {};
5
+ let used = true;
6
+
7
+ Object.defineProperty(result, usageSymbol, {
8
+ get() {
9
+ return used;
10
+ },
11
+ enumerable: false,
12
+ });
13
+
14
+ for (const key of Object.keys(obj)) {
15
+ // only set to false if the object has keys
16
+ used = false;
17
+ Object.defineProperty(result, key, {
18
+ enumerable: true,
19
+ configurable: true,
20
+ // eslint-disable-next-line @typescript-eslint/no-loop-func
21
+ get() {
22
+ used = true;
23
+ return obj[key as keyof T];
24
+ },
25
+ });
26
+ }
27
+
28
+ return result as T;
29
+ }
30
+
31
+ export function isUsed(obj: object): boolean {
32
+ return !(usageSymbol in obj) || (obj as { [usageSymbol]: boolean })[usageSymbol];
33
+ }