@pothos/plugin-drizzle 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.
- package/CHANGELOG.md +351 -0
- package/README.md +784 -221
- package/dts/connection-helpers.d.ts +18 -8
- package/dts/connection-helpers.d.ts.map +1 -1
- package/dts/drizzle-field-builder.d.ts +4 -11
- package/dts/drizzle-field-builder.d.ts.map +1 -1
- package/dts/global-types.d.ts.map +1 -1
- package/dts/index.d.ts.map +1 -1
- package/dts/model-loader.d.ts +18 -17
- package/dts/model-loader.d.ts.map +1 -1
- package/dts/types.d.ts +81 -20
- package/dts/types.d.ts.map +1 -1
- package/dts/utils/adapter.d.ts +39 -0
- package/dts/utils/adapter.d.ts.map +1 -0
- package/dts/utils/await-selections.d.ts +12 -0
- package/dts/utils/await-selections.d.ts.map +1 -0
- package/dts/utils/config.d.ts +23 -3
- package/dts/utils/config.d.ts.map +1 -1
- package/dts/utils/cursors.d.ts +6 -6
- package/dts/utils/cursors.d.ts.map +1 -1
- package/dts/utils/map-query.d.ts +22 -21
- package/dts/utils/map-query.d.ts.map +1 -1
- package/dts/utils/path-info.d.ts +13 -0
- package/dts/utils/path-info.d.ts.map +1 -0
- package/dts/utils/relation-filter.d.ts +48 -0
- package/dts/utils/relation-filter.d.ts.map +1 -0
- package/dts/utils/selections.d.ts +2 -21
- package/dts/utils/selections.d.ts.map +1 -1
- package/esm/connection-helpers.d.ts +18 -8
- package/esm/connection-helpers.d.ts.map +1 -1
- package/esm/connection-helpers.js +52 -19
- package/esm/connection-helpers.js.map +1 -1
- package/esm/drizzle-field-builder.d.ts +4 -11
- package/esm/drizzle-field-builder.d.ts.map +1 -1
- package/esm/drizzle-field-builder.js +138 -96
- package/esm/drizzle-field-builder.js.map +1 -1
- package/esm/field-builder.js +61 -47
- package/esm/field-builder.js.map +1 -1
- package/esm/global-types.d.ts.map +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +37 -61
- package/esm/index.js.map +1 -1
- package/esm/model-loader.d.ts +18 -17
- package/esm/model-loader.d.ts.map +1 -1
- package/esm/model-loader.js +76 -45
- package/esm/model-loader.js.map +1 -1
- package/esm/schema-builder.js +40 -149
- package/esm/schema-builder.js.map +1 -1
- package/esm/types.d.ts +81 -20
- package/esm/types.d.ts.map +1 -1
- package/esm/types.js +1 -0
- package/esm/types.js.map +1 -1
- package/esm/utils/adapter.d.ts +39 -0
- package/esm/utils/adapter.d.ts.map +1 -0
- package/esm/utils/adapter.js +137 -0
- package/esm/utils/adapter.js.map +1 -0
- package/esm/utils/await-selections.d.ts +12 -0
- package/esm/utils/await-selections.d.ts.map +1 -0
- package/esm/utils/await-selections.js +19 -0
- package/esm/utils/await-selections.js.map +1 -0
- package/esm/utils/config.d.ts +23 -3
- package/esm/utils/config.d.ts.map +1 -1
- package/esm/utils/config.js +1 -4
- package/esm/utils/config.js.map +1 -1
- package/esm/utils/cursors.d.ts +6 -6
- package/esm/utils/cursors.d.ts.map +1 -1
- package/esm/utils/cursors.js +55 -90
- package/esm/utils/cursors.js.map +1 -1
- package/esm/utils/map-query.d.ts +22 -21
- package/esm/utils/map-query.d.ts.map +1 -1
- package/esm/utils/map-query.js +40 -336
- package/esm/utils/map-query.js.map +1 -1
- package/esm/utils/path-info.d.ts +13 -0
- package/esm/utils/path-info.d.ts.map +1 -0
- package/esm/utils/path-info.js +37 -0
- package/esm/utils/path-info.js.map +1 -0
- package/esm/utils/relation-filter.d.ts +48 -0
- package/esm/utils/relation-filter.d.ts.map +1 -0
- package/esm/utils/relation-filter.js +92 -0
- package/esm/utils/relation-filter.js.map +1 -0
- package/esm/utils/selections.d.ts +2 -21
- package/esm/utils/selections.d.ts.map +1 -1
- package/esm/utils/selections.js +1 -133
- package/esm/utils/selections.js.map +1 -1
- package/lib/connection-helpers.js +51 -18
- package/lib/connection-helpers.js.map +1 -1
- package/lib/drizzle-field-builder.js +136 -94
- package/lib/drizzle-field-builder.js.map +1 -1
- package/lib/field-builder.js +58 -44
- package/lib/field-builder.js.map +1 -1
- package/lib/index.js +36 -60
- package/lib/index.js.map +1 -1
- package/lib/model-loader.js +76 -45
- package/lib/model-loader.js.map +1 -1
- package/lib/schema-builder.js +40 -149
- package/lib/schema-builder.js.map +1 -1
- package/lib/types.js +4 -0
- package/lib/types.js.map +1 -1
- package/lib/utils/adapter.js +147 -0
- package/lib/utils/adapter.js.map +1 -0
- package/lib/utils/await-selections.js +20 -0
- package/lib/utils/await-selections.js.map +1 -0
- package/lib/utils/config.js +1 -4
- package/lib/utils/config.js.map +1 -1
- package/lib/utils/cursors.js +47 -88
- package/lib/utils/cursors.js.map +1 -1
- package/lib/utils/map-query.js +28 -341
- package/lib/utils/map-query.js.map +1 -1
- package/lib/utils/path-info.js +39 -0
- package/lib/utils/path-info.js.map +1 -0
- package/lib/utils/relation-filter.js +91 -0
- package/lib/utils/relation-filter.js.map +1 -0
- package/lib/utils/selections.js +3 -158
- package/lib/utils/selections.js.map +1 -1
- package/package.json +8 -6
- package/src/connection-helpers.ts +167 -53
- package/src/drizzle-field-builder.ts +296 -176
- package/src/field-builder.ts +110 -77
- package/src/global-types.ts +0 -32
- package/src/index.ts +42 -68
- package/src/model-loader.ts +110 -71
- package/src/schema-builder.ts +76 -169
- package/src/types.ts +176 -44
- package/src/utils/adapter.ts +197 -0
- package/src/utils/await-selections.ts +31 -0
- package/src/utils/config.ts +1 -5
- package/src/utils/cursors.ts +53 -81
- package/src/utils/map-query.ts +51 -708
- package/src/utils/path-info.ts +40 -0
- package/src/utils/relation-filter.ts +185 -0
- package/src/utils/selections.ts +2 -207
- package/dts/utils/deep-equal.d.ts +0 -2
- package/dts/utils/deep-equal.d.ts.map +0 -1
- package/dts/utils/drizzle-graphql.d.ts +0 -2
- package/dts/utils/drizzle-graphql.d.ts.map +0 -1
- package/dts/utils/loader-map.d.ts +0 -11
- package/dts/utils/loader-map.d.ts.map +0 -1
- package/dts/utils/usage.d.ts +0 -5
- package/dts/utils/usage.d.ts.map +0 -1
- package/esm/utils/deep-equal.d.ts +0 -2
- package/esm/utils/deep-equal.d.ts.map +0 -1
- package/esm/utils/deep-equal.js +0 -45
- package/esm/utils/deep-equal.js.map +0 -1
- package/esm/utils/drizzle-graphql.d.ts +0 -2
- package/esm/utils/drizzle-graphql.d.ts.map +0 -1
- package/esm/utils/drizzle-graphql.js +0 -232
- package/esm/utils/drizzle-graphql.js.map +0 -1
- package/esm/utils/loader-map.d.ts +0 -11
- package/esm/utils/loader-map.d.ts.map +0 -1
- package/esm/utils/loader-map.js +0 -35
- package/esm/utils/loader-map.js.map +0 -1
- package/esm/utils/usage.d.ts +0 -5
- package/esm/utils/usage.d.ts.map +0 -1
- package/esm/utils/usage.js +0 -59
- package/esm/utils/usage.js.map +0 -1
- package/lib/utils/deep-equal.js +0 -55
- package/lib/utils/deep-equal.js.map +0 -1
- package/lib/utils/drizzle-graphql.js +0 -236
- package/lib/utils/drizzle-graphql.js.map +0 -1
- package/lib/utils/loader-map.js +0 -56
- package/lib/utils/loader-map.js.map +0 -1
- package/lib/utils/usage.js +0 -83
- package/lib/utils/usage.js.map +0 -1
- package/src/utils/deep-equal.ts +0 -57
- package/src/utils/drizzle-graphql.ts +0 -274
- package/src/utils/loader-map.ts +0 -49
- package/src/utils/usage.ts +0 -62
package/src/utils/map-query.ts
CHANGED
|
@@ -1,478 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
type FragmentDefinitionNode,
|
|
6
|
-
type FragmentSpreadNode,
|
|
7
|
-
type GraphQLField,
|
|
8
|
-
GraphQLIncludeDirective,
|
|
9
|
-
type GraphQLInterfaceType,
|
|
10
|
-
type GraphQLNamedType,
|
|
11
|
-
type GraphQLObjectType,
|
|
12
|
-
type GraphQLResolveInfo,
|
|
13
|
-
GraphQLSkipDirective,
|
|
14
|
-
getDirectiveValues,
|
|
15
|
-
getNamedType,
|
|
16
|
-
type InlineFragmentNode,
|
|
17
|
-
isInterfaceType,
|
|
18
|
-
isListType,
|
|
19
|
-
isObjectType,
|
|
20
|
-
Kind,
|
|
21
|
-
type SelectionSetNode,
|
|
22
|
-
} from 'graphql';
|
|
23
|
-
import type { DrizzleFieldSelection, FieldPathInfo, PathInfo } from '../types.js';
|
|
1
|
+
import { isThenable } from '@pothos/core';
|
|
2
|
+
import { type PathSegment, Plan } from '@pothos/selection-mapper';
|
|
3
|
+
import type { GraphQLResolveInfo } from 'graphql';
|
|
4
|
+
import { type DrizzlePlan, drizzleAdapter } from './adapter.js';
|
|
24
5
|
import type { PothosDrizzleSchemaConfig } from './config.js';
|
|
25
|
-
import
|
|
26
|
-
import {
|
|
27
|
-
createState,
|
|
28
|
-
mergeSelection,
|
|
29
|
-
type SelectionMap,
|
|
30
|
-
type SelectionState,
|
|
31
|
-
selectionCompatible,
|
|
32
|
-
selectionToQuery,
|
|
33
|
-
} from './selections.js';
|
|
34
|
-
import { wrapWithUsageCheck } from './usage.js';
|
|
35
|
-
|
|
36
|
-
export interface IndirectInclude {
|
|
37
|
-
getType: () => string;
|
|
38
|
-
path?: { type?: string; name: string }[];
|
|
39
|
-
paths?: { type?: string; name: string }[][];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function addTypeSelectionsForField(
|
|
43
|
-
config: PothosDrizzleSchemaConfig,
|
|
44
|
-
type: GraphQLNamedType,
|
|
45
|
-
context: object,
|
|
46
|
-
info: GraphQLResolveInfo,
|
|
47
|
-
state: SelectionState,
|
|
48
|
-
selection: FieldNode,
|
|
49
|
-
indirectPath: string[],
|
|
50
|
-
deferred?: boolean,
|
|
51
|
-
segments: FieldPathInfo[] = [],
|
|
52
|
-
) {
|
|
53
|
-
if (selection.name.value.startsWith('__')) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const { pothosDrizzleSelect, pothosIndirectInclude } = (type.extensions ?? {}) as {
|
|
58
|
-
pothosIndirectInclude?: IndirectInclude;
|
|
59
|
-
pothosDrizzleSelect?: boolean | DBQueryConfig<'one'>;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
(!!pothosIndirectInclude?.path && pothosIndirectInclude.path.length > 0) ||
|
|
64
|
-
(!!pothosIndirectInclude?.paths && pothosIndirectInclude.paths.length === 0)
|
|
65
|
-
) {
|
|
66
|
-
resolveIndirectIncludePaths(
|
|
67
|
-
type,
|
|
68
|
-
info,
|
|
69
|
-
selection,
|
|
70
|
-
[],
|
|
71
|
-
pothosIndirectInclude.paths ?? [pothosIndirectInclude.path!],
|
|
72
|
-
indirectPath,
|
|
73
|
-
(resolvedType, field, path) => {
|
|
74
|
-
addTypeSelectionsForField(
|
|
75
|
-
config,
|
|
76
|
-
resolvedType,
|
|
77
|
-
context,
|
|
78
|
-
info,
|
|
79
|
-
state,
|
|
80
|
-
field,
|
|
81
|
-
path,
|
|
82
|
-
deferred,
|
|
83
|
-
segments,
|
|
84
|
-
);
|
|
85
|
-
},
|
|
86
|
-
deferred,
|
|
87
|
-
);
|
|
88
|
-
} else if (pothosIndirectInclude) {
|
|
89
|
-
addTypeSelectionsForField(
|
|
90
|
-
config,
|
|
91
|
-
info.schema.getType(pothosIndirectInclude.getType())!,
|
|
92
|
-
context,
|
|
93
|
-
info,
|
|
94
|
-
state,
|
|
95
|
-
selection,
|
|
96
|
-
indirectPath,
|
|
97
|
-
deferred,
|
|
98
|
-
segments,
|
|
99
|
-
);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!(isObjectType(type) || isInterfaceType(type))) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (pothosDrizzleSelect) {
|
|
108
|
-
mergeSelection(config, state, pothosDrizzleSelect === true ? true : { ...pothosDrizzleSelect });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (selection.selectionSet && (!deferred || !state.skipDeferredFragments)) {
|
|
112
|
-
addNestedSelections(
|
|
113
|
-
config,
|
|
114
|
-
type,
|
|
115
|
-
context,
|
|
116
|
-
info,
|
|
117
|
-
state,
|
|
118
|
-
selection.selectionSet,
|
|
119
|
-
indirectPath,
|
|
120
|
-
segments,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function resolveIndirectIncludePaths(
|
|
126
|
-
type: GraphQLNamedType,
|
|
127
|
-
info: GraphQLResolveInfo,
|
|
128
|
-
selection: FieldNode | FragmentDefinitionNode | InlineFragmentNode,
|
|
129
|
-
pathPrefix: { type?: string; name: string }[],
|
|
130
|
-
includePaths: { type?: string; name: string }[][],
|
|
131
|
-
path: string[],
|
|
132
|
-
resolve: (type: GraphQLNamedType, field: FieldNode, path: string[], deferred: boolean) => void,
|
|
133
|
-
deferred?: boolean,
|
|
134
|
-
) {
|
|
135
|
-
for (const includePath of includePaths) {
|
|
136
|
-
if (pathPrefix.length > 0) {
|
|
137
|
-
resolveIndirectInclude(
|
|
138
|
-
type,
|
|
139
|
-
info,
|
|
140
|
-
selection,
|
|
141
|
-
[...pathPrefix, ...includePath],
|
|
142
|
-
path,
|
|
143
|
-
resolve,
|
|
144
|
-
deferred,
|
|
145
|
-
);
|
|
146
|
-
} else {
|
|
147
|
-
resolveIndirectInclude(type, info, selection, includePath, path, resolve, deferred);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function resolveIndirectInclude(
|
|
153
|
-
type: GraphQLNamedType,
|
|
154
|
-
info: GraphQLResolveInfo,
|
|
155
|
-
selection: FieldNode | FragmentDefinitionNode | InlineFragmentNode,
|
|
156
|
-
includePath: { type?: string; name: string }[],
|
|
157
|
-
path: string[],
|
|
158
|
-
resolve: (type: GraphQLNamedType, field: FieldNode, path: string[], deferred: boolean) => void,
|
|
159
|
-
deferred = false,
|
|
160
|
-
) {
|
|
161
|
-
if (includePath.length === 0) {
|
|
162
|
-
resolve(type, selection as FieldNode, path, deferred);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const [include, ...rest] = includePath;
|
|
167
|
-
if (!selection.selectionSet || !include) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
for (const sel of selection.selectionSet.selections) {
|
|
172
|
-
switch (sel.kind) {
|
|
173
|
-
case Kind.FIELD:
|
|
174
|
-
if (
|
|
175
|
-
!fieldSkipped(info, sel) &&
|
|
176
|
-
sel.name.value === include.name &&
|
|
177
|
-
(isObjectType(type) || isInterfaceType(type))
|
|
178
|
-
) {
|
|
179
|
-
const returnType = getNamedType(type.getFields()[sel.name.value].type);
|
|
180
|
-
|
|
181
|
-
resolveIndirectInclude(
|
|
182
|
-
returnType,
|
|
183
|
-
info,
|
|
184
|
-
sel,
|
|
185
|
-
rest,
|
|
186
|
-
[...path, sel.alias?.value ?? sel.name.value],
|
|
187
|
-
resolve,
|
|
188
|
-
deferred,
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
continue;
|
|
192
|
-
case Kind.FRAGMENT_SPREAD:
|
|
193
|
-
if (
|
|
194
|
-
!include.type ||
|
|
195
|
-
info.fragments[sel.name.value].typeCondition.name.value === include.type
|
|
196
|
-
) {
|
|
197
|
-
resolveIndirectInclude(
|
|
198
|
-
include.type ? info.schema.getType(include.type)! : type,
|
|
199
|
-
info,
|
|
200
|
-
info.fragments[sel.name.value],
|
|
201
|
-
includePath,
|
|
202
|
-
path,
|
|
203
|
-
resolve,
|
|
204
|
-
deferred || isDeferredFragment(sel, info),
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
continue;
|
|
209
|
-
|
|
210
|
-
case Kind.INLINE_FRAGMENT:
|
|
211
|
-
if (!sel.typeCondition || !include.type || sel.typeCondition.name.value === include.type) {
|
|
212
|
-
resolveIndirectInclude(
|
|
213
|
-
sel.typeCondition ? info.schema.getType(sel.typeCondition.name.value)! : type,
|
|
214
|
-
info,
|
|
215
|
-
sel,
|
|
216
|
-
includePath,
|
|
217
|
-
path,
|
|
218
|
-
resolve,
|
|
219
|
-
deferred || isDeferredFragment(sel, info),
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
continue;
|
|
224
|
-
|
|
225
|
-
default:
|
|
226
|
-
throw new PothosValidationError(
|
|
227
|
-
`Unsupported selection kind ${(selection as { kind: string }).kind}`,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function addNestedSelections(
|
|
234
|
-
config: PothosDrizzleSchemaConfig,
|
|
235
|
-
type: GraphQLInterfaceType | GraphQLObjectType,
|
|
236
|
-
context: object,
|
|
237
|
-
info: GraphQLResolveInfo,
|
|
238
|
-
state: SelectionState,
|
|
239
|
-
selections: SelectionSetNode,
|
|
240
|
-
indirectPath: string[],
|
|
241
|
-
segments: FieldPathInfo[] = [],
|
|
242
|
-
) {
|
|
243
|
-
let parentType = type;
|
|
244
|
-
for (const selection of selections.selections) {
|
|
245
|
-
switch (selection.kind) {
|
|
246
|
-
case Kind.FIELD:
|
|
247
|
-
addFieldSelection(config, type, context, info, state, selection, indirectPath, segments);
|
|
248
|
-
|
|
249
|
-
continue;
|
|
250
|
-
case Kind.FRAGMENT_SPREAD:
|
|
251
|
-
if (state.skipDeferredFragments && isDeferredFragment(selection, info)) {
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
parentType = info.schema.getType(
|
|
256
|
-
info.fragments[selection.name.value].typeCondition.name.value,
|
|
257
|
-
)! as GraphQLObjectType;
|
|
258
|
-
if (
|
|
259
|
-
isObjectType(type)
|
|
260
|
-
? parentType.name !== type.name
|
|
261
|
-
: parentType.extensions?.pothosDrizzleModel !== type.extensions.pothosDrizzleModel
|
|
262
|
-
) {
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
addNestedSelections(
|
|
267
|
-
config,
|
|
268
|
-
parentType,
|
|
269
|
-
context,
|
|
270
|
-
info,
|
|
271
|
-
state,
|
|
272
|
-
info.fragments[selection.name.value].selectionSet,
|
|
273
|
-
indirectPath,
|
|
274
|
-
segments,
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
continue;
|
|
278
|
-
|
|
279
|
-
case Kind.INLINE_FRAGMENT:
|
|
280
|
-
if (state.skipDeferredFragments && isDeferredFragment(selection, info)) {
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
parentType = selection.typeCondition
|
|
285
|
-
? (info.schema.getType(selection.typeCondition.name.value) as GraphQLObjectType)
|
|
286
|
-
: type;
|
|
287
|
-
if (
|
|
288
|
-
isObjectType(type)
|
|
289
|
-
? parentType.name !== type.name
|
|
290
|
-
: parentType.extensions?.pothosDrizzleModel !== type.extensions.pothosDrizzleModel
|
|
291
|
-
) {
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
addNestedSelections(
|
|
296
|
-
config,
|
|
297
|
-
parentType,
|
|
298
|
-
context,
|
|
299
|
-
info,
|
|
300
|
-
state,
|
|
301
|
-
selection.selectionSet,
|
|
302
|
-
indirectPath,
|
|
303
|
-
segments,
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
continue;
|
|
307
|
-
|
|
308
|
-
default:
|
|
309
|
-
throw new PothosValidationError(
|
|
310
|
-
`Unsupported selection kind ${(selection as { kind: string }).kind}`,
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function addFieldSelection(
|
|
317
|
-
config: PothosDrizzleSchemaConfig,
|
|
318
|
-
type: GraphQLInterfaceType | GraphQLObjectType,
|
|
319
|
-
context: object,
|
|
320
|
-
info: GraphQLResolveInfo,
|
|
321
|
-
state: SelectionState,
|
|
322
|
-
selection: FieldNode,
|
|
323
|
-
indirectPath: string[],
|
|
324
|
-
segments: FieldPathInfo[] = [],
|
|
325
|
-
) {
|
|
326
|
-
if (selection.name.value.startsWith('__') || fieldSkipped(info, selection)) {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
const field = type.getFields()[selection.name.value];
|
|
330
|
-
if (!field) {
|
|
331
|
-
throw new PothosValidationError(`Unknown field ${selection.name.value} on ${type.name}`);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const allSegments = [
|
|
335
|
-
...segments,
|
|
336
|
-
{
|
|
337
|
-
field: selection.name.value,
|
|
338
|
-
alias: selection.alias?.value ?? selection.name.value,
|
|
339
|
-
parentType: type.name,
|
|
340
|
-
isList: isListType(field.type) || isListType(getNamedType(field.type)),
|
|
341
|
-
},
|
|
342
|
-
];
|
|
343
|
-
|
|
344
|
-
const fieldSelect = field.extensions?.pothosDrizzleSelect as DrizzleFieldSelection | undefined;
|
|
345
|
-
|
|
346
|
-
let fieldSelectionMap: DBQueryConfig<'one'> | undefined;
|
|
347
|
-
let mappings: LoaderMappings = {};
|
|
348
|
-
if (typeof fieldSelect === 'function') {
|
|
349
|
-
const pathInfo: PathInfo = {
|
|
350
|
-
path: allSegments.map((s) => `${s.parentType}.${s.field}`),
|
|
351
|
-
segments: allSegments,
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
const args = getMappedArgumentValues(field, selection, context, info) as Record<
|
|
355
|
-
string,
|
|
356
|
-
unknown
|
|
357
|
-
>;
|
|
358
|
-
fieldSelectionMap = fieldSelect(
|
|
359
|
-
args,
|
|
360
|
-
context,
|
|
361
|
-
(rawQuery, indirectInclude, expectedType) => {
|
|
362
|
-
const returnType = getNamedType(field.type);
|
|
363
|
-
const query = typeof rawQuery === 'function' ? rawQuery(args, context) : rawQuery;
|
|
364
|
-
const normalizedIndirectInclude = Array.isArray(indirectInclude)
|
|
365
|
-
? normalizeInclude(
|
|
366
|
-
indirectInclude,
|
|
367
|
-
getIndirectType(returnType, info),
|
|
368
|
-
expectedType ? getNamedType(info.schema.getType(expectedType)) : undefined,
|
|
369
|
-
)
|
|
370
|
-
: indirectInclude;
|
|
371
|
-
const fieldState = createStateForSelection(
|
|
372
|
-
config,
|
|
373
|
-
info,
|
|
374
|
-
normalizedIndirectInclude
|
|
375
|
-
? info.schema.getType(normalizedIndirectInclude.getType())!
|
|
376
|
-
: returnType,
|
|
377
|
-
state,
|
|
378
|
-
);
|
|
379
|
-
|
|
380
|
-
if (typeof query === 'object' && Object.keys(query).length > 0) {
|
|
381
|
-
mergeSelection(config, fieldState, { columns: {}, ...query });
|
|
382
|
-
}
|
|
383
|
-
if (
|
|
384
|
-
(!!normalizedIndirectInclude?.path && normalizedIndirectInclude.path.length > 0) ||
|
|
385
|
-
(!!normalizedIndirectInclude?.paths && normalizedIndirectInclude.paths.length > 0)
|
|
386
|
-
) {
|
|
387
|
-
resolveIndirectIncludePaths(
|
|
388
|
-
returnType,
|
|
389
|
-
info,
|
|
390
|
-
selection,
|
|
391
|
-
(returnType.extensions?.pothosIndirectInclude as { path: [] })?.path ?? [],
|
|
392
|
-
normalizedIndirectInclude.paths ?? [normalizedIndirectInclude.path!],
|
|
393
|
-
[],
|
|
394
|
-
(resolvedType, resolvedField, path, deferred) => {
|
|
395
|
-
addTypeSelectionsForField(
|
|
396
|
-
config,
|
|
397
|
-
resolvedType,
|
|
398
|
-
context,
|
|
399
|
-
info,
|
|
400
|
-
fieldState,
|
|
401
|
-
resolvedField,
|
|
402
|
-
path,
|
|
403
|
-
deferred,
|
|
404
|
-
allSegments,
|
|
405
|
-
);
|
|
406
|
-
},
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
addTypeSelectionsForField(
|
|
410
|
-
config,
|
|
411
|
-
returnType,
|
|
412
|
-
context,
|
|
413
|
-
info,
|
|
414
|
-
fieldState,
|
|
415
|
-
selection,
|
|
416
|
-
[],
|
|
417
|
-
undefined,
|
|
418
|
-
allSegments,
|
|
419
|
-
);
|
|
420
|
-
mappings = fieldState.mappings;
|
|
421
|
-
return selectionToQuery(config, fieldState);
|
|
422
|
-
},
|
|
423
|
-
(path) => {
|
|
424
|
-
const returnType = getNamedType(field.type);
|
|
425
|
-
let node: FieldNode | null = null;
|
|
426
|
-
resolveIndirectInclude(
|
|
427
|
-
returnType,
|
|
428
|
-
info,
|
|
429
|
-
selection,
|
|
430
|
-
path.map((name) => ({
|
|
431
|
-
name,
|
|
432
|
-
})),
|
|
433
|
-
[],
|
|
434
|
-
(_, resolvedField) => {
|
|
435
|
-
node = resolvedField;
|
|
436
|
-
},
|
|
437
|
-
);
|
|
438
|
-
return node;
|
|
439
|
-
},
|
|
440
|
-
pathInfo,
|
|
441
|
-
);
|
|
442
|
-
} else {
|
|
443
|
-
fieldSelectionMap = fieldSelect!;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if (fieldSelect && selectionCompatible(state, fieldSelectionMap, true)) {
|
|
447
|
-
mergeSelection(config, state, fieldSelectionMap);
|
|
448
|
-
|
|
449
|
-
state.mappings = mergeMappings(state.mappings, {
|
|
450
|
-
[selection.alias?.value ?? selection.name.value]: {
|
|
451
|
-
field: selection.name.value,
|
|
452
|
-
type: type.name,
|
|
453
|
-
mappings,
|
|
454
|
-
indirectPath,
|
|
455
|
-
},
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function mergeMappings(existing: LoaderMappings, incoming: LoaderMappings): LoaderMappings {
|
|
461
|
-
const result: LoaderMappings = { ...existing };
|
|
462
|
-
|
|
463
|
-
for (const [key, value] of Object.entries(incoming)) {
|
|
464
|
-
if (result[key]) {
|
|
465
|
-
result[key] = {
|
|
466
|
-
...result[key],
|
|
467
|
-
mappings: mergeMappings(result[key].mappings, value.mappings),
|
|
468
|
-
};
|
|
469
|
-
} else {
|
|
470
|
-
result[key] = value;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
return result;
|
|
475
|
-
}
|
|
6
|
+
import type { SelectionMap } from './selections.js';
|
|
476
7
|
|
|
477
8
|
export interface QueryFromInfoOptions<T extends SelectionMap> {
|
|
478
9
|
config: PothosDrizzleSchemaConfig;
|
|
@@ -480,248 +11,60 @@ export interface QueryFromInfoOptions<T extends SelectionMap> {
|
|
|
480
11
|
info: GraphQLResolveInfo;
|
|
481
12
|
typeName?: string;
|
|
482
13
|
select?: T;
|
|
483
|
-
path?:
|
|
484
|
-
paths?:
|
|
485
|
-
withUsageCheck?: boolean;
|
|
14
|
+
path?: PathSegment[];
|
|
15
|
+
paths?: PathSegment[][];
|
|
486
16
|
}
|
|
487
17
|
|
|
488
18
|
export function queryFromInfo<T extends SelectionMap>({
|
|
489
|
-
withUsageCheck,
|
|
490
|
-
...options
|
|
491
|
-
}: QueryFromInfoOptions<T>): T {
|
|
492
|
-
const state = stateFromInfo(options);
|
|
493
|
-
|
|
494
|
-
setLoaderMappings(options.context, options.info, state.mappings);
|
|
495
|
-
|
|
496
|
-
const query = selectionToQuery(options.config, state) as T;
|
|
497
|
-
|
|
498
|
-
return withUsageCheck ? wrapWithUsageCheck(query) : query;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
export function stateFromInfo<T extends SelectionMap>({
|
|
502
19
|
config,
|
|
503
|
-
context,
|
|
504
|
-
info,
|
|
505
|
-
typeName,
|
|
506
20
|
select,
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
columns: {},
|
|
515
|
-
...select,
|
|
516
|
-
}
|
|
517
|
-
: undefined;
|
|
518
|
-
|
|
519
|
-
let state: SelectionState | undefined;
|
|
520
|
-
|
|
521
|
-
if (path.length > 0 || paths.length > 0) {
|
|
522
|
-
const { pothosIndirectInclude } = (returnType.extensions ?? {}) as {
|
|
523
|
-
pothosIndirectInclude?: IndirectInclude;
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
resolveIndirectInclude(
|
|
527
|
-
returnType,
|
|
528
|
-
info,
|
|
529
|
-
info.fieldNodes[0],
|
|
530
|
-
pothosIndirectInclude?.path ?? [],
|
|
531
|
-
[],
|
|
532
|
-
(indirectType, indirectField, subPath, deferred) => {
|
|
533
|
-
resolveIndirectIncludePaths(
|
|
534
|
-
indirectType,
|
|
535
|
-
info,
|
|
536
|
-
indirectField,
|
|
537
|
-
[],
|
|
538
|
-
paths.length > 0
|
|
539
|
-
? paths.map((p) => p.map((n) => (typeof n === 'string' ? { name: n } : n)))
|
|
540
|
-
: [path.map((n) => (typeof n === 'string' ? { name: n } : n))],
|
|
541
|
-
subPath,
|
|
542
|
-
(resolvedType, resolvedField, nested, deferred) => {
|
|
543
|
-
state = createStateForSelection(
|
|
544
|
-
config,
|
|
545
|
-
info,
|
|
546
|
-
resolvedType,
|
|
547
|
-
undefined,
|
|
548
|
-
initialSelection,
|
|
549
|
-
);
|
|
550
|
-
|
|
551
|
-
addTypeSelectionsForField(
|
|
552
|
-
config,
|
|
553
|
-
typeName ? type : resolvedType,
|
|
554
|
-
context,
|
|
555
|
-
info,
|
|
556
|
-
state,
|
|
557
|
-
resolvedField,
|
|
558
|
-
nested,
|
|
559
|
-
deferred,
|
|
560
|
-
);
|
|
561
|
-
},
|
|
562
|
-
deferred,
|
|
563
|
-
);
|
|
564
|
-
},
|
|
565
|
-
);
|
|
566
|
-
} else {
|
|
567
|
-
state = createStateForSelection(config, info, type, undefined, initialSelection);
|
|
568
|
-
|
|
569
|
-
// Create initial segment for the root query field
|
|
570
|
-
const rootFieldNode = info.fieldNodes[0];
|
|
571
|
-
const rootField = info.parentType.getFields()[rootFieldNode.name.value];
|
|
572
|
-
const initialSegments: FieldPathInfo[] = rootField
|
|
573
|
-
? [
|
|
574
|
-
{
|
|
575
|
-
field: rootFieldNode.name.value,
|
|
576
|
-
alias: rootFieldNode.alias?.value ?? rootFieldNode.name.value,
|
|
577
|
-
parentType: info.parentType.name,
|
|
578
|
-
isList: isListType(rootField.type) || isListType(getNamedType(rootField.type)),
|
|
579
|
-
},
|
|
580
|
-
]
|
|
581
|
-
: [];
|
|
582
|
-
|
|
583
|
-
addTypeSelectionsForField(
|
|
584
|
-
config,
|
|
585
|
-
type,
|
|
586
|
-
context,
|
|
587
|
-
info,
|
|
588
|
-
state,
|
|
589
|
-
info.fieldNodes[0],
|
|
590
|
-
[],
|
|
591
|
-
undefined,
|
|
592
|
-
initialSegments,
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
if (!state) {
|
|
597
|
-
state = createStateForSelection(config, info, type, undefined, initialSelection);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
return state;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
export function selectionStateFromInfo(
|
|
604
|
-
config: PothosDrizzleSchemaConfig,
|
|
605
|
-
context: object,
|
|
606
|
-
info: GraphQLResolveInfo,
|
|
607
|
-
typeName?: string,
|
|
608
|
-
) {
|
|
609
|
-
const type = typeName ? info.schema.getTypeMap()[typeName] : info.parentType;
|
|
610
|
-
|
|
611
|
-
const state = createStateForSelection(config, info, type);
|
|
612
|
-
|
|
613
|
-
if (!(isObjectType(type) || isInterfaceType(type))) {
|
|
614
|
-
throw new PothosValidationError(
|
|
615
|
-
'Drizzle plugin can only resolve selections for object and interface types',
|
|
616
|
-
);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
addFieldSelection(config, type, context, info, state, info.fieldNodes[0], []);
|
|
620
|
-
|
|
621
|
-
return state;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
function createStateForSelection(
|
|
625
|
-
config: PothosDrizzleSchemaConfig,
|
|
626
|
-
info: GraphQLResolveInfo,
|
|
627
|
-
type: GraphQLNamedType,
|
|
628
|
-
parent?: SelectionState,
|
|
629
|
-
initialSelections?: SelectionMap,
|
|
630
|
-
) {
|
|
631
|
-
const targetType = getIndirectType(type, info);
|
|
632
|
-
const { pothosDrizzleTable } = (targetType.extensions ?? {}) as {
|
|
633
|
-
pothosDrizzleTable?: TableRelationalConfig;
|
|
634
|
-
};
|
|
635
|
-
|
|
636
|
-
if (!pothosDrizzleTable) {
|
|
637
|
-
throw new PothosValidationError(`Expected ${targetType.name} to have a table config`);
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
const state = createState(
|
|
641
|
-
pothosDrizzleTable,
|
|
642
|
-
parent?.skipDeferredFragments ?? config.skipDeferredFragments,
|
|
643
|
-
parent,
|
|
644
|
-
);
|
|
645
|
-
|
|
646
|
-
if (initialSelections) {
|
|
647
|
-
mergeSelection(config, state, initialSelections);
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
return state;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
export function getIndirectType(type: GraphQLNamedType, info: GraphQLResolveInfo) {
|
|
654
|
-
let targetType = type;
|
|
655
|
-
|
|
656
|
-
while (targetType.extensions?.pothosIndirectInclude) {
|
|
657
|
-
targetType = info.schema.getType(
|
|
658
|
-
(targetType.extensions.pothosIndirectInclude as IndirectInclude).getType(),
|
|
659
|
-
)!;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
return targetType;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
export function normalizeInclude(
|
|
666
|
-
path: string[],
|
|
667
|
-
type: GraphQLNamedType,
|
|
668
|
-
expectedType?: GraphQLNamedType,
|
|
669
|
-
): IndirectInclude {
|
|
670
|
-
let currentType = path.length > 0 ? type : (expectedType ?? type);
|
|
671
|
-
|
|
672
|
-
const normalized: { name: string; type: string }[] = [];
|
|
673
|
-
|
|
674
|
-
if (!(isObjectType(currentType) || isInterfaceType(currentType))) {
|
|
675
|
-
throw new PothosValidationError(`Expected ${currentType} to be an Object type`);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
for (const fieldName of path) {
|
|
679
|
-
const field: GraphQLField<unknown, unknown> = currentType.getFields()[fieldName];
|
|
680
|
-
|
|
681
|
-
if (!field) {
|
|
682
|
-
throw new PothosValidationError(`Expected ${currentType} to have a field ${fieldName}`);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
currentType = getNamedType(field.type);
|
|
686
|
-
|
|
687
|
-
if (!(isObjectType(currentType) || isInterfaceType(currentType))) {
|
|
688
|
-
throw new PothosValidationError(`Expected ${currentType} to be an Object or Interface type`);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
normalized.push({ name: fieldName, type: currentType.name });
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
return {
|
|
695
|
-
getType: () =>
|
|
696
|
-
expectedType?.name ??
|
|
697
|
-
(normalized.length > 0 ? normalized[normalized.length - 1].type : type.name),
|
|
698
|
-
path: normalized,
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
function fieldSkipped(info: GraphQLResolveInfo, selection: FieldNode) {
|
|
703
|
-
const skip = getDirectiveValues(GraphQLSkipDirective, selection, info.variableValues);
|
|
704
|
-
if (skip?.if === true) {
|
|
705
|
-
return true;
|
|
706
|
-
}
|
|
21
|
+
...options
|
|
22
|
+
}: QueryFromInfoOptions<T>): T {
|
|
23
|
+
const plan = Plan.fromInfo(drizzleAdapter(config), {
|
|
24
|
+
...options,
|
|
25
|
+
// A `select` without `columns` merges as "no columns yet", not "every column".
|
|
26
|
+
initial: select ? { columns: {}, ...select } : undefined,
|
|
27
|
+
});
|
|
707
28
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
return
|
|
29
|
+
if (!plan) {
|
|
30
|
+
// Nothing is planned under the paths: the caller gets its own selection back untouched.
|
|
31
|
+
return (select ?? {}) as T;
|
|
711
32
|
}
|
|
712
33
|
|
|
713
|
-
return
|
|
34
|
+
return (
|
|
35
|
+
isThenable(plan) ? plan.then((settled) => (settled as DrizzlePlan).query()) : plan.query()
|
|
36
|
+
) as T;
|
|
714
37
|
}
|
|
715
38
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
return
|
|
39
|
+
/**
|
|
40
|
+
* The plan for the field `info` resolves (or `typeName`), nothing recorded: a promise while a
|
|
41
|
+
* select beneath the field is async, undefined when `paths` are given and nothing is selected
|
|
42
|
+
* under them. The model loader's, and the first step of a `drizzleField` resolve, whose
|
|
43
|
+
* merges are recorded so the resolver's `query()` selection can come first.
|
|
44
|
+
*/
|
|
45
|
+
export function planFromInfo({
|
|
46
|
+
config,
|
|
47
|
+
...options
|
|
48
|
+
}: Omit<QueryFromInfoOptions<SelectionMap>, 'select'>): DrizzlePlan | undefined {
|
|
49
|
+
return Plan.fromInfo(drizzleAdapter(config), options);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The query for a plan `planFromInfo` returned, settled: the caller's `select` first, the walked
|
|
54
|
+
* plan after it, the mappings recorded, and the query serialized. This is how the `query()`
|
|
55
|
+
* builder handed to a `drizzleField` or `drizzleConnection` resolver stays synchronous once a
|
|
56
|
+
* selection beneath the field is async, with the precedence of `queryFromInfo`: a relation the
|
|
57
|
+
* document also plans with other arguments loads on its own.
|
|
58
|
+
*/
|
|
59
|
+
export function queryFromPlan<T extends SelectionMap>(
|
|
60
|
+
plan: DrizzlePlan | undefined,
|
|
61
|
+
select?: T,
|
|
62
|
+
): T {
|
|
63
|
+
if (!plan) {
|
|
64
|
+
// Nothing is selected under the paths: the caller gets its own selection back.
|
|
65
|
+
return (select ?? {}) as T;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// A `select` without `columns` merges as "no columns yet", not "every column".
|
|
69
|
+
return plan.query(select ? { columns: {}, ...select } : undefined) as T;
|
|
727
70
|
}
|