@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/field-builder.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import type { FieldRef, MaybePromise } from '@pothos/core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type FieldKind,
|
|
4
|
+
isThenable,
|
|
5
|
+
ObjectRef,
|
|
6
|
+
RootFieldBuilder,
|
|
7
|
+
type SchemaTypes,
|
|
8
|
+
} from '@pothos/core';
|
|
3
9
|
import type { TableRelationalConfig } from 'drizzle-orm';
|
|
4
10
|
import type { GraphQLResolveInfo } from 'graphql';
|
|
5
|
-
import { isInterfaceType, isObjectType, Kind } from 'graphql';
|
|
11
|
+
import { getNamedType, isInterfaceType, isObjectType, Kind } from 'graphql';
|
|
6
12
|
import type { DrizzleRef } from './interface-ref.js';
|
|
7
13
|
import type { DrizzleConnectionFieldOptions } from './types.js';
|
|
14
|
+
import type { DrizzlePlan } from './utils/adapter.js';
|
|
8
15
|
import { getSchemaConfig } from './utils/config.js';
|
|
9
16
|
import { resolveDrizzleCursorConnection } from './utils/cursors.js';
|
|
10
|
-
import {
|
|
17
|
+
import { planFromInfo, queryFromPlan } from './utils/map-query.js';
|
|
11
18
|
import { getRefFromModel } from './utils/refs.js';
|
|
12
19
|
import type { SelectionMap } from './utils/selections.js';
|
|
13
20
|
|
|
@@ -17,34 +24,56 @@ const fieldBuilderProto = RootFieldBuilder.prototype as PothosSchemaTypes.RootFi
|
|
|
17
24
|
FieldKind
|
|
18
25
|
>;
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
type DrizzleFieldType =
|
|
28
|
+
| ObjectRef<SchemaTypes, unknown>
|
|
29
|
+
| [ObjectRef<SchemaTypes, unknown> | string];
|
|
30
|
+
|
|
31
|
+
/** The `type` of a `drizzleField`, with a table name resolved to its ref, list-ness kept. */
|
|
32
|
+
function refForType(
|
|
33
|
+
builder: PothosSchemaTypes.SchemaBuilder<SchemaTypes>,
|
|
34
|
+
type: DrizzleFieldType | string,
|
|
35
|
+
) {
|
|
21
36
|
const modelOrRef = Array.isArray(type) ? type[0] : type;
|
|
22
37
|
const typeRef =
|
|
23
38
|
typeof modelOrRef === 'string'
|
|
24
|
-
? getRefFromModel(modelOrRef,
|
|
39
|
+
? getRefFromModel(modelOrRef, builder)
|
|
25
40
|
: (modelOrRef as ObjectRef<SchemaTypes, unknown>);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
|
|
42
|
+
return Array.isArray(type) ? ([typeRef] as [ObjectRef<SchemaTypes, unknown>]) : typeRef;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The resolver of a `drizzleField`: the plan for the field, then the user's resolver with a query
|
|
47
|
+
* builder over it. A promise while a selection beneath the field is async, so the resolver runs
|
|
48
|
+
* once the plan has settled and the builder it is handed never returns one. Built once per field,
|
|
49
|
+
* so a synchronous plan allocates nothing but the builder itself.
|
|
50
|
+
*/
|
|
51
|
+
function planResolver(
|
|
52
|
+
builder: PothosSchemaTypes.SchemaBuilder<SchemaTypes>,
|
|
53
|
+
resolve: (...args: unknown[]) => unknown,
|
|
54
|
+
) {
|
|
55
|
+
const run = (
|
|
56
|
+
plan: DrizzlePlan | undefined,
|
|
57
|
+
parent: unknown,
|
|
58
|
+
args: unknown,
|
|
59
|
+
context: {},
|
|
60
|
+
info: GraphQLResolveInfo,
|
|
61
|
+
) => resolve((select?: SelectionMap) => queryFromPlan(plan, select), parent, args, context, info);
|
|
62
|
+
|
|
63
|
+
return (parent: unknown, args: unknown, context: {}, info: GraphQLResolveInfo) => {
|
|
64
|
+
const plan = planFromInfo({ config: getSchemaConfig(builder), context, info });
|
|
65
|
+
|
|
66
|
+
return isThenable(plan)
|
|
67
|
+
? plan.then((settled) => run(settled as DrizzlePlan | undefined, parent, args, context, info))
|
|
68
|
+
: run(plan, parent, args, context, info);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fieldBuilderProto.drizzleField = function drizzleField({ type, resolve, ...options }) {
|
|
29
73
|
return this.field({
|
|
30
74
|
...(options as {}),
|
|
31
|
-
type:
|
|
32
|
-
resolve: (
|
|
33
|
-
return resolve(
|
|
34
|
-
(select) =>
|
|
35
|
-
queryFromInfo({
|
|
36
|
-
config: getSchemaConfig(this.builder),
|
|
37
|
-
context,
|
|
38
|
-
select,
|
|
39
|
-
info,
|
|
40
|
-
// withUsageCheck: !!this.builder.options.drizzle?.onUnusedQuery,
|
|
41
|
-
}) as never,
|
|
42
|
-
parent,
|
|
43
|
-
args as never,
|
|
44
|
-
context,
|
|
45
|
-
info,
|
|
46
|
-
) as never;
|
|
47
|
-
},
|
|
75
|
+
type: refForType(this.builder, type as DrizzleFieldType),
|
|
76
|
+
resolve: planResolver(this.builder, resolve as never),
|
|
48
77
|
}) as never;
|
|
49
78
|
};
|
|
50
79
|
|
|
@@ -54,38 +83,14 @@ fieldBuilderProto.drizzleFieldWithInput = function drizzleFieldWithInput(
|
|
|
54
83
|
type,
|
|
55
84
|
resolve,
|
|
56
85
|
...options
|
|
57
|
-
}: { type:
|
|
86
|
+
}: { type: DrizzleFieldType; resolve: (...args: unknown[]) => unknown },
|
|
58
87
|
) {
|
|
59
|
-
const modelOrRef = Array.isArray(type) ? type[0] : type;
|
|
60
|
-
const typeRef =
|
|
61
|
-
typeof modelOrRef === 'string'
|
|
62
|
-
? getRefFromModel(modelOrRef, this.builder)
|
|
63
|
-
: (modelOrRef as ObjectRef<SchemaTypes, unknown>);
|
|
64
|
-
const typeParam = Array.isArray(type)
|
|
65
|
-
? ([typeRef] as [ObjectRef<SchemaTypes, unknown>])
|
|
66
|
-
: typeRef;
|
|
67
|
-
|
|
68
88
|
return (
|
|
69
89
|
this as typeof fieldBuilderProto & { fieldWithInput: typeof fieldBuilderProto.field }
|
|
70
90
|
).fieldWithInput({
|
|
71
91
|
...(options as {}),
|
|
72
|
-
type:
|
|
73
|
-
resolve: (
|
|
74
|
-
return resolve(
|
|
75
|
-
(select: SelectionMap) =>
|
|
76
|
-
queryFromInfo({
|
|
77
|
-
config: getSchemaConfig(this.builder),
|
|
78
|
-
context,
|
|
79
|
-
select,
|
|
80
|
-
info,
|
|
81
|
-
// withUsageCheck: !!this.builder.options.drizzle?.onUnusedQuery,
|
|
82
|
-
}),
|
|
83
|
-
parent,
|
|
84
|
-
args as never,
|
|
85
|
-
context,
|
|
86
|
-
info,
|
|
87
|
-
) as never;
|
|
88
|
-
},
|
|
92
|
+
type: refForType(this.builder, type),
|
|
93
|
+
resolve: planResolver(this.builder, resolve),
|
|
89
94
|
}) as never;
|
|
90
95
|
} as never;
|
|
91
96
|
|
|
@@ -121,6 +126,38 @@ fieldBuilderProto.drizzleConnection = function drizzleConnection<
|
|
|
121
126
|
const ref = typeof type === 'string' ? getRefFromModel(type, this.builder) : type;
|
|
122
127
|
const typeName = this.builder.configStore.getTypeConfig(ref).name;
|
|
123
128
|
const tableName = typeof type === 'string' ? type : (ref as DrizzleRef<SchemaTypes>).tableName;
|
|
129
|
+
|
|
130
|
+
// Built once per field: resolving with a synchronous plan allocates nothing beyond the
|
|
131
|
+
// callback `resolveDrizzleCursorConnection` was already handed.
|
|
132
|
+
const resolveConnection = (
|
|
133
|
+
plan: DrizzlePlan | undefined,
|
|
134
|
+
parent: unknown,
|
|
135
|
+
args: PothosSchemaTypes.DefaultConnectionArguments,
|
|
136
|
+
context: {},
|
|
137
|
+
info: GraphQLResolveInfo,
|
|
138
|
+
totalCountOnly: boolean,
|
|
139
|
+
) =>
|
|
140
|
+
resolveDrizzleCursorConnection(
|
|
141
|
+
tableName,
|
|
142
|
+
plan,
|
|
143
|
+
getSchemaConfig(this.builder),
|
|
144
|
+
{
|
|
145
|
+
ctx: context,
|
|
146
|
+
maxSize,
|
|
147
|
+
defaultSize,
|
|
148
|
+
args,
|
|
149
|
+
totalCount: totalCount && (() => totalCount(parent, args as never, context, info)),
|
|
150
|
+
},
|
|
151
|
+
(q) => {
|
|
152
|
+
if (totalCountOnly) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return resolve(q as never, parent, args as never, context, info) as never;
|
|
157
|
+
},
|
|
158
|
+
parent,
|
|
159
|
+
);
|
|
160
|
+
|
|
124
161
|
const fieldRef = (
|
|
125
162
|
this as typeof fieldBuilderProto & {
|
|
126
163
|
connection: (...args: unknown[]) => FieldRef<SchemaTypes, unknown>;
|
|
@@ -135,7 +172,7 @@ fieldBuilderProto.drizzleConnection = function drizzleConnection<
|
|
|
135
172
|
context: {},
|
|
136
173
|
info: GraphQLResolveInfo,
|
|
137
174
|
) => {
|
|
138
|
-
const returnType = info.returnType;
|
|
175
|
+
const returnType = getNamedType(info.returnType);
|
|
139
176
|
const fields =
|
|
140
177
|
isObjectType(returnType) || isInterfaceType(returnType) ? returnType.getFields() : {};
|
|
141
178
|
|
|
@@ -150,32 +187,28 @@ fieldBuilderProto.drizzleConnection = function drizzleConnection<
|
|
|
150
187
|
),
|
|
151
188
|
);
|
|
152
189
|
|
|
153
|
-
|
|
154
|
-
|
|
190
|
+
// Planned before the resolver runs, so the builder it is handed is synchronous even when
|
|
191
|
+
// a selection beneath the connection is async.
|
|
192
|
+
const plan = planFromInfo({
|
|
193
|
+
config: getSchemaConfig(this.builder),
|
|
194
|
+
context,
|
|
155
195
|
info,
|
|
196
|
+
paths: [['nodes'], ['edges', 'node']],
|
|
156
197
|
typeName,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// this.builder,
|
|
172
|
-
// query,
|
|
173
|
-
// info,
|
|
174
|
-
return resolve(q as never, parent, args as never, context, info) as never;
|
|
175
|
-
// );
|
|
176
|
-
},
|
|
177
|
-
parent,
|
|
178
|
-
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return isThenable(plan)
|
|
201
|
+
? plan.then((settled) =>
|
|
202
|
+
resolveConnection(
|
|
203
|
+
settled as DrizzlePlan | undefined,
|
|
204
|
+
parent,
|
|
205
|
+
args,
|
|
206
|
+
context,
|
|
207
|
+
info,
|
|
208
|
+
totalCountOnly,
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
: resolveConnection(plan, parent, args, context, info, totalCountOnly);
|
|
179
212
|
},
|
|
180
213
|
},
|
|
181
214
|
connectionOptions instanceof ObjectRef
|
package/src/global-types.ts
CHANGED
|
@@ -184,38 +184,6 @@ declare global {
|
|
|
184
184
|
type: Type,
|
|
185
185
|
fields: (t: DrizzleObjectFieldBuilder<Types, TableConfig, Shape>) => FieldMap,
|
|
186
186
|
) => void;
|
|
187
|
-
|
|
188
|
-
// drizzleGraphQLOrderBy: 'addGraphQL' extends PluginName
|
|
189
|
-
// ? <Table extends keyof Types['DrizzleRelations']>(
|
|
190
|
-
// table: Table,
|
|
191
|
-
// type: GraphQLInputObjectType,
|
|
192
|
-
// ...args: NormalizeArgs<[options: AddGraphQLInputTypeOptions<Types, {}>]>
|
|
193
|
-
// ) => InputObjectRef<Types, SQL | SQL[]>
|
|
194
|
-
// : '@pothos/plugin-add-graphql is required to use this method';
|
|
195
|
-
|
|
196
|
-
// drizzleGraphQLFilters: 'addGraphQL' extends PluginName
|
|
197
|
-
// ? <Table extends keyof Types['DrizzleRelations']>(
|
|
198
|
-
// table: Table,
|
|
199
|
-
// type: GraphQLInputObjectType,
|
|
200
|
-
// ...args: NormalizeArgs<[options: AddGraphQLInputTypeOptions<Types, {}>]>
|
|
201
|
-
// ) => InputObjectRef<Types, SQL>
|
|
202
|
-
// : '@pothos/plugin-add-graphql is required to use this method';
|
|
203
|
-
|
|
204
|
-
// drizzleGraphQLInsert: 'addGraphQL' extends PluginName
|
|
205
|
-
// ? <Table extends keyof Types['DrizzleRelations']>(
|
|
206
|
-
// table: Table,
|
|
207
|
-
// type: GraphQLInputObjectType,
|
|
208
|
-
// ...args: NormalizeArgs<[options: AddGraphQLInputTypeOptions<Types, {}>]>
|
|
209
|
-
// ) => InputObjectRef<Types, Record<string, unknown>>
|
|
210
|
-
// : '@pothos/plugin-add-graphql is required to use this method';
|
|
211
|
-
|
|
212
|
-
// drizzleGraphQLUpdate: 'addGraphQL' extends PluginName
|
|
213
|
-
// ? <Table extends keyof Types['DrizzleRelations']>(
|
|
214
|
-
// table: Table,
|
|
215
|
-
// type: GraphQLInputObjectType,
|
|
216
|
-
// ...args: NormalizeArgs<[options: AddGraphQLInputTypeOptions<Types, {}>]>
|
|
217
|
-
// ) => InputObjectRef<Types, Record<string, unknown>>
|
|
218
|
-
// : '@pothos/plugin-add-graphql is required to use this method';
|
|
219
187
|
}
|
|
220
188
|
|
|
221
189
|
export interface PothosKindToGraphQLType {
|
package/src/index.ts
CHANGED
|
@@ -3,14 +3,17 @@ import './field-builder.js';
|
|
|
3
3
|
import './schema-builder.js';
|
|
4
4
|
import SchemaBuilder, {
|
|
5
5
|
BasePlugin,
|
|
6
|
+
completeValue,
|
|
6
7
|
type PothosOutputFieldConfig,
|
|
7
8
|
PothosSchemaError,
|
|
8
9
|
type PothosTypeConfig,
|
|
9
10
|
type SchemaTypes,
|
|
10
11
|
} from '@pothos/core';
|
|
11
|
-
import
|
|
12
|
+
import { getLoaderMapping, setFieldMapping } from '@pothos/selection-mapper';
|
|
13
|
+
import type { TableRelationalConfig } from 'drizzle-orm';
|
|
14
|
+
import type { GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql';
|
|
12
15
|
import type { ModelLoader } from './model-loader.js';
|
|
13
|
-
import {
|
|
16
|
+
import type { PathInfo } from './types.js';
|
|
14
17
|
|
|
15
18
|
export { drizzleConnectionHelpers } from './connection-helpers.js';
|
|
16
19
|
export { DrizzleObjectFieldBuilder } from './drizzle-field-builder.js';
|
|
@@ -23,29 +26,31 @@ const pluginName = 'drizzle';
|
|
|
23
26
|
export default pluginName;
|
|
24
27
|
|
|
25
28
|
export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
|
|
26
|
-
// private mappingCache = new Map<
|
|
27
|
-
// string,
|
|
28
|
-
// InputTypeFieldsMapping<Types, DrizzleGraphQLInputExtensions>
|
|
29
|
-
// >();
|
|
30
29
|
override onTypeConfig(typeConfig: PothosTypeConfig): PothosTypeConfig {
|
|
31
30
|
if (typeConfig.kind !== 'Object' && typeConfig.kind !== 'Interface') {
|
|
32
31
|
return typeConfig;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
let model = typeConfig.extensions?.pothosDrizzleModel as string | undefined;
|
|
35
|
+
let table = typeConfig.extensions?.pothosDrizzleTable as TableRelationalConfig | undefined;
|
|
36
36
|
|
|
37
37
|
for (const iface of typeConfig.interfaces) {
|
|
38
|
-
const
|
|
39
|
-
|
|
38
|
+
const interfaceConfig = this.buildCache.getTypeConfig(iface, 'Interface');
|
|
39
|
+
const interfaceModel = interfaceConfig.extensions?.pothosDrizzleModel as string | undefined;
|
|
40
40
|
|
|
41
41
|
if (interfaceModel) {
|
|
42
42
|
if (model && model !== interfaceModel) {
|
|
43
43
|
throw new PothosSchemaError(
|
|
44
|
-
`DrizzleObjects must be based on the same
|
|
44
|
+
`DrizzleObjects must be based on the same drizzle table as any DrizzleInterfaces they extend. ${typeConfig.name} uses ${model} and ${iface.name} uses ${interfaceModel}`,
|
|
45
45
|
);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
model = interfaceModel;
|
|
49
|
+
// A plain object type implementing a drizzle interface is walked with the interface's
|
|
50
|
+
// table, so fragments on it plan the relations it inherits.
|
|
51
|
+
table ??= interfaceConfig.extensions?.pothosDrizzleTable as
|
|
52
|
+
| TableRelationalConfig
|
|
53
|
+
| undefined;
|
|
49
54
|
}
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -54,6 +59,7 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
54
59
|
extensions: {
|
|
55
60
|
...typeConfig.extensions,
|
|
56
61
|
pothosDrizzleModel: model,
|
|
62
|
+
pothosDrizzleTable: table,
|
|
57
63
|
},
|
|
58
64
|
};
|
|
59
65
|
}
|
|
@@ -61,49 +67,6 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
61
67
|
override onOutputFieldConfig(
|
|
62
68
|
fieldConfig: PothosOutputFieldConfig<Types>,
|
|
63
69
|
): PothosOutputFieldConfig<Types> | null {
|
|
64
|
-
// const argMappings = mapInputFields<Types, DrizzleGraphQLInputExtensions>(
|
|
65
|
-
// fieldConfig.args,
|
|
66
|
-
// this.buildCache,
|
|
67
|
-
// (inputField) => {
|
|
68
|
-
// if (inputField.type.kind === 'InputObject') {
|
|
69
|
-
// const config = this.buildCache.getTypeConfig(inputField.type.ref);
|
|
70
|
-
|
|
71
|
-
// return (config.extensions?.drizzleGraphQL as DrizzleGraphQLInputExtensions) ?? null;
|
|
72
|
-
// }
|
|
73
|
-
|
|
74
|
-
// return null;
|
|
75
|
-
// },
|
|
76
|
-
// this.mappingCache,
|
|
77
|
-
// );
|
|
78
|
-
|
|
79
|
-
// const argMapper = argMappings
|
|
80
|
-
// ? createInputValueMapper(argMappings, (input, mappings) => {
|
|
81
|
-
// if (!mappings.value) {
|
|
82
|
-
// return input;
|
|
83
|
-
// }
|
|
84
|
-
|
|
85
|
-
// const { table, tableConfig, inputType } = mappings.value;
|
|
86
|
-
|
|
87
|
-
// switch (inputType) {
|
|
88
|
-
// case 'orderBy':
|
|
89
|
-
// return extractOrderBy(tableConfig, input as never);
|
|
90
|
-
// case 'filters':
|
|
91
|
-
// return extractFilters(tableConfig, table, input as never);
|
|
92
|
-
// case 'insert':
|
|
93
|
-
// return remapFromGraphQLSingleInput(input as never, tableConfig);
|
|
94
|
-
// case 'update':
|
|
95
|
-
// return remapFromGraphQLSingleInput(input as never, tableConfig);
|
|
96
|
-
|
|
97
|
-
// default:
|
|
98
|
-
// throw new Error(`Unknown drizzle input type: ${inputType}`);
|
|
99
|
-
// }
|
|
100
|
-
// })
|
|
101
|
-
// : null;
|
|
102
|
-
|
|
103
|
-
// const argMappers: typeof fieldConfig.argMappers = argMapper
|
|
104
|
-
// ? [...(fieldConfig.argMappers ?? []), (args) => argMapper(args, undefined)]
|
|
105
|
-
// : fieldConfig.argMappers;
|
|
106
|
-
|
|
107
70
|
if (
|
|
108
71
|
fieldConfig.kind === 'DrizzleObject' &&
|
|
109
72
|
fieldConfig.pothosOptions.select &&
|
|
@@ -112,7 +75,6 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
112
75
|
const { select } = fieldConfig.pothosOptions;
|
|
113
76
|
return {
|
|
114
77
|
...fieldConfig,
|
|
115
|
-
// argMappers,
|
|
116
78
|
extensions: {
|
|
117
79
|
...fieldConfig.extensions,
|
|
118
80
|
pothosDrizzleSelect:
|
|
@@ -122,21 +84,18 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
122
84
|
ctx: Types['Context'],
|
|
123
85
|
nestedQuery: (query: unknown, path?: string[]) => never,
|
|
124
86
|
_resolveSelection: unknown,
|
|
125
|
-
pathInfo:
|
|
87
|
+
pathInfo: PathInfo,
|
|
126
88
|
) => {
|
|
127
|
-
//
|
|
128
|
-
const nestedQueryWithPath = Object.assign(nestedQuery,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
return {
|
|
133
|
-
columns: {},
|
|
134
|
-
...(select as (args: unknown, ctx: unknown, nestedQuery: unknown) => {})(
|
|
89
|
+
// A field's select also reads its metadata from the nested selection function.
|
|
90
|
+
const nestedQueryWithPath = Object.assign(nestedQuery, pathInfo);
|
|
91
|
+
return completeValue(
|
|
92
|
+
(select as (args: unknown, ctx: unknown, nestedQuery: unknown) => {} | null)(
|
|
135
93
|
args,
|
|
136
94
|
ctx,
|
|
137
95
|
nestedQueryWithPath,
|
|
138
96
|
),
|
|
139
|
-
|
|
97
|
+
wrapSelect,
|
|
98
|
+
);
|
|
140
99
|
}
|
|
141
100
|
: {
|
|
142
101
|
columns: {},
|
|
@@ -148,7 +107,6 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
148
107
|
|
|
149
108
|
return {
|
|
150
109
|
...fieldConfig,
|
|
151
|
-
// argMappers,
|
|
152
110
|
};
|
|
153
111
|
}
|
|
154
112
|
|
|
@@ -161,6 +119,12 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
161
119
|
}
|
|
162
120
|
|
|
163
121
|
const parentConfig = this.buildCache.getTypeConfig(fieldConfig.parentType);
|
|
122
|
+
// A field can declare how to tell whether its data is already on the parent row. When the
|
|
123
|
+
// row was not loaded from the planned query (a resolver returned a row it fetched itself),
|
|
124
|
+
// the mapping alone is not proof, and the field falls back to the model loader.
|
|
125
|
+
const loadedCheck = fieldConfig.extensions?.pothosDrizzleLoaded as
|
|
126
|
+
| ((value: unknown, info: GraphQLResolveInfo, context: object) => boolean)
|
|
127
|
+
| undefined;
|
|
164
128
|
|
|
165
129
|
const parentTypes = new Set([fieldConfig.parentType]);
|
|
166
130
|
|
|
@@ -182,19 +146,24 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
182
146
|
}
|
|
183
147
|
|
|
184
148
|
return (parent, args, context, info) => {
|
|
185
|
-
|
|
149
|
+
// Asked of the row: a mapping recorded for this row wins over the plan's, which answers
|
|
150
|
+
// for the rows the planned query loaded.
|
|
151
|
+
let mapping = getLoaderMapping(context, info.path, info.parentType.name, parent);
|
|
186
152
|
|
|
187
153
|
if (!mapping) {
|
|
188
154
|
for (const parentType of parentTypes) {
|
|
189
|
-
mapping = getLoaderMapping(context, info.path, parentType);
|
|
155
|
+
mapping = getLoaderMapping(context, info.path, parentType, parent);
|
|
190
156
|
if (mapping) {
|
|
191
157
|
break;
|
|
192
158
|
}
|
|
193
159
|
}
|
|
194
160
|
}
|
|
195
161
|
|
|
196
|
-
if (mapping) {
|
|
197
|
-
|
|
162
|
+
if ((!loadedCheck || loadedCheck(parent, info, context)) && mapping) {
|
|
163
|
+
// Recorded under the field's own parent type as well, so its resolver finds the pathInfo
|
|
164
|
+
// it was planned with, whichever same-model type the plan was made for. Against the row
|
|
165
|
+
// it resolves with: a sibling row of the same list may have been loaded by another plan.
|
|
166
|
+
setFieldMapping(context, info, mapping, parent);
|
|
198
167
|
|
|
199
168
|
return resolver(parent, args, context, info);
|
|
200
169
|
}
|
|
@@ -206,4 +175,9 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
|
|
|
206
175
|
}
|
|
207
176
|
}
|
|
208
177
|
|
|
178
|
+
/** A falsy selection means the field selects nothing from the parent row. */
|
|
179
|
+
function wrapSelect(selected: {} | null) {
|
|
180
|
+
return selected ? { columns: {}, ...selected } : null;
|
|
181
|
+
}
|
|
182
|
+
|
|
209
183
|
SchemaBuilder.registerPlugin(pluginName, PothosDrizzlePlugin, {});
|