@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
@@ -1,6 +1,6 @@
1
1
  import { ObjectRef, SchemaTypes } from '@pothos/core';
2
+ import { PrismaRef } from './interface-ref';
2
3
  import { ModelLoader } from './model-loader';
3
- import { PrismaObjectRef } from './object-ref';
4
4
  import type { PrismaModelTypes, ShapeFromSelection, UniqueFieldsFromWhereUnique } from './types';
5
5
  import {
6
6
  getCursorFormatter,
@@ -17,12 +17,12 @@ export const prismaModelKey = Symbol.for('Pothos.prismaModelKey');
17
17
 
18
18
  export function prismaConnectionHelpers<
19
19
  Types extends SchemaTypes,
20
- RefOrType extends PrismaObjectRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
20
+ RefOrType extends PrismaRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
21
21
  Select extends Model['Select'] & {},
22
- Model extends PrismaModelTypes = RefOrType extends PrismaObjectRef<infer T>
22
+ Model extends PrismaModelTypes = RefOrType extends PrismaRef<infer T>
23
23
  ? T & PrismaModelTypes
24
24
  : Types['PrismaTypes'][RefOrType & keyof Types['PrismaTypes']] & PrismaModelTypes,
25
- Shape = RefOrType extends PrismaObjectRef<PrismaModelTypes, infer T> ? T : Model['Shape'],
25
+ Shape = RefOrType extends PrismaRef<PrismaModelTypes, infer T> ? T : Model['Shape'],
26
26
  EdgeShape = Model['Include'] extends Select
27
27
  ? Shape
28
28
  : ShapeFromSelection<Types, Model, { select: Select }>,
@@ -41,7 +41,7 @@ export function prismaConnectionHelpers<
41
41
  },
42
42
  ) {
43
43
  const modelName =
44
- typeof refOrType === 'string' ? refOrType : (refOrType as PrismaObjectRef<Model>).modelName;
44
+ typeof refOrType === 'string' ? refOrType : (refOrType as PrismaRef<Model>).modelName;
45
45
  const ref =
46
46
  typeof refOrType === 'string'
47
47
  ? getRefFromModel(modelName, builder)
@@ -119,7 +119,7 @@ export function prismaConnectionHelpers<
119
119
  return {
120
120
  ref: (typeof refOrType === 'string'
121
121
  ? getRefFromModel(refOrType, builder)
122
- : refOrType) as PrismaObjectRef<Model>,
122
+ : refOrType) as PrismaRef<Model>,
123
123
  resolve,
124
124
  select: options.select ?? {},
125
125
  getQuery,
@@ -3,8 +3,10 @@ import {
3
3
  FieldKind,
4
4
  FieldRef,
5
5
  InputFieldMap,
6
+ isThenable,
6
7
  MaybePromise,
7
8
  ObjectRef,
9
+ PothosError,
8
10
  RootFieldBuilder,
9
11
  SchemaTypes,
10
12
  } from '@pothos/core';
@@ -13,6 +15,7 @@ import { PrismaConnectionFieldOptions, PrismaModelTypes } from './types';
13
15
  import { getCursorFormatter, getCursorParser, resolvePrismaCursorConnection } from './util/cursors';
14
16
  import { getRefFromModel } from './util/datamodel';
15
17
  import { queryFromInfo } from './util/map-query';
18
+ import { isUsed } from './util/usage';
16
19
 
17
20
  const fieldBuilderProto = RootFieldBuilder.prototype as PothosSchemaTypes.RootFieldBuilder<
18
21
  SchemaTypes,
@@ -32,9 +35,18 @@ fieldBuilderProto.prismaField = function prismaField({ type, resolve, ...options
32
35
  ...(options as {}),
33
36
  type: typeParam,
34
37
  resolve: (parent: never, args: unknown, context: {}, info: GraphQLResolveInfo) => {
35
- const query = queryFromInfo({ context, info });
38
+ const query = queryFromInfo({
39
+ context,
40
+ info,
41
+ withUsageCheck: !!this.builder.options.prisma?.onUnusedQuery,
42
+ });
36
43
 
37
- return resolve(query, parent, args as never, context, info) as never;
44
+ return checkIfQueryIsUsed(
45
+ this.builder,
46
+ query,
47
+ info,
48
+ resolve(query, parent, args as never, context, info) as never,
49
+ );
38
50
  },
39
51
  }) as never;
40
52
  };
@@ -57,9 +69,18 @@ fieldBuilderProto.prismaFieldWithInput = function prismaFieldWithInput({
57
69
  ...(options as {}),
58
70
  type: typeParam,
59
71
  resolve: (parent: never, args: unknown, context: {}, info: GraphQLResolveInfo) => {
60
- const query = queryFromInfo({ context, info });
72
+ const query = queryFromInfo({
73
+ context,
74
+ info,
75
+ withUsageCheck: !!this.builder.options.prisma?.onUnusedQuery,
76
+ });
61
77
 
62
- return resolve(query, parent, args as never, context, info) as never;
78
+ return checkIfQueryIsUsed(
79
+ this.builder,
80
+ query,
81
+ info,
82
+ resolve(query, parent, args as never, context, info) as never,
83
+ );
63
84
  },
64
85
  }) as never;
65
86
  };
@@ -114,17 +135,20 @@ fieldBuilderProto.prismaConnection = function prismaConnection<
114
135
  args: PothosSchemaTypes.DefaultConnectionArguments,
115
136
  context: {},
116
137
  info: GraphQLResolveInfo,
117
- ) =>
118
- resolvePrismaCursorConnection(
138
+ ) => {
139
+ const query = queryFromInfo({
140
+ context,
141
+ info,
142
+ select: cursorSelection as {},
143
+ paths: [['nodes'], ['edges', 'node']],
144
+ typeName,
145
+ withUsageCheck: !!this.builder.options.prisma?.onUnusedQuery,
146
+ });
147
+
148
+ return resolvePrismaCursorConnection(
119
149
  {
120
150
  parent,
121
- query: queryFromInfo({
122
- context,
123
- info,
124
- select: cursorSelection as {},
125
- paths: [['nodes'], ['edges', 'node']],
126
- typeName,
127
- }),
151
+ query,
128
152
  ctx: context,
129
153
  parseCursor,
130
154
  maxSize,
@@ -133,8 +157,15 @@ fieldBuilderProto.prismaConnection = function prismaConnection<
133
157
  totalCount: totalCount && (() => totalCount(parent, args as never, context, info)),
134
158
  },
135
159
  formatCursor,
136
- (query) => resolve(query as never, parent, args as never, context, info) as never,
137
- ),
160
+ (q) =>
161
+ checkIfQueryIsUsed(
162
+ this.builder,
163
+ query,
164
+ info,
165
+ resolve(q as never, parent, args as never, context, info) as never,
166
+ ),
167
+ );
168
+ },
138
169
  },
139
170
  connectionOptions instanceof ObjectRef
140
171
  ? connectionOptions
@@ -163,3 +194,47 @@ fieldBuilderProto.prismaConnection = function prismaConnection<
163
194
 
164
195
  return fieldRef;
165
196
  } as never;
197
+
198
+ function checkIfQueryIsUsed<Types extends SchemaTypes, T>(
199
+ builder: PothosSchemaTypes.SchemaBuilder<Types>,
200
+ query: object,
201
+ info: GraphQLResolveInfo,
202
+ result: T,
203
+ ): T {
204
+ const { onUnusedQuery } = builder.options.prisma || {};
205
+ if (!onUnusedQuery) {
206
+ return result;
207
+ }
208
+
209
+ if (isThenable(result)) {
210
+ return result.then((resolved) => {
211
+ if (!isUsed(query)) {
212
+ onUnused();
213
+ }
214
+
215
+ return resolved;
216
+ }) as T;
217
+ }
218
+
219
+ if (!isUsed(query)) {
220
+ onUnused();
221
+ }
222
+
223
+ return result;
224
+
225
+ function onUnused() {
226
+ if (typeof onUnusedQuery === 'function') {
227
+ onUnusedQuery(info);
228
+ return;
229
+ }
230
+
231
+ const message = `Prisma query was unused in resolver for ${info.parentType.name}.${info.fieldName}`;
232
+
233
+ if (onUnusedQuery === 'error') {
234
+ throw new PothosError(message);
235
+ } else if (onUnusedQuery === 'warn') {
236
+ // eslint-disable-next-line no-console
237
+ console.warn(message);
238
+ }
239
+ }
240
+ }
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  /* eslint-disable @typescript-eslint/no-empty-interface */
3
+ import { GraphQLResolveInfo } from 'graphql';
3
4
  import {
4
5
  FieldKind,
5
6
  FieldMap,
@@ -15,6 +16,7 @@ import {
15
16
  ShapeFromTypeParam,
16
17
  TypeParam,
17
18
  } from '@pothos/core';
19
+ import { PrismaInterfaceRef, PrismaRef } from './interface-ref';
18
20
  import { PrismaNodeRef } from './node-ref';
19
21
  import { prismaModelKey, PrismaObjectRef } from './object-ref';
20
22
  import { PrismaObjectFieldBuilder as InternalPrismaObjectFieldBuilder } from './prisma-field-builder';
@@ -24,6 +26,7 @@ import {
24
26
  PrismaConnectionShape,
25
27
  PrismaFieldOptions,
26
28
  PrismaFieldWithInputOptions,
29
+ PrismaInterfaceTypeOptions,
27
30
  prismaModelName,
28
31
  PrismaModelTypes,
29
32
  PrismaNodeOptions,
@@ -52,6 +55,7 @@ declare global {
52
55
  models?: boolean;
53
56
  fields?: boolean;
54
57
  };
58
+ onUnusedQuery?: null | 'warn' | 'error' | ((info: GraphQLResolveInfo) => void);
55
59
  }
56
60
  | {
57
61
  filterConnectionTotalCount?: boolean;
@@ -63,6 +67,7 @@ declare global {
63
67
  models?: boolean;
64
68
  fields?: boolean;
65
69
  };
70
+ onUnusedQuery?: null | 'warn' | 'error' | ((info: GraphQLResolveInfo) => void);
66
71
  };
67
72
  }
68
73
 
@@ -122,6 +127,29 @@ declare global {
122
127
  ShapeFromSelection<Types, Model, { select: Select; include: Include }>
123
128
  >;
124
129
 
130
+ prismaInterface: <
131
+ Name extends keyof Types['PrismaTypes'],
132
+ Interfaces extends InterfaceParam<Types>[],
133
+ FindUnique,
134
+ Model extends PrismaModelTypes & Types['PrismaTypes'][Name],
135
+ Include = unknown,
136
+ Select = unknown,
137
+ >(
138
+ name: Name,
139
+ options: PrismaInterfaceTypeOptions<
140
+ Types,
141
+ Model,
142
+ Interfaces,
143
+ FindUnique,
144
+ Include,
145
+ Select,
146
+ ShapeFromSelection<Types, Model, { select: Select; include: Include }>
147
+ >,
148
+ ) => PrismaInterfaceRef<
149
+ Model,
150
+ ShapeFromSelection<Types, Model, { select: Select; include: Include }>
151
+ >;
152
+
125
153
  prismaObjectField: <
126
154
  Type extends PrismaObjectRef<PrismaModelTypes, {}> | keyof Types['PrismaTypes'],
127
155
  Model extends PrismaModelTypes = Type extends PrismaObjectRef<infer M, {}>
@@ -194,10 +222,10 @@ declare global {
194
222
  prismaField: <
195
223
  Args extends InputFieldMap,
196
224
  TypeParam extends
197
- | PrismaObjectRef<PrismaModelTypes>
225
+ | PrismaRef<PrismaModelTypes>
198
226
  | keyof Types['PrismaTypes']
199
227
  | [keyof Types['PrismaTypes']]
200
- | [PrismaObjectRef<PrismaModelTypes>],
228
+ | [PrismaRef<PrismaModelTypes>],
201
229
  Nullable extends FieldNullability<Type>,
202
230
  ResolveShape,
203
231
  ResolveReturnShape,
@@ -207,9 +235,9 @@ declare global {
207
235
  Model extends PrismaModelTypes = PrismaModelTypes &
208
236
  (TypeParam extends [keyof Types['PrismaTypes']]
209
237
  ? Types['PrismaTypes'][TypeParam[0]]
210
- : TypeParam extends [PrismaObjectRef<PrismaModelTypes>]
238
+ : TypeParam extends [PrismaRef<PrismaModelTypes>]
211
239
  ? TypeParam[0][typeof prismaModelKey]
212
- : TypeParam extends PrismaObjectRef<PrismaModelTypes>
240
+ : TypeParam extends PrismaRef<PrismaModelTypes>
213
241
  ? TypeParam[typeof prismaModelKey]
214
242
  : TypeParam extends keyof Types['PrismaTypes']
215
243
  ? Types['PrismaTypes'][TypeParam]
@@ -231,14 +259,14 @@ declare global {
231
259
 
232
260
  prismaConnection: 'relay' extends PluginName
233
261
  ? <
234
- Type extends PrismaObjectRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
262
+ Type extends PrismaRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
235
263
  Nullable extends boolean,
236
264
  ResolveReturnShape,
237
265
  Args extends InputFieldMap = {},
238
- Model extends PrismaModelTypes = Type extends PrismaObjectRef<infer T>
266
+ Model extends PrismaModelTypes = Type extends PrismaRef<infer T>
239
267
  ? T
240
268
  : PrismaModelTypes & Types['PrismaTypes'][Type & keyof Types['PrismaTypes']],
241
- Shape = Type extends PrismaObjectRef<PrismaModelTypes, infer S> ? S : Model['Shape'],
269
+ Shape = Type extends PrismaRef<PrismaModelTypes, infer S> ? S : Model['Shape'],
242
270
  ConnectionInterfaces extends InterfaceParam<Types>[] = [],
243
271
  EdgeInterfaces extends InterfaceParam<Types>[] = [],
244
272
  >(
@@ -287,10 +315,10 @@ declare global {
287
315
  ? <
288
316
  Fields extends Record<string, InputFieldRef<unknown, 'InputObject'>>,
289
317
  TypeParam extends
290
- | PrismaObjectRef<PrismaModelTypes>
318
+ | PrismaRef<PrismaModelTypes>
291
319
  | keyof Types['PrismaTypes']
292
320
  | [keyof Types['PrismaTypes']]
293
- | [PrismaObjectRef<PrismaModelTypes>],
321
+ | [PrismaRef<PrismaModelTypes>],
294
322
  Type extends TypeParam extends [unknown]
295
323
  ? [ObjectRef<Model['Shape']>]
296
324
  : ObjectRef<Model['Shape']>,
@@ -303,9 +331,9 @@ declare global {
303
331
  Model extends PrismaModelTypes = PrismaModelTypes &
304
332
  (TypeParam extends [keyof Types['PrismaTypes']]
305
333
  ? Types['PrismaTypes'][TypeParam[0]]
306
- : TypeParam extends [PrismaObjectRef<PrismaModelTypes>]
334
+ : TypeParam extends [PrismaRef<PrismaModelTypes>]
307
335
  ? TypeParam[0][typeof prismaModelKey]
308
- : TypeParam extends PrismaObjectRef<PrismaModelTypes>
336
+ : TypeParam extends PrismaRef<PrismaModelTypes>
309
337
  ? TypeParam[typeof prismaModelKey]
310
338
  : TypeParam extends keyof Types['PrismaTypes']
311
339
  ? Types['PrismaTypes'][TypeParam]
package/src/index.ts CHANGED
@@ -6,6 +6,8 @@ import SchemaBuilder, {
6
6
  BasePlugin,
7
7
  BuildCache,
8
8
  PothosOutputFieldConfig,
9
+ PothosSchemaError,
10
+ PothosTypeConfig,
9
11
  SchemaTypes,
10
12
  } from '@pothos/core';
11
13
  import { ModelLoader } from './model-loader';
@@ -17,6 +19,7 @@ import { getLoaderMapping, setLoaderMappings } from './util/loader-map';
17
19
  import { queryFromInfo, selectionStateFromInfo } from './util/map-query';
18
20
 
19
21
  export { prismaConnectionHelpers } from './connection-helpers';
22
+ export { PrismaInterfaceRef } from './interface-ref';
20
23
  export { PrismaNodeRef } from './node-ref';
21
24
  export { PrismaObjectRef } from './object-ref';
22
25
  export * from './types';
@@ -47,6 +50,37 @@ export class PrismaPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
47
50
  super(cache, pluginName);
48
51
  }
49
52
 
53
+ override onTypeConfig(typeConfig: PothosTypeConfig): PothosTypeConfig {
54
+ if (typeConfig.kind !== 'Object' && typeConfig.kind !== 'Interface') {
55
+ return typeConfig;
56
+ }
57
+
58
+ let model = typeConfig.extensions?.pothosPrismaModel as string | undefined;
59
+
60
+ typeConfig.interfaces.forEach((iface) => {
61
+ const interfaceModel = this.buildCache.getTypeConfig(iface, 'Interface').extensions
62
+ ?.pothosPrismaModel as string | undefined;
63
+
64
+ if (interfaceModel) {
65
+ if (model && model !== interfaceModel) {
66
+ throw new PothosSchemaError(
67
+ `PrismaObjects must be based on the same prisma model as any PrismaInterfaces they extend. ${typeConfig.name} uses ${model} and ${iface.name} uses ${interfaceModel}`,
68
+ );
69
+ }
70
+
71
+ model = interfaceModel;
72
+ }
73
+ });
74
+
75
+ return {
76
+ ...typeConfig,
77
+ extensions: {
78
+ ...typeConfig.extensions,
79
+ pothosPrismaModel: model,
80
+ },
81
+ };
82
+ }
83
+
50
84
  override onOutputFieldConfig(
51
85
  fieldConfig: PothosOutputFieldConfig<Types>,
52
86
  ): PothosOutputFieldConfig<Types> | null {
@@ -85,7 +119,7 @@ export class PrismaPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
85
119
  return resolver;
86
120
  }
87
121
 
88
- const parentConfig = this.buildCache.getTypeConfig(fieldConfig.parentType, 'Object');
122
+ const parentConfig = this.buildCache.getTypeConfig(fieldConfig.parentType);
89
123
  const loadedCheck = fieldConfig.extensions?.pothosPrismaLoaded as
90
124
  | undefined
91
125
  | ((val: unknown) => boolean);
@@ -97,8 +131,28 @@ export class PrismaPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
97
131
  | undefined
98
132
  | ((query: {}, parent: unknown, args: {}, context: {}, info: {}) => unknown);
99
133
 
134
+ const parentTypes = new Set([fieldConfig.parentType]);
135
+
136
+ if (parentConfig.kind === 'Interface' || parentConfig.kind === 'Object') {
137
+ parentConfig.interfaces.forEach((iface) => {
138
+ const interfaceConfig = this.buildCache.getTypeConfig(iface, 'Interface');
139
+ if (interfaceConfig.extensions?.pothosPrismaModel) {
140
+ parentTypes.add(interfaceConfig.name);
141
+ }
142
+ });
143
+ }
144
+
100
145
  return (parent, args, context, info) => {
101
- const mapping = getLoaderMapping(context, info.path, info.parentType.name);
146
+ let mapping = getLoaderMapping(context, info.path, info.parentType.name);
147
+
148
+ if (!mapping) {
149
+ for (const parentType of parentTypes) {
150
+ mapping = getLoaderMapping(context, info.path, parentType);
151
+ if (mapping) {
152
+ break;
153
+ }
154
+ }
155
+ }
102
156
 
103
157
  if ((!loadedCheck || loadedCheck(parent)) && mapping) {
104
158
  setLoaderMappings(context, info, mapping);
@@ -0,0 +1,18 @@
1
+ import { InterfaceRef } from '@pothos/core';
2
+ import { prismaModelKey, PrismaObjectRef } from './object-ref';
3
+ import type { PrismaModelTypes } from './types';
4
+
5
+ export type PrismaRef<Model extends PrismaModelTypes, T = {}> =
6
+ | PrismaObjectRef<Model, T>
7
+ | PrismaInterfaceRef<Model, T>;
8
+
9
+ export class PrismaInterfaceRef<Model extends PrismaModelTypes, T = {}> extends InterfaceRef<T> {
10
+ [prismaModelKey]!: Model;
11
+ modelName: string;
12
+
13
+ constructor(name: string, modelName: string) {
14
+ super(name);
15
+
16
+ this.modelName = modelName;
17
+ }
18
+ }
@@ -1,4 +1,10 @@
1
- import { createContextCache, ObjectRef, PothosSchemaError, SchemaTypes } from '@pothos/core';
1
+ import {
2
+ createContextCache,
3
+ InterfaceRef,
4
+ ObjectRef,
5
+ PothosSchemaError,
6
+ SchemaTypes,
7
+ } from '@pothos/core';
2
8
  import { getDelegateFromModel, getModel } from './util/datamodel';
3
9
  import { getClient } from './util/get-client';
4
10
  import {
@@ -32,7 +38,7 @@ export class ModelLoader {
32
38
  }
33
39
 
34
40
  static forRef<Types extends SchemaTypes>(
35
- ref: ObjectRef<unknown>,
41
+ ref: ObjectRef<unknown> | InterfaceRef<unknown>,
36
42
  modelName: string,
37
43
  findUnique: ((model: Record<string, unknown>, ctx: {}) => unknown) | undefined,
38
44
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
@@ -78,7 +84,7 @@ export class ModelLoader {
78
84
  }
79
85
 
80
86
  static getDefaultFindBy<Types extends SchemaTypes>(
81
- ref: ObjectRef<unknown>,
87
+ ref: ObjectRef<unknown> | InterfaceRef<unknown>,
82
88
  modelName: string,
83
89
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
84
90
  ) {
@@ -115,7 +121,7 @@ export class ModelLoader {
115
121
  }
116
122
 
117
123
  static getDefaultFindUnique<Types extends SchemaTypes>(
118
- ref: ObjectRef<unknown>,
124
+ ref: ObjectRef<unknown> | InterfaceRef<unknown>,
119
125
  modelName: string,
120
126
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
121
127
  ): (model: Record<string, unknown>) => {} {
@@ -125,7 +131,7 @@ export class ModelLoader {
125
131
  }
126
132
 
127
133
  static getDefaultIDSelection<Types extends SchemaTypes>(
128
- ref: ObjectRef<unknown>,
134
+ ref: ObjectRef<unknown> | InterfaceRef<unknown>,
129
135
  modelName: string,
130
136
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
131
137
  ): Record<string, boolean> {
@@ -145,7 +151,7 @@ export class ModelLoader {
145
151
  }
146
152
 
147
153
  static getCursorSelection<Types extends SchemaTypes>(
148
- ref: ObjectRef<unknown>,
154
+ ref: ObjectRef<unknown> | InterfaceRef<unknown>,
149
155
  modelName: string,
150
156
  cursor: string,
151
157
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
@@ -174,7 +180,7 @@ export class ModelLoader {
174
180
  }
175
181
 
176
182
  static getFindUniqueForField<Types extends SchemaTypes>(
177
- ref: ObjectRef<unknown>,
183
+ ref: ObjectRef<unknown> | InterfaceRef<unknown>,
178
184
  modelName: string,
179
185
  fieldName: string,
180
186
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
@@ -18,8 +18,8 @@ import {
18
18
  ShapeFromTypeParam,
19
19
  TypeParam,
20
20
  } from '@pothos/core';
21
+ import { PrismaRef } from './interface-ref';
21
22
  import { ModelLoader } from './model-loader';
22
- import { PrismaObjectRef } from './object-ref';
23
23
  import {
24
24
  PrismaConnectionShape,
25
25
  PrismaModelTypes,
@@ -367,8 +367,9 @@ export class PrismaObjectFieldBuilder<
367
367
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
368
368
  model: string,
369
369
  fieldMap: FieldMap,
370
+ graphqlKind: PothosSchemaTypes.PothosKindToGraphQLType[FieldKind] = 'Object',
370
371
  ) {
371
- super(name, builder, 'PrismaObject', 'Object');
372
+ super(name, builder, 'PrismaObject', graphqlKind);
372
373
 
373
374
  this.model = model;
374
375
  this.prismaFieldMap = fieldMap;
@@ -473,18 +474,14 @@ export class PrismaObjectFieldBuilder<
473
474
  }) as FieldRef<number, 'Object'>;
474
475
  }
475
476
 
476
- variant<
477
- Variant extends Model['Name'] | PrismaObjectRef<Model>,
478
- Args extends InputFieldMap,
479
- Nullable,
480
- >(
477
+ variant<Variant extends Model['Name'] | PrismaRef<Model>, Args extends InputFieldMap, Nullable>(
481
478
  variant: Variant,
482
479
  ...allArgs: NormalizeArgs<
483
480
  [
484
481
  options: VariantFieldOptions<
485
482
  Types,
486
483
  Model,
487
- Variant extends PrismaObjectRef<Model> ? Variant : PrismaObjectRef<Model>,
484
+ Variant extends PrismaRef<Model> ? Variant : PrismaRef<Model>,
488
485
  Args,
489
486
  Nullable,
490
487
  Shape
@@ -493,7 +490,7 @@ export class PrismaObjectFieldBuilder<
493
490
  >
494
491
  ): FieldRef<Model['Shape'], 'Object'> {
495
492
  const [{ isNull, nullable, ...options } = {} as never] = allArgs;
496
- const ref: PrismaObjectRef<PrismaModelTypes> =
493
+ const ref: PrismaRef<PrismaModelTypes> =
497
494
  typeof variant === 'string' ? getRefFromModel(variant, this.builder) : variant;
498
495
 
499
496
  const selfSelect = (args: object, context: object, nestedQuery: (query: unknown) => unknown) =>
@@ -550,7 +547,7 @@ export class PrismaObjectFieldBuilder<
550
547
  ) {
551
548
  const [name, options = {} as never] = args;
552
549
 
553
- const typeConfig = this.builder.configStore.getTypeConfig(this.typename, 'Object');
550
+ const typeConfig = this.builder.configStore.getTypeConfig(this.typename);
554
551
  const usingSelect = !!typeConfig.extensions?.pothosPrismaSelect;
555
552
 
556
553
  return this.exposeField<Type, Nullable, never>(name as never, {
@@ -9,6 +9,7 @@ import SchemaBuilder, {
9
9
  PothosError,
10
10
  SchemaTypes,
11
11
  } from '@pothos/core';
12
+ import { PrismaInterfaceRef } from './interface-ref';
12
13
  import { ModelLoader } from './model-loader';
13
14
  import { PrismaNodeRef } from './node-ref';
14
15
  import { PrismaObjectRef } from './object-ref';
@@ -29,7 +30,7 @@ schemaBuilderProto.prismaObject = function prismaObject(
29
30
  ) {
30
31
  const ref = options.variant
31
32
  ? new PrismaObjectRef(options.variant, type)
32
- : getRefFromModel(type, this);
33
+ : (getRefFromModel(type, this) as PrismaObjectRef<PrismaModelTypes>);
33
34
  const name = options.variant ?? options.name ?? type;
34
35
  const fieldMap = getRelationMap(getDMMF(this)).get(type)!;
35
36
  const idSelection = ModelLoader.getDefaultIDSelection(ref, type, this);
@@ -64,6 +65,48 @@ schemaBuilderProto.prismaObject = function prismaObject(
64
65
  return ref as never;
65
66
  };
66
67
 
68
+ schemaBuilderProto.prismaInterface = function prismaInterface(
69
+ type,
70
+ { fields, findUnique, select, include, description, ...options },
71
+ ) {
72
+ const ref = options.variant
73
+ ? new PrismaInterfaceRef(options.variant, type)
74
+ : (getRefFromModel(type, this, 'interface') as PrismaInterfaceRef<PrismaModelTypes>);
75
+ const name = options.variant ?? options.name ?? type;
76
+ const fieldMap = getRelationMap(getDMMF(this)).get(type)!;
77
+ const idSelection = ModelLoader.getDefaultIDSelection(ref, type, this);
78
+
79
+ ref.name = name;
80
+
81
+ this.interfaceType(ref, {
82
+ ...(options as {}),
83
+ description: getModelDescription(type, this, description),
84
+ extensions: {
85
+ ...options.extensions,
86
+ pothosPrismaInclude: include,
87
+ pothosPrismaModel: type,
88
+ pothosPrismaFieldMap: fieldMap,
89
+ pothosPrismaSelect: select && { ...idSelection, ...(select as {}) },
90
+ pothosPrismaLoader: ModelLoader.forRef(ref, type, findUnique as never, this),
91
+ },
92
+ name,
93
+ fields: fields
94
+ ? () =>
95
+ fields(
96
+ new PrismaObjectFieldBuilder(
97
+ name,
98
+ this,
99
+ type,
100
+ getRelationMap(getDMMF(this)).get(type)!,
101
+ 'Interface',
102
+ ),
103
+ )
104
+ : undefined,
105
+ });
106
+
107
+ return ref as never;
108
+ };
109
+
67
110
  schemaBuilderProto.prismaNode = function prismaNode(
68
111
  this: PothosSchemaTypes.SchemaBuilder<SchemaTypes> & {
69
112
  nodeInterfaceRef?: () => InterfaceRef<unknown>;