@pothos/plugin-prisma 0.18.0 → 3.1.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 (165) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +420 -315
  3. package/esm/field-builder.d.ts.map +1 -1
  4. package/esm/field-builder.js +19 -6
  5. package/esm/field-builder.js.map +1 -1
  6. package/esm/generator.js +4 -0
  7. package/esm/generator.js.map +1 -1
  8. package/esm/global-types.d.ts +23 -5
  9. package/esm/global-types.d.ts.map +1 -1
  10. package/esm/index.d.ts +4 -1
  11. package/esm/index.d.ts.map +1 -1
  12. package/esm/index.js +46 -1
  13. package/esm/index.js.map +1 -1
  14. package/esm/model-loader.d.ts +5 -6
  15. package/esm/model-loader.d.ts.map +1 -1
  16. package/esm/model-loader.js +18 -78
  17. package/esm/model-loader.js.map +1 -1
  18. package/esm/prisma-field-builder.d.ts +25 -6
  19. package/esm/prisma-field-builder.d.ts.map +1 -1
  20. package/esm/prisma-field-builder.js +86 -118
  21. package/esm/prisma-field-builder.js.map +1 -1
  22. package/esm/schema-builder.js +14 -4
  23. package/esm/schema-builder.js.map +1 -1
  24. package/esm/types.d.ts +74 -77
  25. package/esm/types.d.ts.map +1 -1
  26. package/esm/types.js +1 -0
  27. package/esm/types.js.map +1 -1
  28. package/esm/{cursors.d.ts → util/cursors.d.ts} +5 -5
  29. package/esm/util/cursors.d.ts.map +1 -0
  30. package/esm/{cursors.js → util/cursors.js} +0 -0
  31. package/esm/util/cursors.js.map +1 -0
  32. package/{lib/refs.d.ts → esm/util/datamodel.d.ts} +4 -8
  33. package/esm/util/datamodel.d.ts.map +1 -0
  34. package/esm/{refs.js → util/datamodel.js} +2 -25
  35. package/esm/util/datamodel.js.map +1 -0
  36. package/esm/util/deep-equal.d.ts +2 -0
  37. package/esm/util/deep-equal.d.ts.map +1 -0
  38. package/esm/util/deep-equal.js +39 -0
  39. package/esm/util/deep-equal.js.map +1 -0
  40. package/esm/util/loader-map.d.ts +6 -0
  41. package/esm/util/loader-map.d.ts.map +1 -0
  42. package/esm/{loader-map.js → util/loader-map.js} +10 -12
  43. package/esm/util/loader-map.js.map +1 -0
  44. package/esm/util/map-query.d.ts +6 -0
  45. package/esm/util/map-query.d.ts.map +1 -0
  46. package/esm/util/map-query.js +169 -0
  47. package/esm/util/map-query.js.map +1 -0
  48. package/esm/util/relation-map.d.ts +9 -0
  49. package/esm/util/relation-map.d.ts.map +1 -0
  50. package/esm/util/relation-map.js +20 -0
  51. package/esm/util/relation-map.js.map +1 -0
  52. package/esm/util/selections.d.ts +20 -0
  53. package/esm/util/selections.d.ts.map +1 -0
  54. package/esm/util/selections.js +139 -0
  55. package/esm/util/selections.js.map +1 -0
  56. package/lib/field-builder.d.ts.map +1 -1
  57. package/lib/field-builder.js +30 -13
  58. package/lib/field-builder.js.map +1 -1
  59. package/lib/generator.js +9 -1
  60. package/lib/generator.js.map +1 -1
  61. package/lib/global-types.d.ts +23 -5
  62. package/lib/global-types.d.ts.map +1 -1
  63. package/lib/index.d.ts +4 -1
  64. package/lib/index.d.ts.map +1 -1
  65. package/lib/index.js +50 -1
  66. package/lib/index.js.map +1 -1
  67. package/lib/model-loader.d.ts +5 -6
  68. package/lib/model-loader.d.ts.map +1 -1
  69. package/lib/model-loader.js +19 -79
  70. package/lib/model-loader.js.map +1 -1
  71. package/lib/prisma-field-builder.d.ts +25 -6
  72. package/lib/prisma-field-builder.d.ts.map +1 -1
  73. package/lib/prisma-field-builder.js +92 -124
  74. package/lib/prisma-field-builder.js.map +1 -1
  75. package/lib/schema-builder.js +22 -8
  76. package/lib/schema-builder.js.map +1 -1
  77. package/lib/types.d.ts +74 -77
  78. package/lib/types.d.ts.map +1 -1
  79. package/lib/types.js +2 -0
  80. package/lib/types.js.map +1 -1
  81. package/lib/{cursors.d.ts → util/cursors.d.ts} +5 -5
  82. package/lib/util/cursors.d.ts.map +1 -0
  83. package/lib/{cursors.js → util/cursors.js} +0 -0
  84. package/lib/util/cursors.js.map +1 -0
  85. package/{esm/refs.d.ts → lib/util/datamodel.d.ts} +4 -8
  86. package/lib/util/datamodel.d.ts.map +1 -0
  87. package/lib/{refs.js → util/datamodel.js} +3 -29
  88. package/lib/util/datamodel.js.map +1 -0
  89. package/lib/util/deep-equal.d.ts +2 -0
  90. package/lib/util/deep-equal.d.ts.map +1 -0
  91. package/lib/util/deep-equal.js +43 -0
  92. package/lib/util/deep-equal.js.map +1 -0
  93. package/lib/util/loader-map.d.ts +6 -0
  94. package/lib/util/loader-map.d.ts.map +1 -0
  95. package/lib/{loader-map.js → util/loader-map.js} +10 -12
  96. package/lib/util/loader-map.js.map +1 -0
  97. package/lib/util/map-query.d.ts +6 -0
  98. package/lib/util/map-query.d.ts.map +1 -0
  99. package/lib/util/map-query.js +175 -0
  100. package/lib/util/map-query.js.map +1 -0
  101. package/lib/util/relation-map.d.ts +9 -0
  102. package/lib/util/relation-map.d.ts.map +1 -0
  103. package/lib/util/relation-map.js +24 -0
  104. package/lib/util/relation-map.js.map +1 -0
  105. package/lib/util/selections.d.ts +20 -0
  106. package/lib/util/selections.d.ts.map +1 -0
  107. package/lib/util/selections.js +148 -0
  108. package/lib/util/selections.js.map +1 -0
  109. package/package.json +8 -8
  110. package/src/field-builder.ts +22 -5
  111. package/src/generator.ts +18 -0
  112. package/src/global-types.ts +59 -12
  113. package/src/index.ts +75 -1
  114. package/src/model-loader.ts +27 -106
  115. package/src/prisma-field-builder.ts +195 -152
  116. package/src/schema-builder.ts +28 -7
  117. package/src/types.ts +155 -102
  118. package/src/{cursors.ts → util/cursors.ts} +3 -3
  119. package/src/{refs.ts → util/datamodel.ts} +3 -44
  120. package/src/util/deep-equal.ts +51 -0
  121. package/src/{loader-map.ts → util/loader-map.ts} +13 -13
  122. package/src/util/map-query.ts +327 -0
  123. package/src/util/relation-map.ts +36 -0
  124. package/src/util/selections.ts +192 -0
  125. package/esm/cursors.d.ts.map +0 -1
  126. package/esm/cursors.js.map +0 -1
  127. package/esm/loader-map.d.ts +0 -6
  128. package/esm/loader-map.d.ts.map +0 -1
  129. package/esm/loader-map.js.map +0 -1
  130. package/esm/refs.d.ts.map +0 -1
  131. package/esm/refs.js.map +0 -1
  132. package/esm/util/index.d.ts +0 -5
  133. package/esm/util/index.d.ts.map +0 -1
  134. package/esm/util/index.js +0 -16
  135. package/esm/util/index.js.map +0 -1
  136. package/esm/util/map-includes.d.ts +0 -6
  137. package/esm/util/map-includes.d.ts.map +0 -1
  138. package/esm/util/map-includes.js +0 -184
  139. package/esm/util/map-includes.js.map +0 -1
  140. package/esm/util/merge-includes.d.ts +0 -3
  141. package/esm/util/merge-includes.d.ts.map +0 -1
  142. package/esm/util/merge-includes.js +0 -91
  143. package/esm/util/merge-includes.js.map +0 -1
  144. package/lib/cursors.d.ts.map +0 -1
  145. package/lib/cursors.js.map +0 -1
  146. package/lib/loader-map.d.ts +0 -6
  147. package/lib/loader-map.d.ts.map +0 -1
  148. package/lib/loader-map.js.map +0 -1
  149. package/lib/refs.d.ts.map +0 -1
  150. package/lib/refs.js.map +0 -1
  151. package/lib/util/index.d.ts +0 -5
  152. package/lib/util/index.d.ts.map +0 -1
  153. package/lib/util/index.js +0 -30
  154. package/lib/util/index.js.map +0 -1
  155. package/lib/util/map-includes.d.ts +0 -6
  156. package/lib/util/map-includes.d.ts.map +0 -1
  157. package/lib/util/map-includes.js +0 -189
  158. package/lib/util/map-includes.js.map +0 -1
  159. package/lib/util/merge-includes.d.ts +0 -3
  160. package/lib/util/merge-includes.d.ts.map +0 -1
  161. package/lib/util/merge-includes.js +0 -96
  162. package/lib/util/merge-includes.js.map +0 -1
  163. package/src/util/index.ts +0 -26
  164. package/src/util/map-includes.ts +0 -328
  165. package/src/util/merge-includes.ts +0 -121
@@ -1,46 +1,66 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
2
  import { GraphQLResolveInfo } from 'graphql';
3
3
  import {
4
+ CompatibleTypes,
5
+ FieldKind,
4
6
  FieldRef,
5
7
  InputFieldMap,
6
8
  MaybePromise,
7
9
  NormalizeArgs,
8
- ObjectFieldBuilder,
9
10
  ObjectRef,
10
11
  PluginName,
12
+ RootFieldBuilder,
11
13
  SchemaTypes,
14
+ TypeParam,
12
15
  } from '@pothos/core';
13
- import { prismaCursorConnectionQuery, wrapConnectionResult } from './cursors';
14
- import { getLoaderMapping, setLoaderMappings } from './loader-map';
15
- import { ModelLoader } from './model-loader';
16
16
  import { PrismaObjectRef } from './object-ref';
17
17
  import {
18
- getCursorFormatter,
19
- getCursorParser,
20
- getDelegateFromModel,
21
- getFindUniqueForRef,
22
- getRefFromModel,
23
- getRelation,
24
- } from './refs';
25
- import {
26
- PrismaDelegate,
27
18
  PrismaModelTypes,
28
19
  RelatedConnectionOptions,
29
20
  RelatedFieldOptions,
30
21
  RelationCountOptions,
31
22
  ShapeFromConnection,
23
+ VariantFieldOptions,
32
24
  } from './types';
33
- import { queryFromInfo, SELF_RELATION } from './util';
34
- import { VariantFieldOptions } from '.';
25
+ import { prismaCursorConnectionQuery, wrapConnectionResult } from './util/cursors';
26
+ import {
27
+ getCursorFormatter,
28
+ getCursorParser,
29
+ getRefFromModel,
30
+ getRelation,
31
+ } from './util/datamodel';
32
+ import { FieldMap } from './util/relation-map';
33
+
34
+ // Workaround for FieldKind not being extended on Builder classes
35
+ const RootBuilder: {
36
+ // eslint-disable-next-line @typescript-eslint/prefer-function-type
37
+ new <Types extends SchemaTypes, Shape, Kind extends FieldKind>(
38
+ name: string,
39
+ builder: PothosSchemaTypes.SchemaBuilder<Types>,
40
+ kind: FieldKind,
41
+ graphqlKind: PothosSchemaTypes.PothosKindToGraphQLType[FieldKind],
42
+ ): PothosSchemaTypes.RootFieldBuilder<Types, Shape, Kind>;
43
+ } = RootFieldBuilder as never;
35
44
 
36
45
  export class PrismaObjectFieldBuilder<
37
46
  Types extends SchemaTypes,
38
47
  Model extends PrismaModelTypes,
39
48
  NeedsResolve extends boolean,
40
49
  Shape extends object = Model['Shape'],
41
- > extends ObjectFieldBuilder<Types, Shape> {
42
- delegate: PrismaDelegate;
50
+ > extends RootBuilder<Types, Shape, 'PrismaObject'> {
43
51
  model: string;
52
+ prismaFieldMap: FieldMap;
53
+
54
+ exposeBoolean = this.createExpose('Boolean');
55
+ exposeFloat = this.createExpose('Float');
56
+ exposeInt = this.createExpose('Int');
57
+ exposeID = this.createExpose('ID');
58
+ exposeString = this.createExpose('String');
59
+ exposeBooleanList = this.createExpose(['Boolean']);
60
+ exposeFloatList = this.createExpose(['Float']);
61
+ exposeIntList = this.createExpose(['Int']);
62
+ exposeIDList = this.createExpose(['ID']);
63
+ exposeStringList = this.createExpose(['String']);
44
64
 
45
65
  relatedConnection: 'relay' extends PluginName
46
66
  ? <
@@ -97,10 +117,7 @@ export class PrismaObjectFieldBuilder<
97
117
  edgeOptions = {},
98
118
  ) {
99
119
  const relationField = getRelation(this.model, this.builder, name);
100
- const parentRef = getRefFromModel(this.model, this.builder);
101
120
  const ref = options.type ?? getRefFromModel(relationField.type, this.builder);
102
- const findUnique = getFindUniqueForRef(parentRef, this.builder);
103
- const loaderCache = ModelLoader.forModel(this.model, this.builder);
104
121
  let typeName: string | undefined;
105
122
 
106
123
  const formatCursor = getCursorFormatter(relationField.type, this.builder, cursor);
@@ -116,6 +133,24 @@ export class PrismaObjectFieldBuilder<
116
133
  }),
117
134
  });
118
135
 
136
+ const relationSelect = (
137
+ args: object,
138
+ context: object,
139
+ nestedQuery: (query: unknown) => unknown,
140
+ ) => ({
141
+ select: {
142
+ [name]: nestedQuery({
143
+ ...((typeof query === 'function' ? query(args, context) : query) as {}),
144
+ ...prismaCursorConnectionQuery({
145
+ parseCursor,
146
+ maxSize,
147
+ defaultSize,
148
+ args,
149
+ }),
150
+ }),
151
+ },
152
+ });
153
+
119
154
  const fieldRef = (
120
155
  this as unknown as {
121
156
  connection: (...args: unknown[]) => FieldRef<unknown>;
@@ -125,49 +160,40 @@ export class PrismaObjectFieldBuilder<
125
160
  ...options,
126
161
  extensions: {
127
162
  ...extensions,
128
- pothosPrismaQuery: getQuery,
129
- pothosPrismaRelation: name,
163
+ pothosPrismaSelect: relationSelect,
164
+ pothosPrismaLoaded: (value: Record<string, unknown>) => value[name] !== undefined,
165
+ pothosPrismaFallback:
166
+ resolve &&
167
+ ((
168
+ q: { take: number },
169
+ parent: unknown,
170
+ args: PothosSchemaTypes.DefaultConnectionArguments,
171
+ context: {},
172
+ info: GraphQLResolveInfo,
173
+ ) =>
174
+ Promise.resolve(
175
+ resolve(
176
+ {
177
+ ...q,
178
+ ...(typeof query === 'function' ? query(args, context) : query),
179
+ } as never,
180
+ parent,
181
+ args,
182
+ context,
183
+ info,
184
+ ),
185
+ ).then((result) => wrapConnectionResult(result, args, q.take, formatCursor))),
130
186
  },
131
187
  type: ref,
132
- resolve: async (
133
- parent: object,
188
+ resolve: (
189
+ parent: unknown,
134
190
  args: PothosSchemaTypes.DefaultConnectionArguments,
135
191
  context: {},
136
- info: GraphQLResolveInfo,
137
192
  ) => {
138
193
  const connectionQuery = getQuery(args, context);
139
- const getResult = () => {
140
- const mapping = getLoaderMapping(context, info.path);
141
- const loadedValue = (parent as Record<string, unknown>)[name];
142
-
143
- if (
144
- // if we attempted to load the relation, and its missing it will be null
145
- // undefined means that the query was not constructed in a way that requested the relation
146
- loadedValue !== undefined &&
147
- mapping
148
- ) {
149
- if (loadedValue !== null && loadedValue !== undefined) {
150
- setLoaderMappings(context, info.path, mapping);
151
- }
152
-
153
- return loadedValue as {}[];
154
- }
155
-
156
- if (!resolve && !findUnique) {
157
- throw new Error(`Missing findUnique for Prisma type ${this.model}`);
158
- }
159
-
160
- const mergedQuery = { ...queryFromInfo(context, info), ...connectionQuery };
161
-
162
- if (resolve) {
163
- return resolve(mergedQuery, parent, args, context, info);
164
- }
165
-
166
- return loaderCache(parent).loadRelation(name, mergedQuery, context) as Promise<{}[]>;
167
- };
168
194
 
169
195
  return wrapConnectionResult(
170
- await getResult(),
196
+ (parent as Record<string, never>)[name],
171
197
  args,
172
198
  connectionQuery.take,
173
199
  formatCursor,
@@ -180,18 +206,11 @@ export class PrismaObjectFieldBuilder<
180
206
  fields: totalCount
181
207
  ? (t: PothosSchemaTypes.ObjectFieldBuilder<SchemaTypes, { totalCount?: number }>) => ({
182
208
  totalCount: t.int({
209
+ nullable: false,
183
210
  extensions: {
184
- pothosPrismaRelationCountForParent: name,
185
- },
186
- resolve: (parent, args, context) => {
187
- const loadedValue = parent.totalCount;
188
-
189
- if (loadedValue !== undefined) {
190
- return loadedValue;
191
- }
192
-
193
- return loaderCache(parent).loadCount(name, context);
211
+ pothosPrismaParentSelect: { _count: { select: { [name]: true } } },
194
212
  },
213
+ resolve: (parent, args, context) => parent.totalCount,
195
214
  }),
196
215
  ...(connectionOptions as { fields?: (t: unknown) => {} }).fields?.(t),
197
216
  })
@@ -215,11 +234,16 @@ export class PrismaObjectFieldBuilder<
215
234
  return fieldRef;
216
235
  } as never;
217
236
 
218
- constructor(name: string, builder: PothosSchemaTypes.SchemaBuilder<Types>, model: string) {
219
- super(name, builder);
237
+ constructor(
238
+ name: string,
239
+ builder: PothosSchemaTypes.SchemaBuilder<Types>,
240
+ model: string,
241
+ fieldMap: FieldMap,
242
+ ) {
243
+ super(name, builder, 'PrismaObject', 'Object');
220
244
 
221
245
  this.model = model;
222
- this.delegate = getDelegateFromModel(builder.options.prisma.client, model);
246
+ this.prismaFieldMap = fieldMap;
223
247
  }
224
248
 
225
249
  relation<
@@ -246,54 +270,35 @@ export class PrismaObjectFieldBuilder<
246
270
  ): FieldRef<Model['Relations'][Field]['Shape'], 'Object'> {
247
271
  const [name, options = {} as never] = allArgs;
248
272
  const relationField = getRelation(this.model, this.builder, name);
249
- const parentRef = getRefFromModel(this.model, this.builder);
250
273
  const ref = options.type ?? getRefFromModel(relationField.type, this.builder);
251
- const findUnique = getFindUniqueForRef(parentRef, this.builder);
252
- const loaderCache = ModelLoader.forModel(this.model, this.builder);
253
274
 
254
- const { query = {}, resolve, ...rest } = options;
275
+ const { query = {}, resolve, extensions, ...rest } = options;
276
+
277
+ const relationSelect = (
278
+ args: object,
279
+ context: object,
280
+ nestedQuery: (query: unknown) => unknown,
281
+ ) => ({ select: { [name]: nestedQuery(query) } });
255
282
 
256
283
  return this.field({
257
284
  ...rest,
258
285
  type: relationField.isList ? [ref] : ref,
259
286
  extensions: {
260
- ...options.extensions,
261
- pothosPrismaQuery: query,
262
- pothosPrismaRelation: name,
263
- },
264
- resolve: (parent, args, context, info) => {
265
- const mapping = getLoaderMapping(context, info.path);
266
-
267
- const loadedValue = (parent as Record<string, unknown>)[name];
268
-
269
- if (
270
- // if we attempted to load the relation, and its missing it will be null
271
- // undefined means that the query was not constructed in a way that requested the relation
272
- loadedValue !== undefined &&
273
- mapping
274
- ) {
275
- if (loadedValue !== null && loadedValue !== undefined) {
276
- setLoaderMappings(context, info.path, mapping);
277
- }
278
-
279
- return loadedValue as never;
280
- }
281
-
282
- const queryOptions = {
283
- ...((typeof query === 'function' ? query(args, context) : query) as {}),
284
- ...queryFromInfo(context, info),
285
- };
286
-
287
- if (resolve) {
288
- return resolve(queryOptions, parent, args as never, context, info) as never;
289
- }
290
-
291
- if (!findUnique) {
292
- throw new Error(`Missing findUnique for Prisma type ${this.model}`);
293
- }
294
-
295
- return loaderCache(parent).loadRelation(name, queryOptions, context) as never;
287
+ ...extensions,
288
+ pothosPrismaSelect: relationSelect as never,
289
+ pothosPrismaLoaded: (value: Record<string, unknown>) => value[name] !== undefined,
290
+ pothosPrismaFallback:
291
+ resolve &&
292
+ ((q: {}, parent: Shape, args: {}, context: {}, info: GraphQLResolveInfo) =>
293
+ resolve(
294
+ { ...q, ...(typeof query === 'function' ? query(args, context) : query) } as never,
295
+ parent,
296
+ args as never,
297
+ context,
298
+ info,
299
+ )),
296
300
  },
301
+ resolve: (parent) => (parent as Record<string, never>)[name],
297
302
  }) as FieldRef<Model['Relations'][Field]['Shape'], 'Object'>;
298
303
  }
299
304
 
@@ -303,37 +308,22 @@ export class PrismaObjectFieldBuilder<
303
308
  >
304
309
  ): FieldRef<number, 'Object'> {
305
310
  const [name, options = {} as never] = allArgs;
306
- const parentRef = getRefFromModel(this.model, this.builder);
307
- const findUnique = getFindUniqueForRef(parentRef, this.builder);
308
- const loaderCache = ModelLoader.forModel(this.model, this.builder);
309
311
 
310
312
  const { resolve, ...rest } = options;
311
313
 
314
+ const countSelect = {
315
+ _count: {
316
+ select: { [name]: true },
317
+ },
318
+ };
319
+
312
320
  return this.field({
313
321
  ...rest,
314
322
  type: 'Int',
315
323
  nullable: false,
316
- extensions: {
317
- ...options.extensions,
318
- pothosPrismaRelationCount: name,
319
- },
320
- resolve: (parent, args, context, info) => {
321
- const loadedValue = (parent as { _count: Record<string, unknown> })._count?.[name];
322
-
323
- if (loadedValue !== undefined) {
324
- return loadedValue as never;
325
- }
326
-
327
- if (resolve) {
328
- return resolve(parent, args, context, info) as never;
329
- }
330
-
331
- if (!findUnique) {
332
- throw new Error(`Missing findUnique for Prisma type ${this.model}`);
333
- }
334
-
335
- return loaderCache(parent).loadCount(name, context) as never;
336
- },
324
+ select: countSelect as never,
325
+ resolve: (parent, args, context, info) =>
326
+ (parent as unknown as { _count: Record<string, never> })._count?.[name],
337
327
  }) as FieldRef<number, 'Object'>;
338
328
  }
339
329
 
@@ -352,34 +342,87 @@ export class PrismaObjectFieldBuilder<
352
342
  const [variant, options = {} as never] = allArgs;
353
343
  const ref: PrismaObjectRef<PrismaModelTypes> =
354
344
  typeof variant === 'string' ? getRefFromModel(variant, this.builder) : variant;
355
- const parentRef = getRefFromModel(this.model, this.builder);
356
- const findUnique = getFindUniqueForRef(parentRef, this.builder);
357
- const loaderCache = ModelLoader.forModel(this.model, this.builder);
345
+
346
+ const selfSelect = (args: object, context: object, nestedQuery: (query: unknown) => unknown) =>
347
+ nestedQuery({});
358
348
 
359
349
  return this.field({
360
350
  ...options,
361
351
  type: ref,
362
- extensions: {
363
- ...options.extensions,
364
- pothosPrismaRelation: SELF_RELATION,
365
- },
366
- resolve: (parent, args, context, info) => {
367
- const mapping = getLoaderMapping(context, info.path);
352
+ select: selfSelect as never,
353
+ resolve: (parent, args, context, info) => parent,
354
+ }) as FieldRef<Model['Shape'], 'Object'>;
355
+ }
368
356
 
369
- if (mapping) {
370
- setLoaderMappings(context, info.path, mapping);
357
+ expose<
358
+ Type extends TypeParam<Types>,
359
+ Nullable extends boolean,
360
+ ResolveReturnShape,
361
+ Name extends CompatibleTypes<Types, Model['Shape'], Type, Nullable>,
362
+ >(
363
+ ...args: NormalizeArgs<
364
+ [
365
+ name: Name,
366
+ options?: Omit<
367
+ PothosSchemaTypes.ObjectFieldOptions<
368
+ Types,
369
+ Shape,
370
+ Type,
371
+ Nullable,
372
+ {},
373
+ ResolveReturnShape
374
+ >,
375
+ 'resolve' | 'select'
376
+ >,
377
+ ]
378
+ >
379
+ ) {
380
+ const [name, options = {} as never] = args;
371
381
 
372
- return parent as never;
373
- }
382
+ const typeConfig = this.builder.configStore.getTypeConfig(this.typename, 'Object');
383
+ const usingSelect = !!typeConfig.extensions?.pothosPrismaSelect;
374
384
 
375
- const queryOptions = queryFromInfo(context, info);
385
+ return this.exposeField(name as never, {
386
+ ...options,
387
+ extensions: {
388
+ ...options.extensions,
389
+ pothosPrismaVariant: name,
390
+ pothosPrismaSelect: usingSelect && {
391
+ [name]: true,
392
+ },
393
+ },
394
+ });
395
+ }
376
396
 
377
- if (!findUnique) {
378
- throw new Error(`Missing findUnique for Prisma type ${this.model}`);
379
- }
397
+ private createExpose<Type extends TypeParam<Types>>(type: Type) {
398
+ return <
399
+ Nullable extends boolean,
400
+ ResolveReturnShape,
401
+ Name extends CompatibleTypes<Types, Model['Shape'], Type, Nullable>,
402
+ >(
403
+ ...args: NormalizeArgs<
404
+ [
405
+ name: Name,
406
+ options?: Omit<
407
+ PothosSchemaTypes.ObjectFieldOptions<
408
+ Types,
409
+ Shape,
410
+ Type,
411
+ Nullable,
412
+ {},
413
+ ResolveReturnShape
414
+ >,
415
+ 'resolve' | 'type' | 'select'
416
+ >,
417
+ ]
418
+ >
419
+ ) => {
420
+ const [name, options = {} as never] = args;
380
421
 
381
- return loaderCache(parent).loadSelf(queryOptions, context) as never;
382
- },
383
- }) as FieldRef<Model['Shape'], 'Object'>;
422
+ return this.expose(name as never, {
423
+ ...options,
424
+ type,
425
+ });
426
+ };
384
427
  }
385
428
  }
@@ -10,21 +10,22 @@ import SchemaBuilder, {
10
10
  TypeParam,
11
11
  } from '@pothos/core';
12
12
  import { PrismaObjectFieldBuilder } from './field-builder';
13
+ import { ModelLoader } from './model-loader';
13
14
  import PrismaNodeRef from './node-ref';
14
- import { getDelegateFromModel, getRefFromModel, setFindUniqueForRef } from './refs';
15
- import { ModelTypes, PrismaDelegate, PrismaNodeOptions } from './types';
16
- import { queryFromInfo } from './util';
15
+ import { PrismaModelTypes, PrismaNodeOptions } from './types';
16
+ import { getDelegateFromModel, getRefFromModel } from './util/datamodel';
17
+ import { queryFromInfo } from './util/map-query';
18
+ import { getRelationMap } from './util/relation-map';
17
19
 
18
20
  const schemaBuilderProto = SchemaBuilder.prototype as PothosSchemaTypes.SchemaBuilder<SchemaTypes>;
19
21
 
20
22
  schemaBuilderProto.prismaObject = function prismaObject(type, { fields, findUnique, ...options }) {
21
23
  const ref = options.variant ? this.objectRef(options.variant) : getRefFromModel(type, this);
22
24
  const name = options.variant ?? options.name ?? type;
25
+ const fieldMap = getRelationMap(this.options.prisma.client).get(type)!;
23
26
 
24
27
  ref.name = name;
25
28
 
26
- setFindUniqueForRef(ref, this, findUnique);
27
-
28
29
  this.objectType(ref, {
29
30
  ...(options as {} as PothosSchemaTypes.ObjectFieldOptions<
30
31
  SchemaTypes,
@@ -38,9 +39,29 @@ schemaBuilderProto.prismaObject = function prismaObject(type, { fields, findUniq
38
39
  ...options.extensions,
39
40
  pothosPrismaInclude: options.include,
40
41
  pothosPrismaModel: type,
42
+ pothosPrismaFieldMap: fieldMap,
43
+ pothosPrismaSelect: options.select,
44
+ pothosPrismaLoader: ModelLoader.forRef(
45
+ type,
46
+ (findUnique as never) ||
47
+ (() => {
48
+ throw new Error(`Missing findUnique for ${ref.name}`);
49
+ }),
50
+ this,
51
+ ),
41
52
  },
42
53
  name,
43
- fields: fields ? () => fields(new PrismaObjectFieldBuilder(name, this, type)) : undefined,
54
+ fields: fields
55
+ ? () =>
56
+ fields(
57
+ new PrismaObjectFieldBuilder(
58
+ name,
59
+ this,
60
+ type,
61
+ getRelationMap(this.options.prisma.client).get(type)!,
62
+ ),
63
+ )
64
+ : undefined,
44
65
  });
45
66
 
46
67
  return ref as never;
@@ -56,7 +77,7 @@ schemaBuilderProto.prismaNode = function prismaNode(
56
77
  name,
57
78
  variant,
58
79
  ...options
59
- }: PrismaNodeOptions<SchemaTypes, ModelTypes<PrismaDelegate>, [], never, {}>,
80
+ }: PrismaNodeOptions<SchemaTypes, PrismaModelTypes, [], never, {}, {}>,
60
81
  ) {
61
82
  const interfaceRef = this.nodeInterfaceRef?.();
62
83