@pothos/plugin-prisma 0.18.0 → 0.19.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 +6 -0
  2. package/README.md +403 -308
  3. package/esm/field-builder.js +3 -3
  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 +12 -69
  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 +83 -116
  20. package/esm/prisma-field-builder.js.map +1 -1
  21. package/esm/schema-builder.js +14 -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} +1 -1
  28. package/esm/util/cursors.d.ts.map +1 -0
  29. package/esm/{cursors.js → util/cursors.js} +0 -0
  30. package/esm/util/cursors.js.map +1 -0
  31. package/{lib/refs.d.ts → esm/util/datamodel.d.ts} +4 -8
  32. package/esm/util/datamodel.d.ts.map +1 -0
  33. package/esm/{refs.js → util/datamodel.js} +2 -25
  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 +9 -9
  56. package/lib/field-builder.js.map +1 -1
  57. package/lib/generator.js +4 -0
  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 +45 -0
  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 +13 -70
  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 +89 -122
  72. package/lib/prisma-field-builder.js.map +1 -1
  73. package/lib/schema-builder.js +17 -7
  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} +1 -1
  80. package/lib/util/cursors.d.ts.map +1 -0
  81. package/lib/{cursors.js → util/cursors.js} +0 -0
  82. package/lib/util/cursors.js.map +1 -0
  83. package/{esm/refs.d.ts → lib/util/datamodel.d.ts} +4 -8
  84. package/lib/util/datamodel.d.ts.map +1 -0
  85. package/lib/{refs.js → util/datamodel.js} +3 -29
  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 +5 -5
  108. package/src/field-builder.ts +3 -3
  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 +19 -92
  113. package/src/prisma-field-builder.ts +194 -152
  114. package/src/schema-builder.ts +28 -7
  115. package/src/types.ts +138 -102
  116. package/src/{cursors.ts → util/cursors.ts} +1 -1
  117. package/src/{refs.ts → util/datamodel.ts} +3 -44
  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
@@ -11,6 +11,7 @@ import {
11
11
  PluginName,
12
12
  SchemaTypes,
13
13
  ShapeFromTypeParam,
14
+ TypeParam,
14
15
  } from '@pothos/core';
15
16
  import PrismaNodeRef from './node-ref';
16
17
  import { prismaModelKey, PrismaObjectRef } from './object-ref';
@@ -20,9 +21,8 @@ import {
20
21
  PrismaModelTypes,
21
22
  PrismaNodeOptions,
22
23
  PrismaObjectTypeOptions,
23
- ShapeWithInclude,
24
24
  } from './types';
25
- import { PrismaPlugin, ShapeFromConnection } from '.';
25
+ import { PrismaObjectFieldOptions, PrismaPlugin, ShapeFromConnection, ShapeFromSelection } from '.';
26
26
 
27
27
  declare global {
28
28
  export namespace PothosSchemaTypes {
@@ -48,30 +48,77 @@ declare global {
48
48
  : PartialTypes['PrismaTypes'] & {};
49
49
  }
50
50
 
51
+ export interface PothosKindToGraphQLType {
52
+ PrismaObject: 'Object';
53
+ }
54
+
55
+ export interface FieldOptionsByKind<
56
+ Types extends SchemaTypes,
57
+ ParentShape,
58
+ Type extends TypeParam<Types>,
59
+ Nullable extends FieldNullability<Type>,
60
+ Args extends InputFieldMap,
61
+ ResolveShape,
62
+ ResolveReturnShape,
63
+ > {
64
+ PrismaObject: PrismaObjectFieldOptions<
65
+ Types,
66
+ ParentShape,
67
+ Type,
68
+ Nullable,
69
+ Args,
70
+ ResolveShape,
71
+ ResolveReturnShape
72
+ >;
73
+ }
74
+
51
75
  export interface SchemaBuilder<Types extends SchemaTypes> {
52
76
  prismaObject: <
53
77
  Name extends keyof Types['PrismaTypes'],
54
78
  Interfaces extends InterfaceParam<Types>[],
55
79
  FindUnique,
56
80
  Model extends PrismaModelTypes & Types['PrismaTypes'][Name],
57
- Include extends Model['Include'] = {},
58
- Shape extends object = ShapeWithInclude<Model, Include>,
81
+ Include = unknown,
82
+ Select = unknown,
59
83
  >(
60
84
  name: Name,
61
- options: PrismaObjectTypeOptions<Types, Model, Interfaces, FindUnique, Include, Shape>,
62
- ) => PrismaObjectRef<Model, Shape>;
85
+ options: PrismaObjectTypeOptions<
86
+ Types,
87
+ Model,
88
+ Interfaces,
89
+ FindUnique,
90
+ Include,
91
+ Select,
92
+ ShapeFromSelection<Model, { select: Select; include: Include }>
93
+ >,
94
+ ) => PrismaObjectRef<Model, ShapeFromSelection<Model, { select: Select; include: Include }>>;
63
95
 
64
96
  prismaNode: 'relay' extends PluginName
65
97
  ? <
66
98
  Name extends keyof Types['PrismaTypes'],
67
- Interfaces extends InterfaceParam<Types>[],
68
- Model extends PrismaModelTypes & Types['PrismaTypes'][Name],
69
- Include extends Model['Include'] = {},
70
- Shape extends object = ShapeWithInclude<Model, Include>,
99
+ Interfaces extends InterfaceParam<Types>[] = [],
100
+ Include = unknown,
101
+ Select = unknown,
71
102
  >(
72
103
  name: Name,
73
- options: PrismaNodeOptions<Types, Model, Interfaces, Include, Shape>,
74
- ) => PrismaNodeRef<Model, Shape>
104
+ options: PrismaNodeOptions<
105
+ Types,
106
+ Types['PrismaTypes'][Name] & PrismaModelTypes,
107
+ Interfaces,
108
+ Include,
109
+ Select,
110
+ ShapeFromSelection<
111
+ PrismaModelTypes & Types['PrismaTypes'][Name],
112
+ { select: Select; include: Include }
113
+ >
114
+ >,
115
+ ) => PrismaNodeRef<
116
+ Types['PrismaTypes'][Name] & PrismaModelTypes,
117
+ ShapeFromSelection<
118
+ PrismaModelTypes & Types['PrismaTypes'][Name],
119
+ { select: Select; include: Include }
120
+ >
121
+ >
75
122
  : '@pothos/plugin-relay is required to use this method';
76
123
  }
77
124
 
package/src/index.ts CHANGED
@@ -1,7 +1,16 @@
1
1
  import './global-types';
2
2
  import './field-builder';
3
3
  import './schema-builder';
4
- import SchemaBuilder, { BasePlugin, BuildCache, SchemaTypes } from '@pothos/core';
4
+ import { getNamedType, GraphQLFieldResolver } from 'graphql';
5
+ import SchemaBuilder, {
6
+ BasePlugin,
7
+ BuildCache,
8
+ PothosOutputFieldConfig,
9
+ SchemaTypes,
10
+ } from '@pothos/core';
11
+ import { ModelLoader } from './model-loader';
12
+ import { getLoaderMapping, setLoaderMappings } from './util/loader-map';
13
+ import { queryFromInfo, selectionStateFromInfo } from './util/map-query';
5
14
 
6
15
  export * from './types';
7
16
 
@@ -13,6 +22,71 @@ export class PrismaPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
13
22
  constructor(cache: BuildCache<Types>) {
14
23
  super(cache, pluginName);
15
24
  }
25
+
26
+ override onOutputFieldConfig(
27
+ fieldConfig: PothosOutputFieldConfig<Types>,
28
+ ): PothosOutputFieldConfig<Types> | null {
29
+ if (fieldConfig.kind === 'PrismaObject' && fieldConfig.pothosOptions.select) {
30
+ return {
31
+ ...fieldConfig,
32
+ extensions: {
33
+ ...fieldConfig.extensions,
34
+ pothosPrismaSelect: fieldConfig.pothosOptions.select,
35
+ },
36
+ };
37
+ }
38
+
39
+ return fieldConfig;
40
+ }
41
+
42
+ override wrapResolve(
43
+ resolver: GraphQLFieldResolver<unknown, Types['Context'], object, unknown>,
44
+ fieldConfig: PothosOutputFieldConfig<Types>,
45
+ ): GraphQLFieldResolver<unknown, Types['Context'], object> {
46
+ if (fieldConfig.kind !== 'PrismaObject' || !fieldConfig.extensions?.pothosPrismaSelect) {
47
+ return resolver;
48
+ }
49
+
50
+ const parentConfig = this.buildCache.getTypeConfig(fieldConfig.parentType, 'Object');
51
+ const loadedCheck = fieldConfig.extensions.pothosPrismaLoaded as
52
+ | undefined
53
+ | ((val: unknown) => boolean);
54
+ const loaderCache = parentConfig.extensions?.pothosPrismaLoader as (
55
+ model: unknown,
56
+ ) => ModelLoader;
57
+
58
+ const fallback = fieldConfig.extensions.pothosPrismaFallback as
59
+ | undefined
60
+ | ((query: {}, parent: unknown, args: {}, context: {}, info: {}) => unknown);
61
+
62
+ return (parent, args, context, info) => {
63
+ const mapping = getLoaderMapping(context, info.path, info.parentType.name);
64
+
65
+ if ((!loadedCheck || loadedCheck(parent)) && mapping) {
66
+ setLoaderMappings(context, info, mapping, getNamedType(info.returnType));
67
+
68
+ return resolver(parent, args, context, info);
69
+ }
70
+
71
+ if (fallback) {
72
+ return fallback(queryFromInfo(context, info), parent, args, context, info);
73
+ }
74
+
75
+ const selectionState = selectionStateFromInfo(context, info);
76
+
77
+ return loaderCache(parent)
78
+ .loadSelection(selectionState, context)
79
+ .then((result) => {
80
+ const mappings = selectionState.mappings[info.path.key];
81
+
82
+ if (mappings) {
83
+ setLoaderMappings(context, info, mappings.mappings, getNamedType(info.returnType));
84
+ }
85
+
86
+ return resolver(result, args, context, info);
87
+ });
88
+ };
89
+ }
16
90
  }
17
91
 
18
92
  SchemaBuilder.registerPlugin(pluginName, PrismaPlugin);
@@ -1,11 +1,12 @@
1
- /* eslint-disable prefer-destructuring */
2
- /* eslint-disable no-underscore-dangle */
3
1
  import { createContextCache, SchemaTypes } from '@pothos/core';
4
- import { getDelegateFromModel, getFindUniqueForRef, getRefFromModel } from './refs';
5
2
  import { PrismaDelegate } from './types';
6
- import { mergeIncludes } from './util';
7
-
8
- const loaderCache = new WeakMap<object, (model: object) => ModelLoader>();
3
+ import { getDelegateFromModel } from './util/datamodel';
4
+ import {
5
+ mergeSelection,
6
+ selectionCompatible,
7
+ SelectionState,
8
+ selectionToQuery,
9
+ } from './util/selections';
9
10
 
10
11
  export class ModelLoader {
11
12
  model: object;
@@ -14,7 +15,7 @@ export class ModelLoader {
14
15
 
15
16
  staged = new Set<{
16
17
  promise: Promise<Record<string, unknown>>;
17
- include: Record<string, unknown>;
18
+ state: SelectionState;
18
19
  }>();
19
20
 
20
21
  constructor(
@@ -27,105 +28,31 @@ export class ModelLoader {
27
28
  this.findUnique = findUnique;
28
29
  }
29
30
 
30
- static forModel<Types extends SchemaTypes>(
31
+ static forRef<Types extends SchemaTypes>(
31
32
  modelName: string,
33
+ findUnique: (args: unknown, ctx: {}) => unknown,
32
34
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
33
35
  ) {
34
36
  const delegate = getDelegateFromModel(builder.options.prisma.client, modelName);
35
37
 
36
- if (!loaderCache.has(delegate)) {
37
- const ref = getRefFromModel(modelName, builder);
38
-
39
- const findUnique = getFindUniqueForRef(ref, builder);
40
- loaderCache.set(
41
- delegate,
42
- createContextCache((model) => new ModelLoader(model, delegate, findUnique!)),
43
- );
44
- }
45
-
46
- return loaderCache.get(delegate)!;
38
+ return createContextCache((model) => new ModelLoader(model, delegate, findUnique));
47
39
  }
48
40
 
49
- async loadCount(relation: string, context: {}): Promise<number> {
50
- let promise;
51
- const entry = [...this.staged][0];
52
-
53
- if (entry) {
54
- if (!entry.include._count) {
55
- entry.include._count = { select: {} };
56
- }
57
-
58
- (entry.include._count as { select: Record<string, boolean> }).select[relation] = true;
59
- promise = entry.promise;
60
- } else {
61
- promise = this.initLoad(relation, null, context, true);
62
- }
63
-
64
- const result = await promise;
41
+ async loadSelection(selection: SelectionState, context: object) {
42
+ const query = selectionToQuery(selection);
65
43
 
66
- return (result._count as Record<string, number>)[relation];
67
- }
68
-
69
- async loadSelf(include: unknown, context: {}) {
70
44
  for (const entry of this.staged) {
71
- const merged = mergeIncludes(entry.include, include as Record<string, unknown>);
72
-
73
- if (merged) {
74
- entry.include = merged as Record<string, unknown>;
45
+ if (selectionCompatible(entry.state, query)) {
46
+ mergeSelection(entry.state, query);
75
47
 
76
48
  return entry.promise;
77
49
  }
78
50
  }
79
51
 
80
- return this.initLoad(null, include, context);
52
+ return this.initLoad(selection, context);
81
53
  }
82
54
 
83
- async loadRelation(relation: string, include: unknown, context: {}) {
84
- let promise;
85
- for (const entry of this.staged) {
86
- if (entry.include[relation] === undefined) {
87
- promise = entry.promise;
88
- entry.include[relation] = include;
89
-
90
- break;
91
- }
92
-
93
- const merged = mergeIncludes(
94
- entry.include[relation] as Record<string, unknown>,
95
- include as Record<string, unknown>,
96
- );
97
-
98
- if (merged) {
99
- entry.include[relation] = merged;
100
- break;
101
- }
102
- }
103
-
104
- if (!promise) {
105
- promise = this.initLoad(relation, include, context);
106
- }
107
-
108
- const result = await promise;
109
-
110
- return result[relation];
111
- }
112
-
113
- async initLoad(relation: string | null, includeArg: unknown, context: {}, count = false) {
114
- const include: Record<string, unknown> =
115
- (relation &&
116
- (count
117
- ? {
118
- _count: {
119
- select: {
120
- [relation]: true,
121
- },
122
- },
123
- }
124
- : {
125
- [relation]: includeArg,
126
- })) ||
127
- {};
128
-
55
+ async initLoad(state: SelectionState, context: {}) {
129
56
  const promise = new Promise<Record<string, unknown>>((resolve, reject) => {
130
57
  setTimeout(() => {
131
58
  this.staged.delete(entry);
@@ -133,8 +60,8 @@ export class ModelLoader {
133
60
  resolve(
134
61
  this.delegate.findUnique({
135
62
  rejectOnNotFound: true,
63
+ ...selectionToQuery(state),
136
64
  where: { ...(this.findUnique(this.model, context) as {}) },
137
- include: Object.keys(include).length > 0 ? include : undefined,
138
65
  } as never) as Promise<Record<string, unknown>>,
139
66
  );
140
67
  }, 0);
@@ -142,7 +69,7 @@ export class ModelLoader {
142
69
 
143
70
  const entry = {
144
71
  promise,
145
- include,
72
+ state,
146
73
  };
147
74
 
148
75
  this.staged.add(entry);