@pothos/plugin-prisma 3.35.8 → 3.37.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 (118) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +247 -39
  3. package/dts/connection-helpers.d.ts +40 -0
  4. package/dts/connection-helpers.d.ts.map +1 -0
  5. package/dts/global-types.d.ts +15 -6
  6. package/dts/global-types.d.ts.map +1 -1
  7. package/dts/index.d.ts +4 -1
  8. package/dts/index.d.ts.map +1 -1
  9. package/dts/node-ref.d.ts +1 -1
  10. package/dts/node-ref.d.ts.map +1 -1
  11. package/dts/object-ref.d.ts +2 -0
  12. package/dts/object-ref.d.ts.map +1 -1
  13. package/dts/prisma-field-builder.d.ts +7 -4
  14. package/dts/prisma-field-builder.d.ts.map +1 -1
  15. package/dts/types.d.ts +35 -33
  16. package/dts/types.d.ts.map +1 -1
  17. package/dts/util/cursors.d.ts +11 -5
  18. package/dts/util/cursors.d.ts.map +1 -1
  19. package/dts/util/map-query.d.ts.map +1 -1
  20. package/dts/util/relation-map.d.ts +1 -1
  21. package/dts/util/relation-map.d.ts.map +1 -1
  22. package/dts/util/selections.d.ts +1 -1
  23. package/dts/util/selections.d.ts.map +1 -1
  24. package/esm/connection-helpers.d.ts +40 -0
  25. package/esm/connection-helpers.d.ts.map +1 -0
  26. package/esm/connection-helpers.js +58 -0
  27. package/esm/connection-helpers.js.map +1 -0
  28. package/esm/field-builder.js +19 -25
  29. package/esm/field-builder.js.map +1 -1
  30. package/esm/generator.js +4 -4
  31. package/esm/generator.js.map +1 -1
  32. package/esm/global-types.d.ts +15 -6
  33. package/esm/global-types.d.ts.map +1 -1
  34. package/esm/global-types.js.map +1 -1
  35. package/esm/index.d.ts +4 -1
  36. package/esm/index.d.ts.map +1 -1
  37. package/esm/index.js +8 -5
  38. package/esm/index.js.map +1 -1
  39. package/esm/model-loader.js +9 -9
  40. package/esm/model-loader.js.map +1 -1
  41. package/esm/node-ref.d.ts +1 -1
  42. package/esm/node-ref.d.ts.map +1 -1
  43. package/esm/node-ref.js +1 -1
  44. package/esm/node-ref.js.map +1 -1
  45. package/esm/object-ref.d.ts +2 -0
  46. package/esm/object-ref.d.ts.map +1 -1
  47. package/esm/object-ref.js +4 -0
  48. package/esm/object-ref.js.map +1 -1
  49. package/esm/prisma-field-builder.d.ts +7 -4
  50. package/esm/prisma-field-builder.d.ts.map +1 -1
  51. package/esm/prisma-field-builder.js +14 -14
  52. package/esm/prisma-field-builder.js.map +1 -1
  53. package/esm/schema-builder.js +31 -16
  54. package/esm/schema-builder.js.map +1 -1
  55. package/esm/types.d.ts +35 -33
  56. package/esm/types.d.ts.map +1 -1
  57. package/esm/util/cursors.d.ts +11 -5
  58. package/esm/util/cursors.d.ts.map +1 -1
  59. package/esm/util/cursors.js +33 -29
  60. package/esm/util/cursors.js.map +1 -1
  61. package/esm/util/datamodel.js +1 -1
  62. package/esm/util/datamodel.js.map +1 -1
  63. package/esm/util/get-client.js +2 -2
  64. package/esm/util/get-client.js.map +1 -1
  65. package/esm/util/loader-map.js +2 -2
  66. package/esm/util/loader-map.js.map +1 -1
  67. package/esm/util/map-query.d.ts.map +1 -1
  68. package/esm/util/map-query.js +38 -38
  69. package/esm/util/map-query.js.map +1 -1
  70. package/esm/util/relation-map.d.ts +1 -1
  71. package/esm/util/relation-map.d.ts.map +1 -1
  72. package/esm/util/selections.d.ts +1 -1
  73. package/esm/util/selections.d.ts.map +1 -1
  74. package/esm/util/selections.js +2 -2
  75. package/esm/util/selections.js.map +1 -1
  76. package/lib/connection-helpers.js +73 -0
  77. package/lib/connection-helpers.js.map +1 -0
  78. package/lib/field-builder.js +18 -24
  79. package/lib/field-builder.js.map +1 -1
  80. package/lib/generator.js +4 -4
  81. package/lib/generator.js.map +1 -1
  82. package/lib/index.js +11 -5
  83. package/lib/index.js.map +1 -1
  84. package/lib/model-loader.js +9 -9
  85. package/lib/model-loader.js.map +1 -1
  86. package/lib/node-ref.js +1 -1
  87. package/lib/node-ref.js.map +1 -1
  88. package/lib/object-ref.js +4 -0
  89. package/lib/object-ref.js.map +1 -1
  90. package/lib/prisma-field-builder.js +13 -13
  91. package/lib/prisma-field-builder.js.map +1 -1
  92. package/lib/schema-builder.js +31 -21
  93. package/lib/schema-builder.js.map +1 -1
  94. package/lib/util/cursors.js +33 -29
  95. package/lib/util/cursors.js.map +1 -1
  96. package/lib/util/datamodel.js +1 -1
  97. package/lib/util/datamodel.js.map +1 -1
  98. package/lib/util/get-client.js +2 -2
  99. package/lib/util/get-client.js.map +1 -1
  100. package/lib/util/loader-map.js +2 -2
  101. package/lib/util/loader-map.js.map +1 -1
  102. package/lib/util/map-query.js +38 -37
  103. package/lib/util/map-query.js.map +1 -1
  104. package/lib/util/selections.js +2 -2
  105. package/lib/util/selections.js.map +1 -1
  106. package/package.json +10 -10
  107. package/src/connection-helpers.ts +122 -0
  108. package/src/field-builder.ts +23 -23
  109. package/src/global-types.ts +50 -14
  110. package/src/index.ts +3 -0
  111. package/src/node-ref.ts +1 -4
  112. package/src/object-ref.ts +7 -0
  113. package/src/prisma-field-builder.ts +38 -25
  114. package/src/schema-builder.ts +38 -3
  115. package/src/types.ts +35 -16
  116. package/src/util/cursors.ts +8 -1
  117. package/src/util/datamodel.ts +1 -1
  118. package/src/util/map-query.ts +32 -17
@@ -0,0 +1,122 @@
1
+ import { ObjectRef, SchemaTypes } from '@pothos/core';
2
+ import { ModelLoader } from './model-loader';
3
+ import { PrismaObjectRef } from './object-ref';
4
+ import type { PrismaModelTypes, ShapeFromSelection } from './types';
5
+ import {
6
+ getCursorFormatter,
7
+ getCursorParser,
8
+ prismaCursorConnectionQuery,
9
+ wrapConnectionResult,
10
+ } from './util/cursors';
11
+ import { getRefFromModel } from './util/datamodel';
12
+ import { getDMMF } from './util/get-client';
13
+ import { getRelationMap } from './util/relation-map';
14
+ import { createState, mergeSelection, selectionToQuery } from './util/selections';
15
+
16
+ export const prismaModelKey = Symbol.for('Pothos.prismaModelKey');
17
+
18
+ export function prismaConnectionHelpers<
19
+ Types extends SchemaTypes,
20
+ RefOrType extends PrismaObjectRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
21
+ Select extends Model['Select'] & {},
22
+ Model extends PrismaModelTypes = RefOrType extends PrismaObjectRef<infer T>
23
+ ? T & PrismaModelTypes
24
+ : Types['PrismaTypes'][RefOrType & keyof Types['PrismaTypes']] & PrismaModelTypes,
25
+ Shape = RefOrType extends PrismaObjectRef<PrismaModelTypes, infer T> ? T : Model['Shape'],
26
+ EdgeShape = Model['Include'] extends Select
27
+ ? Shape
28
+ : ShapeFromSelection<Model, { select: Select }>,
29
+ NodeShape = EdgeShape,
30
+ >(
31
+ builder: PothosSchemaTypes.SchemaBuilder<Types>,
32
+ refOrType: RefOrType,
33
+ options: {
34
+ cursor: string & keyof Model['WhereUnique'];
35
+ select?: (nestedSelection: <T extends {} | true>(selection?: T) => T) => Select;
36
+ defaultSize?:
37
+ | number
38
+ | ((args: PothosSchemaTypes.DefaultConnectionArguments, ctx: {}) => number);
39
+ maxSize?: number | ((args: PothosSchemaTypes.DefaultConnectionArguments, ctx: {}) => number);
40
+ resolveNode?: (edge: EdgeShape) => NodeShape;
41
+ },
42
+ ) {
43
+ const modelName =
44
+ typeof refOrType === 'string' ? refOrType : (refOrType as PrismaObjectRef<Model>).modelName;
45
+ const ref =
46
+ typeof refOrType === 'string'
47
+ ? getRefFromModel(modelName, builder)
48
+ : (refOrType as ObjectRef<unknown>);
49
+ const formatCursor = getCursorFormatter(modelName, builder, options.cursor);
50
+ const parseCursor = getCursorParser(modelName, builder, options.cursor);
51
+ const cursorSelection = ModelLoader.getCursorSelection(ref, modelName, options.cursor, builder);
52
+ const fieldMap = getRelationMap(getDMMF(builder)).get(modelName)!;
53
+
54
+ function resolve(
55
+ list: (EdgeShape & {})[],
56
+ args: PothosSchemaTypes.DefaultConnectionArguments,
57
+ ctx: Types['Context'],
58
+ ) {
59
+ return wrapConnectionResult(
60
+ list,
61
+ args,
62
+ getQueryArgs(args, ctx).take,
63
+ formatCursor,
64
+ null,
65
+ (options?.resolveNode as never) ?? ((edge: unknown) => edge),
66
+ ) as unknown as {
67
+ edges: (Omit<EdgeShape, 'cursor' | 'node'> & { node: NodeShape; cursor: string })[];
68
+ pageInfo: {
69
+ startCursor: string | null;
70
+ endCursor: string | null;
71
+ hasPreviousPage: boolean;
72
+ hasNextPage: boolean;
73
+ };
74
+ };
75
+ }
76
+
77
+ function getQueryArgs(args: PothosSchemaTypes.DefaultConnectionArguments, ctx: Types['Context']) {
78
+ return prismaCursorConnectionQuery({
79
+ args,
80
+ ctx,
81
+ maxSize: typeof options.maxSize === 'function' ? options.maxSize(args, ctx) : options.maxSize,
82
+ defaultSize:
83
+ typeof options.defaultSize === 'function'
84
+ ? options.defaultSize(args, ctx)
85
+ : options.defaultSize,
86
+ parseCursor,
87
+ });
88
+ }
89
+
90
+ function getQuery(
91
+ args: PothosSchemaTypes.DefaultConnectionArguments,
92
+ ctx: Types['Context'],
93
+ nestedSelection: <T extends true | {}>(selection?: T, path?: string[]) => T,
94
+ ) {
95
+ const nestedSelect: Record<string, unknown> | true = options.select
96
+ ? { select: options.select((sel) => nestedSelection(sel, ['edges', 'node'])) }
97
+ : nestedSelection(true, ['edges', 'node']);
98
+
99
+ const selectState = createState(fieldMap, 'select');
100
+
101
+ mergeSelection(selectState, { select: cursorSelection });
102
+
103
+ if (typeof nestedSelect === 'object' && nestedSelect) {
104
+ mergeSelection(selectState, nestedSelect);
105
+ }
106
+
107
+ return {
108
+ ...getQueryArgs(args, ctx),
109
+ ...selectionToQuery(selectState),
110
+ } as unknown as ReturnType<typeof getQueryArgs> &
111
+ (Model['Select'] extends Select ? {} : { select: Select });
112
+ }
113
+
114
+ return {
115
+ ref: (typeof refOrType === 'string'
116
+ ? getRefFromModel(refOrType, builder)
117
+ : refOrType) as PrismaObjectRef<Model>,
118
+ resolve,
119
+ select: options.select ?? {},
120
+ getQuery,
121
+ };
122
+ }
@@ -123,6 +123,8 @@ fieldBuilderProto.prismaConnection = function prismaConnection<
123
123
  context,
124
124
  info,
125
125
  select: cursorSelection as {},
126
+ path: ['edges', 'node'],
127
+ typeName,
126
128
  }),
127
129
  ctx: context,
128
130
  parseCursor,
@@ -135,30 +137,28 @@ fieldBuilderProto.prismaConnection = function prismaConnection<
135
137
  (query) => resolve(query as never, parent, args as never, context, info) as never,
136
138
  ),
137
139
  },
138
- {
139
- ...connectionOptions,
140
- fields: totalCount
141
- ? (
142
- t: PothosSchemaTypes.ObjectFieldBuilder<
143
- SchemaTypes,
144
- { totalCount?: () => MaybePromise<number> }
145
- >,
146
- ) => ({
147
- totalCount: t.int({
148
- nullable: false,
149
- resolve: (parent, args, context) => parent.totalCount?.(),
150
- }),
151
- ...(connectionOptions as { fields?: (t: unknown) => {} }).fields?.(t),
152
- })
153
- : (connectionOptions as { fields: undefined }).fields,
154
- extensions: {
155
- ...(connectionOptions as Record<string, {}> | undefined)?.extensions,
156
- pothosPrismaIndirectInclude: {
157
- getType: () => typeName,
158
- path: [{ name: 'edges' }, { name: 'node' }],
140
+ connectionOptions instanceof ObjectRef
141
+ ? connectionOptions
142
+ : {
143
+ ...connectionOptions,
144
+ fields: totalCount
145
+ ? (
146
+ t: PothosSchemaTypes.ObjectFieldBuilder<
147
+ SchemaTypes,
148
+ { totalCount?: () => MaybePromise<number> }
149
+ >,
150
+ ) => ({
151
+ totalCount: t.int({
152
+ nullable: false,
153
+ resolve: (parent, args, context) => parent.totalCount?.(),
154
+ }),
155
+ ...(connectionOptions as { fields?: (t: unknown) => {} }).fields?.(t),
156
+ })
157
+ : (connectionOptions as { fields: undefined }).fields,
158
+ extensions: {
159
+ ...(connectionOptions as Record<string, {}> | undefined)?.extensions,
160
+ },
159
161
  },
160
- },
161
- },
162
162
  edgeOptions,
163
163
  );
164
164
 
@@ -2,6 +2,7 @@
2
2
  /* eslint-disable @typescript-eslint/no-empty-interface */
3
3
  import {
4
4
  FieldKind,
5
+ FieldMap,
5
6
  FieldNullability,
6
7
  FieldRef,
7
8
  InputFieldMap,
@@ -14,7 +15,7 @@ import {
14
15
  ShapeFromTypeParam,
15
16
  TypeParam,
16
17
  } from '@pothos/core';
17
- import PrismaNodeRef from './node-ref';
18
+ import { PrismaNodeRef } from './node-ref';
18
19
  import { prismaModelKey, PrismaObjectRef } from './object-ref';
19
20
  import { PrismaObjectFieldBuilder as InternalPrismaObjectFieldBuilder } from './prisma-field-builder';
20
21
  import {
@@ -22,6 +23,7 @@ import {
22
23
  PrismaConnectionFieldOptions,
23
24
  PrismaFieldOptions,
24
25
  PrismaFieldWithInputOptions,
26
+ prismaModelName,
25
27
  PrismaModelTypes,
26
28
  PrismaNodeOptions,
27
29
  PrismaObjectFieldOptions,
@@ -116,6 +118,37 @@ declare global {
116
118
  >,
117
119
  ) => PrismaObjectRef<Model, ShapeFromSelection<Model, { select: Select; include: Include }>>;
118
120
 
121
+ prismaObjectField: <
122
+ Type extends PrismaObjectRef<PrismaModelTypes, {}> | keyof Types['PrismaTypes'],
123
+ Model extends PrismaModelTypes = Type extends PrismaObjectRef<infer M, {}>
124
+ ? M
125
+ : Types['PrismaTypes'][Type & keyof Types['PrismaTypes']] & PrismaModelTypes,
126
+ Shape extends {} = Type extends PrismaObjectRef<PrismaModelTypes, infer S>
127
+ ? S
128
+ : Model['Shape'] & {
129
+ [prismaModelName]?: Type;
130
+ },
131
+ >(
132
+ type: Type,
133
+ fieldName: string,
134
+ field: (t: PrismaObjectFieldBuilder<Types, Model, false, Shape>) => FieldRef,
135
+ ) => void;
136
+
137
+ prismaObjectFields: <
138
+ Type extends PrismaObjectRef<PrismaModelTypes, {}> | keyof Types['PrismaTypes'],
139
+ Model extends PrismaModelTypes = Type extends PrismaObjectRef<infer M, {}>
140
+ ? M
141
+ : Types['PrismaTypes'][Type & keyof Types['PrismaTypes']] & PrismaModelTypes,
142
+ Shape extends {} = Type extends PrismaObjectRef<PrismaModelTypes, infer S>
143
+ ? S
144
+ : Model['Shape'] & {
145
+ [prismaModelName]?: Type;
146
+ },
147
+ >(
148
+ type: Type,
149
+ fields: (t: PrismaObjectFieldBuilder<Types, Model, false, Shape>) => FieldMap,
150
+ ) => void;
151
+
119
152
  prismaNode: 'relay' extends PluginName
120
153
  ? <
121
154
  Name extends keyof Types['PrismaTypes'],
@@ -199,6 +232,7 @@ declare global {
199
232
  Model extends PrismaModelTypes = Type extends PrismaObjectRef<infer T>
200
233
  ? T
201
234
  : PrismaModelTypes & Types['PrismaTypes'][Type & keyof Types['PrismaTypes']],
235
+ Shape = Type extends PrismaObjectRef<PrismaModelTypes, infer S> ? S : Model['Shape'],
202
236
  >(
203
237
  options: PrismaConnectionFieldOptions<
204
238
  Types,
@@ -213,19 +247,21 @@ declare global {
213
247
  >,
214
248
  ...args: NormalizeArgs<
215
249
  [
216
- connectionOptions: ConnectionObjectOptions<
217
- Types,
218
- ObjectRef<Model['Shape']>,
219
- false,
220
- false,
221
- ResolveReturnShape
222
- >,
223
- edgeOptions: ConnectionEdgeObjectOptions<
224
- Types,
225
- ObjectRef<Model['Shape']>,
226
- false,
227
- ResolveReturnShape
228
- >,
250
+ connectionOptions:
251
+ | ConnectionObjectOptions<
252
+ Types,
253
+ ObjectRef<Shape>,
254
+ false,
255
+ false,
256
+ ResolveReturnShape
257
+ >
258
+ | ObjectRef<ShapeFromConnection<ConnectionShapeHelper<Types, Shape, false>>>,
259
+ edgeOptions:
260
+ | ConnectionEdgeObjectOptions<Types, ObjectRef<Shape>, false, ResolveReturnShape>
261
+ | ObjectRef<{
262
+ cursor: string;
263
+ node?: Shape | null | undefined;
264
+ }>,
229
265
  ],
230
266
  0
231
267
  >
package/src/index.ts CHANGED
@@ -13,6 +13,9 @@ import { PrismaModelTypes } from './types';
13
13
  import { getLoaderMapping, setLoaderMappings } from './util/loader-map';
14
14
  import { queryFromInfo, selectionStateFromInfo } from './util/map-query';
15
15
 
16
+ export { prismaConnectionHelpers } from './connection-helpers';
17
+ export { PrismaNodeRef } from './node-ref';
18
+ export { PrismaObjectRef } from './object-ref';
16
19
  export * from './types';
17
20
 
18
21
  const pluginName = 'prisma' as const;
package/src/node-ref.ts CHANGED
@@ -1,7 +1,4 @@
1
1
  import { PrismaObjectRef } from './object-ref';
2
2
  import type { PrismaModelTypes } from './types';
3
3
 
4
- export default class PrismaNodeRef<Model extends PrismaModelTypes, T> extends PrismaObjectRef<
5
- Model,
6
- T
7
- > {}
4
+ export class PrismaNodeRef<Model extends PrismaModelTypes, T> extends PrismaObjectRef<Model, T> {}
package/src/object-ref.ts CHANGED
@@ -6,6 +6,13 @@ export const prismaModelKey = Symbol.for('Pothos.prismaModelKey');
6
6
  export class PrismaObjectRef<Model extends PrismaModelTypes, T = {}> extends ObjectRef<T> {
7
7
  [prismaModelKey]!: Model;
8
8
  [abstractReturnShapeKey]!: WithBrand<T>;
9
+ modelName: string;
10
+
11
+ constructor(name: string, modelName: string) {
12
+ super(name);
13
+
14
+ this.modelName = modelName;
15
+ }
9
16
 
10
17
  addBrand<V extends T | T[]>(
11
18
  value: V,
@@ -111,19 +111,28 @@ export class PrismaObjectFieldBuilder<
111
111
  options: RelatedConnectionOptions<Types, Model, Field, Nullable, Args, NeedsResolve>,
112
112
  ...args: NormalizeArgs<
113
113
  [
114
- connectionOptions: PothosSchemaTypes.ConnectionObjectOptions<
115
- Types,
116
- ObjectRef<Shape>,
117
- false,
118
- false,
119
- ResolveReturnShape
120
- >,
121
- edgeOptions: PothosSchemaTypes.ConnectionEdgeObjectOptions<
122
- Types,
123
- ObjectRef<Shape>,
124
- false,
125
- ResolveReturnShape
126
- >,
114
+ connectionOptions:
115
+ | PothosSchemaTypes.ConnectionObjectOptions<
116
+ Types,
117
+ ObjectRef<Shape>,
118
+ false,
119
+ false,
120
+ ResolveReturnShape
121
+ >
122
+ | ObjectRef<
123
+ ShapeFromConnection<PothosSchemaTypes.ConnectionShapeHelper<Types, Shape, false>>
124
+ >,
125
+ edgeOptions:
126
+ | PothosSchemaTypes.ConnectionEdgeObjectOptions<
127
+ Types,
128
+ ObjectRef<Shape>,
129
+ false,
130
+ ResolveReturnShape
131
+ >
132
+ | ObjectRef<{
133
+ cursor: string;
134
+ node?: ShapeFromTypeParam<Types, Model['Shape'], false>;
135
+ }>,
127
136
  ],
128
137
  0
129
138
  >
@@ -272,18 +281,22 @@ export class PrismaObjectFieldBuilder<
272
281
  );
273
282
  },
274
283
  },
275
- {
276
- ...connectionOptions,
277
- fields: totalCount
278
- ? (t: PothosSchemaTypes.ObjectFieldBuilder<SchemaTypes, { totalCount?: number }>) => ({
279
- totalCount: t.int({
280
- nullable: false,
281
- resolve: (parent, args, context) => parent.totalCount,
282
- }),
283
- ...(connectionOptions as { fields?: (t: unknown) => {} }).fields?.(t),
284
- })
285
- : (connectionOptions as { fields: undefined }).fields,
286
- },
284
+ connectionOptions instanceof ObjectRef
285
+ ? connectionOptions
286
+ : {
287
+ ...connectionOptions,
288
+ fields: totalCount
289
+ ? (
290
+ t: PothosSchemaTypes.ObjectFieldBuilder<SchemaTypes, { totalCount?: number }>,
291
+ ) => ({
292
+ totalCount: t.int({
293
+ nullable: false,
294
+ resolve: (parent, args, context) => parent.totalCount,
295
+ }),
296
+ ...(connectionOptions as { fields?: (t: unknown) => {} }).fields?.(t),
297
+ })
298
+ : (connectionOptions as { fields: undefined }).fields,
299
+ },
287
300
  edgeOptions,
288
301
  );
289
302
 
@@ -9,7 +9,8 @@ import SchemaBuilder, {
9
9
  } from '@pothos/core';
10
10
  import { PrismaObjectFieldBuilder } from './field-builder';
11
11
  import { ModelLoader } from './model-loader';
12
- import PrismaNodeRef from './node-ref';
12
+ import { PrismaNodeRef } from './node-ref';
13
+ import { PrismaObjectRef } from './object-ref';
13
14
  import { PrismaModelTypes, PrismaNodeOptions } from './types';
14
15
  import { getDefaultIDParser, getDefaultIDSerializer } from './util/cursors';
15
16
  import { getDelegateFromModel, getRefFromModel } from './util/datamodel';
@@ -24,7 +25,9 @@ schemaBuilderProto.prismaObject = function prismaObject(
24
25
  type,
25
26
  { fields, findUnique, select, include, description, ...options },
26
27
  ) {
27
- const ref = options.variant ? this.objectRef(options.variant) : getRefFromModel(type, this);
28
+ const ref = options.variant
29
+ ? new PrismaObjectRef(options.variant, type)
30
+ : getRefFromModel(type, this);
28
31
  const name = options.variant ?? options.name ?? type;
29
32
  const fieldMap = getRelationMap(getDMMF(this)).get(type)!;
30
33
  const idSelection = ModelLoader.getDefaultIDSelection(ref, type, this);
@@ -77,7 +80,7 @@ schemaBuilderProto.prismaNode = function prismaNode(
77
80
  const resolve = rawResolve ?? getDefaultIDSerializer(type, fieldName, this);
78
81
  const idParser = fieldName ? getDefaultIDParser(type, fieldName, this) : undefined;
79
82
  const typeName = variant ?? name ?? type;
80
- const nodeRef = new PrismaNodeRef(typeName);
83
+ const nodeRef = new PrismaNodeRef(typeName, type);
81
84
  const findUnique = rawFindUnique
82
85
  ? (parent: unknown, context: {}) =>
83
86
  rawFindUnique(resolve(parent as never, context) as string, context)
@@ -156,3 +159,35 @@ schemaBuilderProto.prismaNode = function prismaNode(
156
159
 
157
160
  return nodeRef;
158
161
  } as never;
162
+
163
+ schemaBuilderProto.prismaObjectField = function prismaObjectField(type, fieldName, field) {
164
+ const ref = typeof type === 'string' ? getRefFromModel(type, this) : type;
165
+ this.configStore.onTypeConfig(ref, ({ name }) => {
166
+ this.configStore.addFields(ref, () => ({
167
+ [fieldName]: field(
168
+ new PrismaObjectFieldBuilder(
169
+ name,
170
+ this,
171
+ ref.modelName,
172
+ getRelationMap(getDMMF(this)).get(ref.modelName)!,
173
+ ),
174
+ ),
175
+ }));
176
+ });
177
+ };
178
+
179
+ schemaBuilderProto.prismaObjectFields = function prismaObjectFields(type, fields) {
180
+ const ref = typeof type === 'string' ? getRefFromModel(type, this) : type;
181
+ this.configStore.onTypeConfig(ref, ({ name }) => {
182
+ this.configStore.addFields(ref, () =>
183
+ fields(
184
+ new PrismaObjectFieldBuilder(
185
+ name,
186
+ this,
187
+ ref.modelName,
188
+ getRelationMap(getDMMF(this)).get(ref.modelName)!,
189
+ ),
190
+ ),
191
+ );
192
+ });
193
+ };
package/src/types.ts CHANGED
@@ -151,29 +151,15 @@ type RelationShapeFromInclude<Model extends PrismaModelTypes, Include> = Normali
151
151
  : unknown;
152
152
  }>;
153
153
 
154
- export type PrismaObjectTypeOptions<
154
+ export type PrismaObjectRefOptions<
155
155
  Types extends SchemaTypes,
156
156
  Model extends PrismaModelTypes,
157
- Interfaces extends InterfaceParam<Types>[],
158
157
  FindUnique,
159
158
  Include,
160
159
  Select,
161
160
  Shape extends object,
162
161
  > = NameOrVariant &
163
- Omit<
164
- | PothosSchemaTypes.ObjectTypeOptions<Types, Shape>
165
- | PothosSchemaTypes.ObjectTypeWithInterfaceOptions<Types, Shape, Interfaces>,
166
- 'fields' | 'description'
167
- > & {
168
- description?: string | false;
169
- fields?: PrismaObjectFieldsShape<
170
- Types,
171
- Model,
172
- FindUnique extends null ? true : false,
173
- Shape & (FindUnique extends null ? {} : { [prismaModelName]?: Model['Name'] }),
174
- Select
175
- >;
176
- } & (
162
+ (
177
163
  | {
178
164
  include?: Include & Model['Include'];
179
165
  select?: never;
@@ -187,6 +173,39 @@ export type PrismaObjectTypeOptions<
187
173
  }
188
174
  );
189
175
 
176
+ export type PrismaObjectImplementationOptions<
177
+ Types extends SchemaTypes,
178
+ Model extends PrismaModelTypes,
179
+ Interfaces extends InterfaceParam<Types>[],
180
+ FindUnique,
181
+ Select,
182
+ Shape extends object,
183
+ > = Omit<
184
+ | PothosSchemaTypes.ObjectTypeOptions<Types, Shape>
185
+ | PothosSchemaTypes.ObjectTypeWithInterfaceOptions<Types, Shape, Interfaces>,
186
+ 'fields' | 'description'
187
+ > & {
188
+ description?: string | false;
189
+ fields?: PrismaObjectFieldsShape<
190
+ Types,
191
+ Model,
192
+ FindUnique extends null ? true : false,
193
+ Shape & (FindUnique extends null ? {} : { [prismaModelName]?: Model['Name'] }),
194
+ Select
195
+ >;
196
+ };
197
+
198
+ export type PrismaObjectTypeOptions<
199
+ Types extends SchemaTypes,
200
+ Model extends PrismaModelTypes,
201
+ Interfaces extends InterfaceParam<Types>[],
202
+ FindUnique,
203
+ Include,
204
+ Select,
205
+ Shape extends object,
206
+ > = PrismaObjectRefOptions<Types, Model, FindUnique, Include, Select, Shape> &
207
+ PrismaObjectImplementationOptions<Types, Model, Interfaces, FindUnique, Select, Shape>;
208
+
190
209
  type NameOrVariant =
191
210
  | {
192
211
  name?: never;
@@ -261,7 +261,8 @@ export function wrapConnectionResult<T extends {}>(
261
261
  args: PothosSchemaTypes.DefaultConnectionArguments,
262
262
  take: number,
263
263
  cursor: (node: T) => string,
264
- totalCount?: number | (() => MaybePromise<number>),
264
+ totalCount?: null | number | (() => MaybePromise<number>),
265
+ resolveNode?: (node: unknown) => unknown,
265
266
  ) {
266
267
  const gotFullResults = results.length === Math.abs(take);
267
268
  const hasNextPage = args.before ? true : gotFullResults;
@@ -273,6 +274,12 @@ export function wrapConnectionResult<T extends {}>(
273
274
  const edges = nodes.map((value, index) =>
274
275
  value == null
275
276
  ? null
277
+ : resolveNode
278
+ ? {
279
+ ...value,
280
+ cursor: cursor(value),
281
+ node: resolveNode(value),
282
+ }
276
283
  : {
277
284
  cursor: cursor(value),
278
285
  node: value,
@@ -24,7 +24,7 @@ export function getRefFromModel<Types extends SchemaTypes>(
24
24
  const cache = refMap.get(builder)!;
25
25
 
26
26
  if (!cache.has(name)) {
27
- cache.set(name, new PrismaObjectRef(name));
27
+ cache.set(name, new PrismaObjectRef(name, name));
28
28
  }
29
29
 
30
30
  return cache.get(name)!;
@@ -96,6 +96,11 @@ function resolveIndirectInclude(
96
96
  path: string[],
97
97
  resolve: (type: GraphQLNamedType, field: FieldNode, path: string[]) => void,
98
98
  ) {
99
+ if (includePath.length === 0) {
100
+ resolve(type, selection as FieldNode, path);
101
+ return;
102
+ }
103
+
99
104
  const [include, ...rest] = includePath;
100
105
  if (!selection.selectionSet || !include) {
101
106
  return;
@@ -107,18 +112,14 @@ function resolveIndirectInclude(
107
112
  if (sel.name.value === include.name && isObjectType(type)) {
108
113
  const returnType = getNamedType(type.getFields()[sel.name.value].type);
109
114
 
110
- if (rest.length === 0) {
111
- resolve(returnType, sel, [...path, sel.alias?.value ?? sel.name.value]);
112
- } else {
113
- resolveIndirectInclude(
114
- returnType,
115
- info,
116
- sel,
117
- rest,
118
- [...path, sel.alias?.value ?? sel.name.value],
119
- resolve,
120
- );
121
- }
115
+ resolveIndirectInclude(
116
+ returnType,
117
+ info,
118
+ sel,
119
+ rest,
120
+ [...path, sel.alias?.value ?? sel.name.value],
121
+ resolve,
122
+ );
122
123
  }
123
124
  continue;
124
125
  case Kind.FRAGMENT_SPREAD:
@@ -334,7 +335,8 @@ export function queryFromInfo<T extends SelectionMap['select'] | undefined = und
334
335
  select?: T;
335
336
  path?: string[];
336
337
  }): { select: T } | { include?: {} } {
337
- const type = typeName ? info.schema.getTypeMap()[typeName] : getNamedType(info.returnType);
338
+ const returnType = getNamedType(info.returnType);
339
+ const type = typeName ? info.schema.getTypeMap()[typeName] : returnType;
338
340
  const state = createStateForType(type, info);
339
341
 
340
342
  if (select) {
@@ -342,14 +344,27 @@ export function queryFromInfo<T extends SelectionMap['select'] | undefined = und
342
344
  }
343
345
 
344
346
  if (path.length > 0) {
347
+ const { pothosPrismaIndirectInclude } = (returnType.extensions ?? {}) as {
348
+ pothosPrismaIndirectInclude?: IndirectInclude;
349
+ };
350
+
345
351
  resolveIndirectInclude(
346
- getNamedType(info.returnType),
352
+ returnType,
347
353
  info,
348
354
  info.fieldNodes[0],
349
- path.map((n) => (typeof n === 'string' ? { name: n } : n)),
355
+ pothosPrismaIndirectInclude?.path ?? [],
350
356
  [],
351
- (resolvedType, resolvedField, nested) => {
352
- addTypeSelectionsForField(resolvedType, context, info, state, resolvedField, nested);
357
+ (indirectType, indirectField, subPath) => {
358
+ resolveIndirectInclude(
359
+ indirectType,
360
+ info,
361
+ indirectField,
362
+ path.map((n) => (typeof n === 'string' ? { name: n } : n)),
363
+ subPath,
364
+ (resolvedType, resolvedField, nested) => {
365
+ addTypeSelectionsForField(resolvedType, context, info, state, resolvedField, nested);
366
+ },
367
+ );
353
368
  },
354
369
  );
355
370
  } else {