@pothos/plugin-prisma 3.12.1 → 3.13.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 (81) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/README.md +10 -16
  3. package/dts/field-builder.d.ts.map +1 -1
  4. package/dts/global-types.d.ts +7 -0
  5. package/dts/global-types.d.ts.map +1 -1
  6. package/dts/index.d.ts +4 -2
  7. package/dts/index.d.ts.map +1 -1
  8. package/dts/model-loader.d.ts +1 -0
  9. package/dts/model-loader.d.ts.map +1 -1
  10. package/dts/prisma-field-builder.d.ts +9 -0
  11. package/dts/prisma-field-builder.d.ts.map +1 -1
  12. package/dts/types.d.ts +2 -1
  13. package/dts/types.d.ts.map +1 -1
  14. package/dts/util/cursors.d.ts +1 -1
  15. package/dts/util/cursors.d.ts.map +1 -1
  16. package/dts/util/datamodel.d.ts.map +1 -1
  17. package/dts/util/map-query.d.ts +2 -1
  18. package/dts/util/map-query.d.ts.map +1 -1
  19. package/esm/field-builder.js +5 -1
  20. package/esm/field-builder.js.map +1 -1
  21. package/esm/global-types.js.map +1 -1
  22. package/esm/index.js +2 -1
  23. package/esm/index.js.map +1 -1
  24. package/esm/model-loader.js +30 -0
  25. package/esm/model-loader.js.map +1 -1
  26. package/esm/prisma-field-builder.js +53 -26
  27. package/esm/prisma-field-builder.js.map +1 -1
  28. package/esm/schema-builder.js +7 -2
  29. package/esm/schema-builder.js.map +1 -1
  30. package/esm/types.js.map +1 -1
  31. package/esm/util/cursors.js.map +1 -1
  32. package/esm/util/datamodel.js +18 -2
  33. package/esm/util/datamodel.js.map +1 -1
  34. package/esm/util/map-query.js +4 -1
  35. package/esm/util/map-query.js.map +1 -1
  36. package/lib/field-builder.js +25 -59
  37. package/lib/field-builder.js.map +1 -1
  38. package/lib/generator.js +10 -7
  39. package/lib/generator.js.map +1 -1
  40. package/lib/index.js +32 -26
  41. package/lib/index.js.map +1 -1
  42. package/lib/model-loader.js +46 -13
  43. package/lib/model-loader.js.map +1 -1
  44. package/lib/node-ref.js +8 -6
  45. package/lib/node-ref.js.map +1 -1
  46. package/lib/object-ref.js +11 -4
  47. package/lib/object-ref.js.map +1 -1
  48. package/lib/prisma-field-builder.js +71 -41
  49. package/lib/prisma-field-builder.js.map +1 -1
  50. package/lib/schema-builder.js +27 -19
  51. package/lib/schema-builder.js.map +1 -1
  52. package/lib/types.js +4 -2
  53. package/lib/types.js.map +1 -1
  54. package/lib/util/cursors.js +22 -14
  55. package/lib/util/cursors.js.map +1 -1
  56. package/lib/util/datamodel.js +38 -16
  57. package/lib/util/datamodel.js.map +1 -1
  58. package/lib/util/deep-equal.js +4 -1
  59. package/lib/util/deep-equal.js.map +1 -1
  60. package/lib/util/get-client.js +12 -4
  61. package/lib/util/get-client.js.map +1 -1
  62. package/lib/util/loader-map.js +13 -5
  63. package/lib/util/loader-map.js.map +1 -1
  64. package/lib/util/map-query.js +39 -28
  65. package/lib/util/map-query.js.map +1 -1
  66. package/lib/util/relation-map.js +12 -5
  67. package/lib/util/relation-map.js.map +1 -1
  68. package/lib/util/selections.js +17 -9
  69. package/lib/util/selections.js.map +1 -1
  70. package/package.json +6 -7
  71. package/src/field-builder.ts +3 -1
  72. package/src/global-types.ts +16 -0
  73. package/src/index.ts +17 -1
  74. package/src/model-loader.ts +36 -0
  75. package/src/prisma-field-builder.ts +108 -22
  76. package/src/schema-builder.ts +11 -5
  77. package/src/types.ts +3 -2
  78. package/src/util/cursors.ts +1 -1
  79. package/src/util/datamodel.ts +21 -3
  80. package/src/util/map-query.ts +10 -1
  81. package/tsconfig.type.tsbuildinfo +1 -1
@@ -14,12 +14,14 @@ import {
14
14
  SchemaTypes,
15
15
  TypeParam,
16
16
  } from '@pothos/core';
17
+ import { ModelLoader } from './model-loader';
17
18
  import { PrismaObjectRef } from './object-ref';
18
19
  import {
19
20
  PrismaModelTypes,
20
21
  RelatedConnectionOptions,
21
22
  RelatedFieldOptions,
22
23
  RelationCountOptions,
24
+ SelectionMap,
23
25
  ShapeFromConnection,
24
26
  VariantFieldOptions,
25
27
  } from './types';
@@ -43,6 +45,25 @@ const RootBuilder: {
43
45
  ): PothosSchemaTypes.RootFieldBuilder<Types, Shape, Kind>;
44
46
  } = RootFieldBuilder as never;
45
47
 
48
+ type ContextForAuth<
49
+ Types extends SchemaTypes,
50
+ Scopes extends {} = {},
51
+ > = PothosSchemaTypes.ScopeAuthContextForAuth<Types, Scopes> extends {
52
+ Context: infer T;
53
+ }
54
+ ? T
55
+ : never;
56
+
57
+ type FieldAuthScopes<
58
+ Types extends SchemaTypes,
59
+ Parent,
60
+ Args extends {} = {},
61
+ > = PothosSchemaTypes.ScopeAuthFieldAuthScopes<Types, Parent, Args> extends {
62
+ Scopes: infer T;
63
+ }
64
+ ? T
65
+ : never;
66
+
46
67
  export class PrismaObjectFieldBuilder<
47
68
  Types extends SchemaTypes,
48
69
  Model extends PrismaModelTypes,
@@ -63,6 +84,17 @@ export class PrismaObjectFieldBuilder<
63
84
  exposeIDList = this.createExpose(['ID']);
64
85
  exposeStringList = this.createExpose(['String']);
65
86
 
87
+ withAuth: 'scopeAuth' extends PluginName
88
+ ? <Scopes extends FieldAuthScopes<Types, Shape, Record<string, unknown>>>(
89
+ scopes: Scopes,
90
+ ) => PothosSchemaTypes.PrismaObjectFieldBuilder<
91
+ Omit<Types, 'Context'> & { Context: ContextForAuth<Types, Scopes> },
92
+ Model,
93
+ NeedsResolve,
94
+ Shape
95
+ >
96
+ : '@pothos/plugin-scope-auth is required to use this method' = (() => {}) as never;
97
+
66
98
  relatedConnection: 'relay' extends PluginName
67
99
  ? <
68
100
  Field extends Model['ListRelations'],
@@ -133,35 +165,53 @@ export class PrismaObjectFieldBuilder<
133
165
  args,
134
166
  }),
135
167
  });
168
+ const cursorSelection = ModelLoader.getCursorSelection(
169
+ ref,
170
+ relationField.type,
171
+ cursor,
172
+ this.builder,
173
+ );
136
174
 
137
175
  const relationSelect = (
138
176
  args: object,
139
177
  context: object,
140
178
  nestedQuery: (query: unknown, path: unknown) => unknown,
141
- ) => ({
142
- select: {
143
- [name]: nestedQuery(
144
- {
145
- ...((typeof query === 'function' ? query(args, context) : query) as {}),
146
- ...prismaCursorConnectionQuery({
147
- parseCursor,
148
- maxSize,
149
- defaultSize,
150
- args,
151
- }),
179
+ ) => {
180
+ const nested = nestedQuery(
181
+ {
182
+ ...((typeof query === 'function' ? query(args, context) : query) as {}),
183
+ ...prismaCursorConnectionQuery({
184
+ parseCursor,
185
+ maxSize,
186
+ defaultSize,
187
+ args,
188
+ }),
189
+ },
190
+ {
191
+ getType: () => {
192
+ if (!typeName) {
193
+ typeName = this.builder.configStore.getTypeConfig(ref).name;
194
+ }
195
+ return typeName;
152
196
  },
153
- {
154
- getType: () => {
155
- if (!typeName) {
156
- typeName = this.builder.configStore.getTypeConfig(ref).name;
197
+ path: [{ name: 'edges' }, { name: 'node' }],
198
+ },
199
+ ) as SelectionMap;
200
+
201
+ return {
202
+ select: {
203
+ [name]: nested?.select
204
+ ? {
205
+ ...nested,
206
+ select: {
207
+ ...cursorSelection,
208
+ ...nested.select,
209
+ },
157
210
  }
158
- return typeName;
159
- },
160
- path: [{ name: 'edges' }, { name: 'node' }],
161
- },
162
- ),
163
- },
164
- });
211
+ : nested,
212
+ },
213
+ };
214
+ };
165
215
 
166
216
  const fieldRef = (
167
217
  this as unknown as {
@@ -448,3 +498,39 @@ export class PrismaObjectFieldBuilder<
448
498
  };
449
499
  }
450
500
  }
501
+
502
+ const prismaFieldBuilderProto = PrismaObjectFieldBuilder.prototype as {} as Omit<
503
+ PrismaObjectFieldBuilder<SchemaTypes, PrismaModelTypes, false, {}>,
504
+ 'withAuth'
505
+ > & {
506
+ withAuth: (scopes: {}) => unknown;
507
+ };
508
+
509
+ prismaFieldBuilderProto.withAuth = function withAuth(scopes) {
510
+ return addScopes(
511
+ scopes,
512
+ new PrismaObjectFieldBuilder(
513
+ this.typename,
514
+ this.builder,
515
+ this.model,
516
+ this.prismaFieldMap,
517
+ ) as never,
518
+ );
519
+ };
520
+
521
+ function addScopes(
522
+ scopes: unknown,
523
+ builder: { createField: (options: Record<string, unknown>) => unknown },
524
+ ) {
525
+ const originalCreateField = builder.createField;
526
+
527
+ // eslint-disable-next-line no-param-reassign
528
+ builder.createField = function createField(options) {
529
+ return originalCreateField.call(this, {
530
+ authScopes: scopes,
531
+ ...options,
532
+ });
533
+ };
534
+
535
+ return builder as never;
536
+ }
@@ -97,11 +97,17 @@ schemaBuilderProto.prismaNode = function prismaNode(
97
97
  ) => {
98
98
  const query = queryFromInfo(context, info, typeName);
99
99
  const delegate = getDelegateFromModel(getClient(this, context), type);
100
- const record = await delegate.findUnique({
101
- ...query,
102
- rejectOnNotFound: true,
103
- where: rawFindUnique ? rawFindUnique(id, context) : { [fieldName]: idParser!(id) },
104
- } as never);
100
+
101
+ const record = await (delegate.findUniqueOrThrow
102
+ ? delegate.findUniqueOrThrow({
103
+ ...query,
104
+ where: rawFindUnique ? rawFindUnique(id, context) : { [fieldName]: idParser!(id) },
105
+ } as never)
106
+ : delegate.findUnique({
107
+ ...query,
108
+ rejectOnNotFound: true,
109
+ where: rawFindUnique ? rawFindUnique(id, context) : { [fieldName]: idParser!(id) },
110
+ } as never));
105
111
 
106
112
  brandWithType(record, typeName as OutputType<SchemaTypes>);
107
113
 
package/src/types.ts CHANGED
@@ -24,6 +24,7 @@ import { PrismaObjectFieldBuilder } from './field-builder';
24
24
  import { PrismaObjectRef } from './object-ref';
25
25
 
26
26
  export interface PrismaDelegate {
27
+ findUniqueOrThrow?: (...args: any[]) => Promise<unknown>;
27
28
  findUnique: (...args: any[]) => Promise<unknown>;
28
29
  }
29
30
 
@@ -517,10 +518,10 @@ export type RelatedConnectionOptions<
517
518
  Model['Shape'],
518
519
  ObjectRef<unknown>,
519
520
  Nullable,
520
- Args,
521
+ Args & InputFieldsFromShape<PothosSchemaTypes.DefaultConnectionArguments>,
521
522
  unknown
522
523
  >,
523
- 'resolve' | 'type'
524
+ 'resolve' | 'type' | 'args'
524
525
  > &
525
526
  Omit<
526
527
  PothosSchemaTypes.ConnectionFieldOptions<
@@ -174,7 +174,7 @@ export function serializeID(id: unknown, dataType: string) {
174
174
  }
175
175
 
176
176
  export function parseCompositeCursor(fields: string[]) {
177
- return (cursor: string) => {
177
+ return (cursor: unknown) => {
178
178
  const parsed = parseRawCursor(cursor) as unknown[];
179
179
 
180
180
  if (!Array.isArray(parsed)) {
@@ -72,8 +72,15 @@ export function getCursorFormatter<Types extends SchemaTypes>(
72
72
  ) {
73
73
  const modelData = getModel(name, builder);
74
74
  const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
75
+ if (primaryKey === cursor) {
76
+ return formatCursor(modelData.primaryKey!.fields);
77
+ }
78
+
79
+ const uniqueIndex = modelData.uniqueIndexes.find(
80
+ (idx) => (idx.name ?? idx.fields.join('_')) === cursor,
81
+ );
75
82
 
76
- return formatCursor(cursor === primaryKey ? modelData.primaryKey!.fields : cursor);
83
+ return formatCursor(uniqueIndex?.fields ?? cursor);
77
84
  }
78
85
 
79
86
  export function getCursorParser<Types extends SchemaTypes>(
@@ -84,8 +91,19 @@ export function getCursorParser<Types extends SchemaTypes>(
84
91
  const modelData = getModel(name, builder);
85
92
  const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
86
93
 
87
- const parser =
88
- cursor === primaryKey ? parseCompositeCursor(modelData.primaryKey!.fields) : parseRawCursor;
94
+ let parser = parseRawCursor;
95
+
96
+ if (primaryKey === cursor) {
97
+ parser = parseCompositeCursor(modelData.primaryKey!.fields);
98
+ } else {
99
+ const uniqueIndex = modelData.uniqueIndexes.find(
100
+ (idx) => (idx.name ?? idx.fields.join('_')) === cursor,
101
+ );
102
+
103
+ if (uniqueIndex) {
104
+ parser = parseCompositeCursor(uniqueIndex.fields);
105
+ }
106
+ }
89
107
 
90
108
  return (rawCursor: string) => ({
91
109
  [cursor]: parser(rawCursor),
@@ -306,10 +306,19 @@ function addFieldSelection(
306
306
  }
307
307
  }
308
308
 
309
- export function queryFromInfo(context: object, info: GraphQLResolveInfo, typeName?: string): {} {
309
+ export function queryFromInfo(
310
+ context: object,
311
+ info: GraphQLResolveInfo,
312
+ typeName?: string,
313
+ initialSelection?: SelectionMap,
314
+ ): {} {
310
315
  const type = typeName ? info.schema.getTypeMap()[typeName] : getNamedType(info.returnType);
311
316
  const state = createStateForType(type, info);
312
317
 
318
+ if (initialSelection) {
319
+ mergeSelection(state, initialSelection);
320
+ }
321
+
313
322
  addTypeSelectionsForField(type, context, info, state, info.fieldNodes[0], []);
314
323
 
315
324
  setLoaderMappings(context, info, state.mappings);