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