@pothos/plugin-drizzle 0.18.1 → 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 +345 -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 +80 -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 +80 -20
- package/esm/types.d.ts.map +1 -1
- 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 -354
- 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.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 -359
- 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 +175 -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 -734
- 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/lib/utils/selections.js
CHANGED
|
@@ -2,171 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
_export(exports, {
|
|
12
|
-
get createState () {
|
|
13
|
-
return createState;
|
|
14
|
-
},
|
|
15
|
-
get mergeSelection () {
|
|
16
|
-
return mergeSelection;
|
|
17
|
-
},
|
|
18
|
-
get mergeState () {
|
|
19
|
-
return mergeState;
|
|
20
|
-
},
|
|
21
|
-
get omitUndefinedKeys () {
|
|
5
|
+
Object.defineProperty(exports, "omitUndefinedKeys", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
22
8
|
return omitUndefinedKeys;
|
|
23
|
-
},
|
|
24
|
-
get selectionCompatible () {
|
|
25
|
-
return selectionCompatible;
|
|
26
|
-
},
|
|
27
|
-
get selectionToQuery () {
|
|
28
|
-
return selectionToQuery;
|
|
29
|
-
},
|
|
30
|
-
get stateCompatible () {
|
|
31
|
-
return stateCompatible;
|
|
32
9
|
}
|
|
33
10
|
});
|
|
34
|
-
const _core = require("@pothos/core");
|
|
35
|
-
const _deepequal = require("./deep-equal.js");
|
|
36
11
|
function omitUndefinedKeys(query) {
|
|
37
12
|
const entries = Object.entries(query);
|
|
38
13
|
const defined = entries.filter(([, value])=>value !== undefined);
|
|
39
14
|
return defined.length === entries.length ? query : Object.fromEntries(defined);
|
|
40
15
|
}
|
|
41
|
-
function selectionCompatible(state, selectionMap, ignoreQuery = false) {
|
|
42
|
-
if (typeof selectionMap === 'boolean') {
|
|
43
|
-
return ignoreQuery || !selectionMap || Object.keys(state.query).length === 0;
|
|
44
|
-
}
|
|
45
|
-
const { with: withSelection, extras, columns: _, ...query } = selectionMap;
|
|
46
|
-
if (withSelection && Object.entries(withSelection).some(([key, value])=>value && state.with.has(key) && // TODO: make sure nested extras are normalized
|
|
47
|
-
!selectionCompatible(state.with.get(key), value))) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
if (extras && Object.entries(extras).some(([key, value])=>{
|
|
51
|
-
const existing = state.extras.get(key);
|
|
52
|
-
return existing && existing !== value;
|
|
53
|
-
})) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
return ignoreQuery || (0, _deepequal.deepEqual)(state.query, omitUndefinedKeys(query));
|
|
57
|
-
}
|
|
58
|
-
function stateCompatible(state, newState, ignoreQuery = false) {
|
|
59
|
-
for (const [name, relationState] of newState.with){
|
|
60
|
-
if (state.with.has(name) && !stateCompatible(state.with.get(name), relationState)) {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return ignoreQuery || (0, _deepequal.deepEqual)(state.query, newState.query);
|
|
65
|
-
}
|
|
66
|
-
function mergeState(state, newState) {
|
|
67
|
-
for (const [name, relationState] of newState.with){
|
|
68
|
-
if (state.with.has(name)) {
|
|
69
|
-
mergeState(state.with.get(name), relationState);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (!state.allColumns) {
|
|
73
|
-
if (newState.allColumns) {
|
|
74
|
-
state.allColumns = true;
|
|
75
|
-
} else {
|
|
76
|
-
for (const name of newState.columns){
|
|
77
|
-
state.columns.add(name);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
for (const [name, value] of newState.extras){
|
|
82
|
-
state.extras.set(name, value);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
function createState(table, skipDeferredFragments, parent) {
|
|
86
|
-
return {
|
|
87
|
-
table,
|
|
88
|
-
skipDeferredFragments,
|
|
89
|
-
parent,
|
|
90
|
-
query: {},
|
|
91
|
-
columns: new Set(),
|
|
92
|
-
with: new Map(),
|
|
93
|
-
extras: new Map(),
|
|
94
|
-
mappings: {},
|
|
95
|
-
allColumns: false,
|
|
96
|
-
depth: parent ? parent.depth + 1 : 0
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
function mergeSelection(config, state, selection) {
|
|
100
|
-
const { with: withSelection, extras, columns, ...query } = typeof selection === 'boolean' ? selection === true ? {} : {
|
|
101
|
-
columns: {}
|
|
102
|
-
} : selection;
|
|
103
|
-
if (withSelection) {
|
|
104
|
-
for (const [key, value] of Object.entries(withSelection)){
|
|
105
|
-
const relation = state.table.relations[key];
|
|
106
|
-
if (!relation) {
|
|
107
|
-
throw new _core.PothosValidationError(`Relation ${key} does not exist on ${state.table.name}`);
|
|
108
|
-
}
|
|
109
|
-
merge(config.relations[relation.targetTableName], key, value);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
const normalizedQuery = omitUndefinedKeys(query);
|
|
113
|
-
if (Object.keys(normalizedQuery).length > 0) {
|
|
114
|
-
state.query = normalizedQuery;
|
|
115
|
-
}
|
|
116
|
-
if (extras) {
|
|
117
|
-
for (const [key, value] of Object.entries(extras)){
|
|
118
|
-
state.extras.set(key, value);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (state.allColumns) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (columns && !state.allColumns) {
|
|
125
|
-
for (const [key, value] of Object.entries(columns)){
|
|
126
|
-
if (value) {
|
|
127
|
-
state.columns.add(key);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
state.allColumns = true;
|
|
132
|
-
}
|
|
133
|
-
function merge(table, key, value) {
|
|
134
|
-
if (!value) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
if (state.with.has(key)) {
|
|
138
|
-
mergeSelection(config, state.with.get(key), value);
|
|
139
|
-
} else {
|
|
140
|
-
const relatedState = createState(table, state.skipDeferredFragments, state);
|
|
141
|
-
mergeSelection(config, relatedState, value);
|
|
142
|
-
state.with.set(key, relatedState);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
function selectionToQuery(config, state) {
|
|
147
|
-
const query = {
|
|
148
|
-
...omitUndefinedKeys(state.query),
|
|
149
|
-
columns: undefined,
|
|
150
|
-
with: {},
|
|
151
|
-
extras: {}
|
|
152
|
-
};
|
|
153
|
-
if (!state.allColumns) {
|
|
154
|
-
query.columns = {};
|
|
155
|
-
for (const key of state.columns){
|
|
156
|
-
query.columns[key] = true;
|
|
157
|
-
}
|
|
158
|
-
for (const column of config.getPrimaryKey(state.table.name)){
|
|
159
|
-
const tsName = config.columnToTsName(column);
|
|
160
|
-
query.columns[tsName] = true;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
for (const [key, value] of state.extras){
|
|
164
|
-
query.extras[key] = value;
|
|
165
|
-
}
|
|
166
|
-
state.with.forEach((sel, relation)=>{
|
|
167
|
-
query.with[relation] = selectionToQuery(config, sel);
|
|
168
|
-
});
|
|
169
|
-
return query;
|
|
170
|
-
}
|
|
171
16
|
|
|
172
17
|
//# sourceMappingURL=selections.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/selections.ts"],"names":["
|
|
1
|
+
{"version":3,"sources":["../../src/utils/selections.ts"],"names":["omitUndefinedKeys","query","entries","Object","defined","filter","value","undefined","length","fromEntries"],"mappings":";;;;+BAKgBA;;;eAAAA;;;AAAT,SAASA,kBAAoCC,KAAQ;IAC1D,MAAMC,UAAUC,OAAOD,OAAO,CAACD;IAC/B,MAAMG,UAAUF,QAAQG,MAAM,CAAC,CAAC,GAAGC,MAAM,GAAKA,UAAUC;IAExD,OAAOH,QAAQI,MAAM,KAAKN,QAAQM,MAAM,GAAGP,QAASE,OAAOM,WAAW,CAACL;AACzE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pothos/plugin-drizzle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "A Pothos plugin for drizzle",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./dts/index.d.ts",
|
|
@@ -33,23 +33,25 @@
|
|
|
33
33
|
"access": "public",
|
|
34
34
|
"provenance": true
|
|
35
35
|
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@pothos/selection-mapper": "0.1.0"
|
|
38
|
+
},
|
|
36
39
|
"peerDependencies": {
|
|
37
40
|
"@pothos/core": "*",
|
|
38
|
-
"drizzle-orm": ">=1.0.0-
|
|
41
|
+
"drizzle-orm": ">=1.0.0-rc.2",
|
|
39
42
|
"graphql": "^16.10.0 || ^17.0.0"
|
|
40
43
|
},
|
|
41
44
|
"devDependencies": {
|
|
42
45
|
"@libsql/client": "^0.17.2",
|
|
43
|
-
"drizzle-graphql": "^0.8.5",
|
|
44
46
|
"drizzle-kit": "1.0.0-rc.2",
|
|
45
47
|
"drizzle-orm": "1.0.0-rc.2",
|
|
46
48
|
"graphql-scalars": "^1.25.0",
|
|
47
49
|
"graphql-tag": "^2.12.6",
|
|
48
50
|
"postgres": "^3.4.9",
|
|
49
|
-
"@pothos/core": "4.
|
|
50
|
-
"@pothos/plugin-errors": "4.9.1",
|
|
51
|
-
"@pothos/plugin-relay": "4.7.1",
|
|
51
|
+
"@pothos/core": "4.14.0",
|
|
52
52
|
"@pothos/plugin-add-graphql": "4.3.1",
|
|
53
|
+
"@pothos/plugin-errors": "4.9.1",
|
|
54
|
+
"@pothos/plugin-relay": "4.7.2",
|
|
53
55
|
"@pothos/plugin-scope-auth": "4.1.7",
|
|
54
56
|
"@pothos/plugin-with-input": "4.1.5",
|
|
55
57
|
"@pothos/test-utils": "2.2.1"
|
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
completeValue,
|
|
3
|
+
type InputFieldMap,
|
|
4
|
+
type InputShapeFromFields,
|
|
5
|
+
isThenable,
|
|
6
|
+
type MaybeAsyncSelection,
|
|
7
|
+
type MaybePromise,
|
|
8
|
+
type SchemaTypes,
|
|
9
|
+
} from '@pothos/core';
|
|
10
|
+
import type { PathSegment } from '@pothos/selection-mapper';
|
|
2
11
|
import type {
|
|
3
12
|
BuildQueryResult,
|
|
4
13
|
DBQueryConfig,
|
|
5
14
|
RelationsFilter,
|
|
15
|
+
SQL,
|
|
6
16
|
TableRelationalConfig,
|
|
7
17
|
} from 'drizzle-orm';
|
|
8
18
|
import type { GraphQLResolveInfo } from 'graphql';
|
|
9
19
|
import type { DrizzleRef } from './interface-ref.js';
|
|
10
20
|
import type { QueryForDrizzleConnection } from './types.js';
|
|
21
|
+
import { drizzleAdapter } from './utils/adapter.js';
|
|
22
|
+
import { checkAwaitSelections } from './utils/await-selections.js';
|
|
11
23
|
import { getSchemaConfig } from './utils/config.js';
|
|
12
24
|
import {
|
|
13
25
|
type DrizzleCursorConnectionQueryOptions,
|
|
@@ -17,12 +29,7 @@ import {
|
|
|
17
29
|
} from './utils/cursors.js';
|
|
18
30
|
import { queryFromInfo } from './utils/map-query.js';
|
|
19
31
|
import { getRefFromModel } from './utils/refs.js';
|
|
20
|
-
import {
|
|
21
|
-
createState,
|
|
22
|
-
mergeSelection,
|
|
23
|
-
omitUndefinedKeys,
|
|
24
|
-
selectionToQuery,
|
|
25
|
-
} from './utils/selections.js';
|
|
32
|
+
import { omitUndefinedKeys, type SelectionMap } from './utils/selections.js';
|
|
26
33
|
|
|
27
34
|
export function drizzleConnectionHelpers<
|
|
28
35
|
Types extends SchemaTypes,
|
|
@@ -60,14 +67,18 @@ export function drizzleConnectionHelpers<
|
|
|
60
67
|
}: {
|
|
61
68
|
args?: (t: PothosSchemaTypes.InputFieldBuilder<Types, 'Arg'>) => ExtraArgs;
|
|
62
69
|
select?: (
|
|
70
|
+
// The node's selection: its table is the connection field's, which the helper does not know.
|
|
63
71
|
nestedSelection: <T extends true | {}>(selection?: T) => T,
|
|
64
72
|
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
65
73
|
ctx: Types['Context'],
|
|
66
|
-
) => Selection
|
|
74
|
+
) => MaybeAsyncSelection<Types, Selection>;
|
|
67
75
|
query?: QueryForDrizzleConnection<Types, TableConfig> extends infer QueryConfig
|
|
68
76
|
?
|
|
69
77
|
| QueryConfig
|
|
70
|
-
| ((
|
|
78
|
+
| ((
|
|
79
|
+
args: InputShapeFromFields<ExtraArgs>,
|
|
80
|
+
context: Types['Context'],
|
|
81
|
+
) => MaybeAsyncSelection<Types, QueryConfig>)
|
|
71
82
|
: never;
|
|
72
83
|
defaultSize?:
|
|
73
84
|
| number
|
|
@@ -79,23 +90,47 @@ export function drizzleConnectionHelpers<
|
|
|
79
90
|
| number
|
|
80
91
|
| ((args: PothosSchemaTypes.DefaultConnectionArguments, ctx: Types['Context']) => number);
|
|
81
92
|
resolveNode?: (edge: EdgeShape) => NodeShape;
|
|
82
|
-
},
|
|
93
|
+
} = {},
|
|
83
94
|
) {
|
|
84
95
|
const config = getSchemaConfig(builder);
|
|
96
|
+
const adapter = drizzleAdapter(config);
|
|
85
97
|
const tableName =
|
|
86
98
|
typeof refOrType === 'string'
|
|
87
99
|
? refOrType
|
|
88
100
|
: (refOrType as DrizzleRef<Types, Type extends DrizzleRef<Types, infer T> ? T : Type>)
|
|
89
101
|
.tableName;
|
|
90
102
|
|
|
91
|
-
|
|
103
|
+
interface BaseQuery {
|
|
104
|
+
limit?: number;
|
|
105
|
+
orderBy?: unknown;
|
|
106
|
+
where?: SQL;
|
|
107
|
+
columns?: Record<string, boolean>;
|
|
108
|
+
extras?: DrizzleCursorConnectionQueryOptions['extras'];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** The user's `query`, a promise when its callback is async, which the caller awaits. */
|
|
112
|
+
const baseQueryFor = (
|
|
113
|
+
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
114
|
+
ctx: Types['Context'],
|
|
115
|
+
): MaybePromise<BaseQuery> =>
|
|
116
|
+
completeValue(
|
|
117
|
+
(typeof query === 'function' ? query(args, ctx) : query) as MaybePromise<
|
|
118
|
+
BaseQuery | null | undefined
|
|
119
|
+
>,
|
|
120
|
+
orEmpty,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Built once per helper, so a synchronous `resolve` allocates nothing beyond the connection.
|
|
124
|
+
const resolveList = (
|
|
125
|
+
baseQuery: BaseQuery,
|
|
92
126
|
list: (EdgeShape & {})[],
|
|
93
127
|
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
94
128
|
ctx: Types['Context'],
|
|
95
|
-
parent
|
|
96
|
-
) {
|
|
97
|
-
const { select, cursorFields } = getQueryArgs(args, ctx);
|
|
129
|
+
parent: unknown,
|
|
130
|
+
) => {
|
|
131
|
+
const { select, cursorFields } = getQueryArgs(args, ctx, baseQuery);
|
|
98
132
|
const formatCursor = getCursorFormatter(cursorFields, config);
|
|
133
|
+
|
|
99
134
|
return wrapConnectionResult(
|
|
100
135
|
list,
|
|
101
136
|
args,
|
|
@@ -103,24 +138,42 @@ export function drizzleConnectionHelpers<
|
|
|
103
138
|
formatCursor,
|
|
104
139
|
(resolveNode as never) ?? ((edge: unknown) => edge),
|
|
105
140
|
parent,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
function resolve<Parent = undefined>(
|
|
145
|
+
list: (EdgeShape & {})[],
|
|
146
|
+
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
147
|
+
ctx: Types['Context'],
|
|
148
|
+
parent?: Parent,
|
|
149
|
+
) {
|
|
150
|
+
const baseQuery = baseQueryFor(args, ctx);
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
isThenable(baseQuery)
|
|
154
|
+
? baseQuery.then((resolved) => resolveList(resolved, list, args, ctx, parent))
|
|
155
|
+
: resolveList(baseQuery, list, args, ctx, parent)
|
|
156
|
+
) as MaybeAsyncSelection<
|
|
157
|
+
Types,
|
|
158
|
+
{
|
|
159
|
+
parent: Parent;
|
|
160
|
+
edges: (Omit<EdgeShape, 'cursor' | 'node'> & { node: NodeShape; cursor: string })[];
|
|
161
|
+
pageInfo: {
|
|
162
|
+
startCursor: string | null;
|
|
163
|
+
endCursor: string | null;
|
|
164
|
+
hasPreviousPage: boolean;
|
|
165
|
+
hasNextPage: boolean;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
>;
|
|
116
169
|
}
|
|
117
170
|
|
|
118
171
|
const getQueryArgs = (
|
|
119
172
|
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
120
173
|
ctx: {},
|
|
174
|
+
baseQuery: BaseQuery,
|
|
121
175
|
) => {
|
|
122
|
-
const { limit, orderBy, where, ...fieldQuery } =
|
|
123
|
-
(typeof query === 'function' ? query(args, ctx) : query) ?? {};
|
|
176
|
+
const { limit, orderBy, where, ...fieldQuery } = baseQuery;
|
|
124
177
|
const table = config.relations[tableName];
|
|
125
178
|
|
|
126
179
|
const { cursorFields, columns, ...connectionQuery } = drizzleCursorConnectionQuery({
|
|
@@ -151,13 +204,45 @@ export function drizzleConnectionHelpers<
|
|
|
151
204
|
};
|
|
152
205
|
};
|
|
153
206
|
|
|
154
|
-
|
|
207
|
+
// The `nestedSelection` of the field's `select`, whatever table its type names.
|
|
208
|
+
type NestedSelection = (selection?: SelectionMap | true, path?: PathSegment[]) => unknown;
|
|
209
|
+
|
|
210
|
+
/** The drizzle query `getQuery` builds: the node selection, with the connection's own arguments. */
|
|
211
|
+
type ConnectionQuery = Omit<Selection, 'orderBy'> & {
|
|
212
|
+
orderBy: {
|
|
213
|
+
[K in TableConfig['table']['_'] extends { columns: infer Columns } ? keyof Columns : never]?:
|
|
214
|
+
| 'asc'
|
|
215
|
+
| 'desc'
|
|
216
|
+
| undefined;
|
|
217
|
+
};
|
|
218
|
+
where: RelationsFilter<TableConfig, Types['DrizzleRelations']>;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* What `getQuery` returns for a given `awaitSelections`. `[Await] extends [false]` rather than
|
|
223
|
+
* `Await extends true`, so a caller passing a `boolean` variable — which infers `Await` as
|
|
224
|
+
* `boolean`, neither literal — is handed the promise to deal with, rather than a synchronous
|
|
225
|
+
* type it cannot rely on.
|
|
226
|
+
*/
|
|
227
|
+
type ConnectionQueryReturn<Await extends boolean> = [Await] extends [false]
|
|
228
|
+
? ConnectionQuery
|
|
229
|
+
: MaybePromise<ConnectionQuery>;
|
|
155
230
|
|
|
156
|
-
|
|
231
|
+
/**
|
|
232
|
+
* The connection's query, built from the helper's own `select` and `query` and the selection
|
|
233
|
+
* beneath the field. Synchronous unless `awaitSelections` says otherwise: an async `select` or
|
|
234
|
+
* `query`, or an async selection beneath the connection, throws rather than returning a promise
|
|
235
|
+
* the declared type denies.
|
|
236
|
+
*/
|
|
237
|
+
function getQuery<Await extends boolean = false>(
|
|
157
238
|
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
158
239
|
ctx: Types['Context'],
|
|
159
240
|
nestedSelectionOrInfo: NestedSelection | GraphQLResolveInfo,
|
|
160
|
-
|
|
241
|
+
options?: {
|
|
242
|
+
/** Whether the caller will await the query. */
|
|
243
|
+
awaitSelections?: Await;
|
|
244
|
+
},
|
|
245
|
+
): ConnectionQueryReturn<Await> {
|
|
161
246
|
const nestedSelection: NestedSelection =
|
|
162
247
|
typeof nestedSelectionOrInfo === 'function'
|
|
163
248
|
? nestedSelectionOrInfo
|
|
@@ -166,43 +251,72 @@ export function drizzleConnectionHelpers<
|
|
|
166
251
|
info: nestedSelectionOrInfo,
|
|
167
252
|
context: ctx,
|
|
168
253
|
config,
|
|
169
|
-
select,
|
|
254
|
+
select: select as SelectionMap,
|
|
170
255
|
path,
|
|
171
256
|
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const selectState = createState(
|
|
178
|
-
config.relations[tableName],
|
|
179
|
-
builder.options.drizzle?.skipDeferredFragments ?? true,
|
|
180
|
-
);
|
|
257
|
+
// Both callbacks start now; the query waits for whichever of them is async.
|
|
258
|
+
const nestedSelect: MaybePromise<Record<string, unknown> | true> = select
|
|
259
|
+
? select((sel) => nestedSelection(sel as SelectionMap, ['edges', 'node']) as never, args, ctx)
|
|
260
|
+
: (nestedSelection(true, ['edges', 'node']) as never);
|
|
261
|
+
let baseQuery: MaybePromise<object>;
|
|
181
262
|
|
|
182
|
-
|
|
263
|
+
try {
|
|
264
|
+
baseQuery = baseQueryFor(args, ctx);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
// The selection has already started. Preserve the query error while handling any
|
|
267
|
+
// later rejection from the selection that this invocation can no longer consume.
|
|
268
|
+
if (isThenable(nestedSelect)) {
|
|
269
|
+
nestedSelect.then(
|
|
270
|
+
() => {},
|
|
271
|
+
() => {},
|
|
272
|
+
);
|
|
273
|
+
}
|
|
183
274
|
|
|
184
|
-
|
|
185
|
-
mergeSelection(config, selectState, nestedSelect);
|
|
275
|
+
throw error;
|
|
186
276
|
}
|
|
187
277
|
|
|
188
|
-
const
|
|
189
|
-
|
|
278
|
+
const built: MaybePromise<object> =
|
|
279
|
+
isThenable(nestedSelect) || isThenable(baseQuery)
|
|
280
|
+
? Promise.all([nestedSelect, baseQuery]).then(([nested, base]) =>
|
|
281
|
+
buildQuery(nested, base, args, ctx),
|
|
282
|
+
)
|
|
283
|
+
: buildQuery(nestedSelect, baseQuery, args, ctx);
|
|
284
|
+
|
|
285
|
+
return checkAwaitSelections(
|
|
286
|
+
built,
|
|
287
|
+
options?.awaitSelections,
|
|
288
|
+
'getQuery',
|
|
289
|
+
`the ${String(tableName)} connection`,
|
|
290
|
+
) as ConnectionQueryReturn<Await>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Built once per helper, so a synchronous `getQuery` allocates nothing beyond the query.
|
|
294
|
+
function buildQuery(
|
|
295
|
+
nestedSelect: Record<string, unknown> | true,
|
|
296
|
+
baseQuery: BaseQuery,
|
|
297
|
+
args: InputShapeFromFields<ExtraArgs> & PothosSchemaTypes.DefaultConnectionArguments,
|
|
298
|
+
ctx: Types['Context'],
|
|
299
|
+
) {
|
|
300
|
+
const node = adapter.createNode(config.relations[tableName]);
|
|
301
|
+
|
|
302
|
+
adapter.mergeQuery(node, getQueryArgs(args, ctx, baseQuery).select as SelectionMap);
|
|
303
|
+
|
|
304
|
+
if (typeof nestedSelect === 'object' && nestedSelect) {
|
|
305
|
+
adapter.mergeQuery(node, nestedSelect);
|
|
306
|
+
}
|
|
190
307
|
|
|
191
308
|
return omitUndefinedKeys({
|
|
192
309
|
...baseQuery,
|
|
193
|
-
...
|
|
194
|
-
})
|
|
195
|
-
orderBy: {
|
|
196
|
-
[K in TableConfig['table']['_'] extends { columns: infer Columns }
|
|
197
|
-
? keyof Columns
|
|
198
|
-
: never]?: 'asc' | 'desc' | undefined;
|
|
199
|
-
};
|
|
200
|
-
where: RelationsFilter<TableConfig, Types['DrizzleRelations']>;
|
|
201
|
-
};
|
|
310
|
+
...adapter.toQuery(node),
|
|
311
|
+
});
|
|
202
312
|
}
|
|
203
313
|
|
|
204
314
|
const getArgs = () => (createArgs ? builder.args(createArgs) : {}) as ExtraArgs;
|
|
205
315
|
|
|
316
|
+
function orEmpty(baseQuery: BaseQuery | null | undefined): BaseQuery {
|
|
317
|
+
return baseQuery ?? ({} as BaseQuery);
|
|
318
|
+
}
|
|
319
|
+
|
|
206
320
|
return {
|
|
207
321
|
ref: (typeof refOrType === 'string'
|
|
208
322
|
? getRefFromModel(refOrType, builder)
|