drizzle-graphql-plus 0.8.6 → 0.8.8
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/package.json +3 -3
- package/src/types.ts +478 -360
- package/src/util/builders/common.ts +2 -0
- package/src/util/builders/mysql.ts +534 -449
- package/src/util/builders/pg.ts +583 -484
- package/src/util/builders/sqlite.ts +589 -491
- package/src/util/builders/types.ts +261 -175
|
@@ -1,524 +1,622 @@
|
|
|
1
|
-
import { createTableRelationsHelpers, is, Relation, Relations, Table } from 'drizzle-orm';
|
|
2
|
-
import { BaseSQLiteDatabase, SQLiteColumn, SQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
3
1
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
createTableRelationsHelpers,
|
|
3
|
+
is,
|
|
4
|
+
Relation,
|
|
5
|
+
Relations,
|
|
6
|
+
Table,
|
|
7
|
+
} from "drizzle-orm";
|
|
8
|
+
import {
|
|
9
|
+
BaseSQLiteDatabase,
|
|
10
|
+
SQLiteColumn,
|
|
11
|
+
SQLiteTable,
|
|
12
|
+
} from "drizzle-orm/sqlite-core";
|
|
13
|
+
import {
|
|
14
|
+
GraphQLError,
|
|
15
|
+
GraphQLInputObjectType,
|
|
16
|
+
GraphQLInt,
|
|
17
|
+
GraphQLInterfaceType,
|
|
18
|
+
GraphQLList,
|
|
19
|
+
GraphQLNonNull,
|
|
20
|
+
GraphQLObjectType,
|
|
21
|
+
} from "graphql";
|
|
11
22
|
|
|
12
23
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from
|
|
20
|
-
import { capitalize, uncapitalize } from
|
|
24
|
+
extractFilters,
|
|
25
|
+
extractOrderBy,
|
|
26
|
+
extractRelationsParams,
|
|
27
|
+
extractSelectedColumnsFromTree,
|
|
28
|
+
extractSelectedColumnsFromTreeSQLFormat,
|
|
29
|
+
generateTableTypes,
|
|
30
|
+
} from "@/util/builders/common";
|
|
31
|
+
import { capitalize, uncapitalize } from "@/util/case-ops";
|
|
21
32
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from
|
|
27
|
-
import { parseResolveInfo } from
|
|
28
|
-
|
|
29
|
-
import type { GeneratedEntities } from
|
|
30
|
-
import type { RelationalQueryBuilder } from
|
|
31
|
-
import type {
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
remapFromGraphQLArrayInput,
|
|
34
|
+
remapFromGraphQLSingleInput,
|
|
35
|
+
remapToGraphQLArrayOutput,
|
|
36
|
+
remapToGraphQLSingleOutput,
|
|
37
|
+
} from "@/util/data-mappers";
|
|
38
|
+
import { parseResolveInfo } from "graphql-parse-resolve-info";
|
|
39
|
+
|
|
40
|
+
import type { GeneratedEntities } from "@/types";
|
|
41
|
+
import type { RelationalQueryBuilder } from "drizzle-orm/mysql-core/query-builders/query";
|
|
42
|
+
import type {
|
|
43
|
+
GraphQLFieldConfig,
|
|
44
|
+
GraphQLFieldConfigArgumentMap,
|
|
45
|
+
ThunkObjMap,
|
|
46
|
+
} from "graphql";
|
|
47
|
+
import type { ResolveTree } from "graphql-parse-resolve-info";
|
|
48
|
+
import type {
|
|
49
|
+
CreatedResolver,
|
|
50
|
+
Filters,
|
|
51
|
+
TableNamedRelations,
|
|
52
|
+
TableSelectArgs,
|
|
53
|
+
} from "./types";
|
|
34
54
|
|
|
35
55
|
const generateSelectArray = (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
db: BaseSQLiteDatabase<any, any, any, any>,
|
|
57
|
+
tableName: string,
|
|
58
|
+
tables: Record<string, Table>,
|
|
59
|
+
relationMap: Record<string, Record<string, TableNamedRelations>>,
|
|
60
|
+
orderArgs: GraphQLInputObjectType,
|
|
61
|
+
filterArgs: GraphQLInputObjectType
|
|
42
62
|
): CreatedResolver => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
63
|
+
const queryName = `${uncapitalize(tableName)}`;
|
|
64
|
+
const queryBase = db.query[tableName as keyof typeof db.query] as unknown as
|
|
65
|
+
| RelationalQueryBuilder<any, any, any>
|
|
66
|
+
| undefined;
|
|
67
|
+
if (!queryBase) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Drizzle-GraphQL Error: Table ${tableName} not found in drizzle instance. Did you forget to pass schema to drizzle constructor?`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const queryArgs = {
|
|
74
|
+
offset: {
|
|
75
|
+
type: GraphQLInt,
|
|
76
|
+
},
|
|
77
|
+
limit: {
|
|
78
|
+
type: GraphQLInt,
|
|
79
|
+
},
|
|
80
|
+
orderBy: {
|
|
81
|
+
type: orderArgs,
|
|
82
|
+
},
|
|
83
|
+
where: {
|
|
84
|
+
type: filterArgs,
|
|
85
|
+
},
|
|
86
|
+
} as GraphQLFieldConfigArgumentMap;
|
|
87
|
+
|
|
88
|
+
const typeName = `${capitalize(tableName)}SelectItem`;
|
|
89
|
+
const table = tables[tableName]!;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
name: queryName,
|
|
93
|
+
resolver: async (source, args: Partial<TableSelectArgs>, context, info) => {
|
|
94
|
+
try {
|
|
95
|
+
const { offset, limit, orderBy, where } = args;
|
|
96
|
+
|
|
97
|
+
const parsedInfo = parseResolveInfo(info, {
|
|
98
|
+
deep: true,
|
|
99
|
+
}) as ResolveTree;
|
|
100
|
+
|
|
101
|
+
const query = queryBase.findMany({
|
|
102
|
+
columns: extractSelectedColumnsFromTree(
|
|
103
|
+
parsedInfo.fieldsByTypeName[typeName]!,
|
|
104
|
+
table
|
|
105
|
+
),
|
|
106
|
+
offset,
|
|
107
|
+
limit,
|
|
108
|
+
orderBy: orderBy ? extractOrderBy(table, orderBy) : undefined,
|
|
109
|
+
where: where ? extractFilters(table, tableName, where) : undefined,
|
|
110
|
+
with: relationMap[tableName]
|
|
111
|
+
? extractRelationsParams(
|
|
112
|
+
relationMap,
|
|
113
|
+
tables,
|
|
114
|
+
tableName,
|
|
115
|
+
parsedInfo,
|
|
116
|
+
typeName
|
|
117
|
+
)
|
|
118
|
+
: undefined,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const result = await query;
|
|
122
|
+
|
|
123
|
+
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
|
|
124
|
+
} catch (e) {
|
|
125
|
+
if (typeof e === "object" && typeof (<any>e).message === "string") {
|
|
126
|
+
throw new GraphQLError((<any>e).message);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
throw e;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
args: queryArgs,
|
|
133
|
+
};
|
|
108
134
|
};
|
|
109
135
|
|
|
110
136
|
const generateSelectSingle = (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
137
|
+
db: BaseSQLiteDatabase<any, any, any, any>,
|
|
138
|
+
tableName: string,
|
|
139
|
+
tables: Record<string, Table>,
|
|
140
|
+
relationMap: Record<string, Record<string, TableNamedRelations>>,
|
|
141
|
+
orderArgs: GraphQLInputObjectType,
|
|
142
|
+
filterArgs: GraphQLInputObjectType
|
|
117
143
|
): CreatedResolver => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
144
|
+
const queryName = `${uncapitalize(tableName)}Single`;
|
|
145
|
+
const queryBase = db.query[tableName as keyof typeof db.query] as unknown as
|
|
146
|
+
| RelationalQueryBuilder<any, any, any>
|
|
147
|
+
| undefined;
|
|
148
|
+
if (!queryBase) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Drizzle-GraphQL Error: Table ${tableName} not found in drizzle instance. Did you forget to pass schema to drizzle constructor?`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const queryArgs = {
|
|
155
|
+
offset: {
|
|
156
|
+
type: GraphQLInt,
|
|
157
|
+
},
|
|
158
|
+
orderBy: {
|
|
159
|
+
type: orderArgs,
|
|
160
|
+
},
|
|
161
|
+
where: {
|
|
162
|
+
type: filterArgs,
|
|
163
|
+
},
|
|
164
|
+
} as GraphQLFieldConfigArgumentMap;
|
|
165
|
+
|
|
166
|
+
const typeName = `${capitalize(tableName)}SelectItem`;
|
|
167
|
+
const table = tables[tableName]!;
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
name: queryName,
|
|
171
|
+
resolver: async (source, args: Partial<TableSelectArgs>, context, info) => {
|
|
172
|
+
try {
|
|
173
|
+
const { offset, orderBy, where } = args;
|
|
174
|
+
|
|
175
|
+
const parsedInfo = parseResolveInfo(info, {
|
|
176
|
+
deep: true,
|
|
177
|
+
}) as ResolveTree;
|
|
178
|
+
|
|
179
|
+
const query = queryBase.findFirst({
|
|
180
|
+
columns: extractSelectedColumnsFromTree(
|
|
181
|
+
parsedInfo.fieldsByTypeName[typeName]!,
|
|
182
|
+
table
|
|
183
|
+
),
|
|
184
|
+
offset,
|
|
185
|
+
orderBy: orderBy ? extractOrderBy(table, orderBy) : undefined,
|
|
186
|
+
where: where ? extractFilters(table, tableName, where) : undefined,
|
|
187
|
+
with: relationMap[tableName]
|
|
188
|
+
? extractRelationsParams(
|
|
189
|
+
relationMap,
|
|
190
|
+
tables,
|
|
191
|
+
tableName,
|
|
192
|
+
parsedInfo,
|
|
193
|
+
typeName
|
|
194
|
+
)
|
|
195
|
+
: undefined,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const result = await query;
|
|
199
|
+
if (!result) return undefined;
|
|
200
|
+
|
|
201
|
+
return remapToGraphQLSingleOutput(
|
|
202
|
+
result,
|
|
203
|
+
tableName,
|
|
204
|
+
table,
|
|
205
|
+
relationMap
|
|
206
|
+
);
|
|
207
|
+
} catch (e) {
|
|
208
|
+
if (typeof e === "object" && typeof (<any>e).message === "string") {
|
|
209
|
+
throw new GraphQLError((<any>e).message);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
throw e;
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
args: queryArgs,
|
|
216
|
+
};
|
|
180
217
|
};
|
|
181
218
|
|
|
182
219
|
const generateInsertArray = (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
220
|
+
db: BaseSQLiteDatabase<any, any, any, any>,
|
|
221
|
+
tableName: string,
|
|
222
|
+
table: SQLiteTable,
|
|
223
|
+
baseType: GraphQLInputObjectType
|
|
187
224
|
): CreatedResolver => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
225
|
+
const queryName = `insertInto${capitalize(tableName)}`;
|
|
226
|
+
const typeName = `${capitalize(tableName)}Item`;
|
|
227
|
+
|
|
228
|
+
const queryArgs: GraphQLFieldConfigArgumentMap = {
|
|
229
|
+
values: {
|
|
230
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(baseType))),
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
name: queryName,
|
|
236
|
+
resolver: async (
|
|
237
|
+
source,
|
|
238
|
+
args: { values: Record<string, any>[] },
|
|
239
|
+
context,
|
|
240
|
+
info
|
|
241
|
+
) => {
|
|
242
|
+
try {
|
|
243
|
+
const input = remapFromGraphQLArrayInput(args.values, table);
|
|
244
|
+
if (!input.length) throw new GraphQLError("No values were provided!");
|
|
245
|
+
|
|
246
|
+
const parsedInfo = parseResolveInfo(info, {
|
|
247
|
+
deep: true,
|
|
248
|
+
}) as ResolveTree;
|
|
249
|
+
|
|
250
|
+
const columns = extractSelectedColumnsFromTreeSQLFormat<SQLiteColumn>(
|
|
251
|
+
parsedInfo.fieldsByTypeName[typeName]!,
|
|
252
|
+
table
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const result = await db
|
|
256
|
+
.insert(table)
|
|
257
|
+
.values(input)
|
|
258
|
+
.returning(columns)
|
|
259
|
+
.onConflictDoNothing();
|
|
260
|
+
|
|
261
|
+
return remapToGraphQLArrayOutput(result, tableName, table);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
if (typeof e === "object" && typeof (<any>e).message === "string") {
|
|
264
|
+
throw new GraphQLError((<any>e).message);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
throw e;
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
args: queryArgs,
|
|
271
|
+
};
|
|
230
272
|
};
|
|
231
273
|
|
|
232
274
|
const generateInsertSingle = (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
275
|
+
db: BaseSQLiteDatabase<any, any, any, any>,
|
|
276
|
+
tableName: string,
|
|
277
|
+
table: SQLiteTable,
|
|
278
|
+
baseType: GraphQLInputObjectType
|
|
237
279
|
): CreatedResolver => {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
280
|
+
const queryName = `insertInto${capitalize(tableName)}Single`;
|
|
281
|
+
const typeName = `${capitalize(tableName)}Item`;
|
|
282
|
+
|
|
283
|
+
const queryArgs: GraphQLFieldConfigArgumentMap = {
|
|
284
|
+
values: {
|
|
285
|
+
type: new GraphQLNonNull(baseType),
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
name: queryName,
|
|
291
|
+
resolver: async (
|
|
292
|
+
source,
|
|
293
|
+
args: { values: Record<string, any> },
|
|
294
|
+
context,
|
|
295
|
+
info
|
|
296
|
+
) => {
|
|
297
|
+
try {
|
|
298
|
+
const input = remapFromGraphQLSingleInput(args.values, table);
|
|
299
|
+
|
|
300
|
+
const parsedInfo = parseResolveInfo(info, {
|
|
301
|
+
deep: true,
|
|
302
|
+
}) as ResolveTree;
|
|
303
|
+
|
|
304
|
+
const columns = extractSelectedColumnsFromTreeSQLFormat<SQLiteColumn>(
|
|
305
|
+
parsedInfo.fieldsByTypeName[typeName]!,
|
|
306
|
+
table
|
|
307
|
+
);
|
|
308
|
+
const result = await db
|
|
309
|
+
.insert(table)
|
|
310
|
+
.values(input)
|
|
311
|
+
.returning(columns)
|
|
312
|
+
.onConflictDoNothing();
|
|
313
|
+
|
|
314
|
+
if (!result[0]) return undefined;
|
|
315
|
+
|
|
316
|
+
return remapToGraphQLSingleOutput(result[0], tableName, table);
|
|
317
|
+
} catch (e) {
|
|
318
|
+
if (typeof e === "object" && typeof (<any>e).message === "string") {
|
|
319
|
+
throw new GraphQLError((<any>e).message);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
throw e;
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
args: queryArgs,
|
|
326
|
+
};
|
|
276
327
|
};
|
|
277
328
|
|
|
278
329
|
const generateUpdate = (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
330
|
+
db: BaseSQLiteDatabase<any, any, any, any>,
|
|
331
|
+
tableName: string,
|
|
332
|
+
table: SQLiteTable,
|
|
333
|
+
setArgs: GraphQLInputObjectType,
|
|
334
|
+
filterArgs: GraphQLInputObjectType
|
|
284
335
|
): CreatedResolver => {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
+
const queryName = `update${capitalize(tableName)}`;
|
|
337
|
+
const typeName = `${capitalize(tableName)}Item`;
|
|
338
|
+
|
|
339
|
+
const queryArgs = {
|
|
340
|
+
set: {
|
|
341
|
+
type: new GraphQLNonNull(setArgs),
|
|
342
|
+
},
|
|
343
|
+
where: {
|
|
344
|
+
type: filterArgs,
|
|
345
|
+
},
|
|
346
|
+
} as const satisfies GraphQLFieldConfigArgumentMap;
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
name: queryName,
|
|
350
|
+
resolver: async (
|
|
351
|
+
source,
|
|
352
|
+
args: { where?: Filters<Table>; set: Record<string, any> },
|
|
353
|
+
context,
|
|
354
|
+
info
|
|
355
|
+
) => {
|
|
356
|
+
try {
|
|
357
|
+
const { where, set } = args;
|
|
358
|
+
|
|
359
|
+
const parsedInfo = parseResolveInfo(info, {
|
|
360
|
+
deep: true,
|
|
361
|
+
}) as ResolveTree;
|
|
362
|
+
|
|
363
|
+
const columns = extractSelectedColumnsFromTreeSQLFormat<SQLiteColumn>(
|
|
364
|
+
parsedInfo.fieldsByTypeName[typeName]!,
|
|
365
|
+
table
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
const input = remapFromGraphQLSingleInput(set, table);
|
|
369
|
+
if (!Object.keys(input).length)
|
|
370
|
+
throw new GraphQLError("Unable to update with no values specified!");
|
|
371
|
+
|
|
372
|
+
let query = db.update(table).set(input);
|
|
373
|
+
if (where) {
|
|
374
|
+
const filters = extractFilters(table, tableName, where);
|
|
375
|
+
query = query.where(filters) as any;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
query = query.returning(columns) as any;
|
|
379
|
+
|
|
380
|
+
const result = await query;
|
|
381
|
+
|
|
382
|
+
return remapToGraphQLArrayOutput(result, tableName, table);
|
|
383
|
+
} catch (e) {
|
|
384
|
+
if (typeof e === "object" && typeof (<any>e).message === "string") {
|
|
385
|
+
throw new GraphQLError((<any>e).message);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
throw e;
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
args: queryArgs,
|
|
392
|
+
};
|
|
336
393
|
};
|
|
337
394
|
|
|
338
395
|
const generateDelete = (
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
396
|
+
db: BaseSQLiteDatabase<any, any, any, any>,
|
|
397
|
+
tableName: string,
|
|
398
|
+
table: SQLiteTable,
|
|
399
|
+
filterArgs: GraphQLInputObjectType
|
|
343
400
|
): CreatedResolver => {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
401
|
+
const queryName = `deleteFrom${capitalize(tableName)}`;
|
|
402
|
+
const typeName = `${capitalize(tableName)}Item`;
|
|
403
|
+
|
|
404
|
+
const queryArgs = {
|
|
405
|
+
where: {
|
|
406
|
+
type: filterArgs,
|
|
407
|
+
},
|
|
408
|
+
} as const satisfies GraphQLFieldConfigArgumentMap;
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
name: queryName,
|
|
412
|
+
resolver: async (
|
|
413
|
+
source,
|
|
414
|
+
args: { where?: Filters<Table> },
|
|
415
|
+
context,
|
|
416
|
+
info
|
|
417
|
+
) => {
|
|
418
|
+
try {
|
|
419
|
+
const { where } = args;
|
|
420
|
+
|
|
421
|
+
const parsedInfo = parseResolveInfo(info, {
|
|
422
|
+
deep: true,
|
|
423
|
+
}) as ResolveTree;
|
|
424
|
+
|
|
425
|
+
const columns = extractSelectedColumnsFromTreeSQLFormat<SQLiteColumn>(
|
|
426
|
+
parsedInfo.fieldsByTypeName[typeName]!,
|
|
427
|
+
table
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
let query = db.delete(table);
|
|
431
|
+
if (where) {
|
|
432
|
+
const filters = extractFilters(table, tableName, where);
|
|
433
|
+
query = query.where(filters) as any;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
query = query.returning(columns) as any;
|
|
437
|
+
|
|
438
|
+
const result = await query;
|
|
439
|
+
|
|
440
|
+
return remapToGraphQLArrayOutput(result, tableName, table);
|
|
441
|
+
} catch (e) {
|
|
442
|
+
if (typeof e === "object" && typeof (<any>e).message === "string") {
|
|
443
|
+
throw new GraphQLError((<any>e).message);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
throw e;
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
args: queryArgs,
|
|
450
|
+
};
|
|
389
451
|
};
|
|
390
452
|
|
|
391
453
|
export const generateSchemaData = <
|
|
392
|
-
|
|
393
|
-
|
|
454
|
+
TDrizzleInstance extends BaseSQLiteDatabase<any, any, any, any>,
|
|
455
|
+
TSchema extends Record<string, Table | unknown>
|
|
394
456
|
>(
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
457
|
+
db: TDrizzleInstance,
|
|
458
|
+
schema: TSchema,
|
|
459
|
+
relationsDepthLimit: number | undefined
|
|
398
460
|
): GeneratedEntities<TDrizzleInstance, TSchema> => {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
461
|
+
const rawSchema = schema;
|
|
462
|
+
const schemaEntries = Object.entries(rawSchema);
|
|
463
|
+
|
|
464
|
+
const tableEntries = schemaEntries.filter(([key, value]) =>
|
|
465
|
+
is(value, SQLiteTable)
|
|
466
|
+
) as [string, SQLiteTable][];
|
|
467
|
+
const tables = Object.fromEntries(tableEntries) as Record<
|
|
468
|
+
string,
|
|
469
|
+
SQLiteTable
|
|
470
|
+
>;
|
|
471
|
+
|
|
472
|
+
if (!tableEntries.length) {
|
|
473
|
+
throw new Error(
|
|
474
|
+
"Drizzle-GraphQL Error: No tables detected in Drizzle-ORM's database instance. Did you forget to pass schema to drizzle constructor?"
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const rawRelations = schemaEntries
|
|
479
|
+
.filter(([key, value]) => is(value, Relations))
|
|
480
|
+
.map<[string, Relations]>(([key, value]) => [
|
|
481
|
+
tableEntries.find(
|
|
482
|
+
([tableName, tableValue]) => tableValue === (value as Relations).table
|
|
483
|
+
)![0] as string,
|
|
484
|
+
value as Relations,
|
|
485
|
+
])
|
|
486
|
+
.map<[string, Record<string, Relation>]>(([tableName, relValue]) => [
|
|
487
|
+
tableName,
|
|
488
|
+
relValue.config(createTableRelationsHelpers(tables[tableName]!)),
|
|
489
|
+
]);
|
|
490
|
+
|
|
491
|
+
const namedRelations = Object.fromEntries(
|
|
492
|
+
rawRelations.map(([relName, config]) => {
|
|
493
|
+
const namedConfig: Record<string, TableNamedRelations> =
|
|
494
|
+
Object.fromEntries(
|
|
495
|
+
Object.entries(config).map(([innerRelName, innerRelValue]) => [
|
|
496
|
+
innerRelName,
|
|
497
|
+
{
|
|
498
|
+
relation: innerRelValue,
|
|
499
|
+
targetTableName: tableEntries.find(
|
|
500
|
+
([tableName, tableValue]) =>
|
|
501
|
+
tableValue === innerRelValue.referencedTable
|
|
502
|
+
)![0],
|
|
503
|
+
},
|
|
504
|
+
])
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
return [relName, namedConfig];
|
|
508
|
+
})
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
const queries: ThunkObjMap<GraphQLFieldConfig<any, any>> = {};
|
|
512
|
+
const mutations: ThunkObjMap<GraphQLFieldConfig<any, any>> = {};
|
|
513
|
+
const gqlSchemaTypes = Object.fromEntries(
|
|
514
|
+
Object.entries(tables).map(([tableName, table]) => [
|
|
515
|
+
tableName,
|
|
516
|
+
generateTableTypes(
|
|
517
|
+
tableName,
|
|
518
|
+
tables,
|
|
519
|
+
namedRelations,
|
|
520
|
+
true,
|
|
521
|
+
relationsDepthLimit
|
|
522
|
+
),
|
|
523
|
+
])
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
const inputs: Record<string, GraphQLInputObjectType> = {};
|
|
527
|
+
const interfaces: Record<string, GraphQLInterfaceType> = {};
|
|
528
|
+
const outputs: Record<string, GraphQLObjectType> = {};
|
|
529
|
+
|
|
530
|
+
for (const [tableName, tableTypes] of Object.entries(gqlSchemaTypes)) {
|
|
531
|
+
const { insertInput, updateInput, tableFilters, tableOrder } =
|
|
532
|
+
tableTypes.inputs;
|
|
533
|
+
const {
|
|
534
|
+
selectSingleOutput,
|
|
535
|
+
selectArrOutput,
|
|
536
|
+
singleTableItemOutput,
|
|
537
|
+
arrTableItemOutput,
|
|
538
|
+
tableFieldsInterface,
|
|
539
|
+
} = tableTypes.outputs;
|
|
540
|
+
|
|
541
|
+
const selectArrGenerated = generateSelectArray(
|
|
542
|
+
db,
|
|
543
|
+
tableName,
|
|
544
|
+
tables,
|
|
545
|
+
namedRelations,
|
|
546
|
+
tableOrder,
|
|
547
|
+
tableFilters
|
|
548
|
+
);
|
|
549
|
+
const selectSingleGenerated = generateSelectSingle(
|
|
550
|
+
db,
|
|
551
|
+
tableName,
|
|
552
|
+
tables,
|
|
553
|
+
namedRelations,
|
|
554
|
+
tableOrder,
|
|
555
|
+
tableFilters
|
|
556
|
+
);
|
|
557
|
+
const insertArrGenerated = generateInsertArray(
|
|
558
|
+
db,
|
|
559
|
+
tableName,
|
|
560
|
+
schema[tableName] as SQLiteTable,
|
|
561
|
+
insertInput
|
|
562
|
+
);
|
|
563
|
+
const insertSingleGenerated = generateInsertSingle(
|
|
564
|
+
db,
|
|
565
|
+
tableName,
|
|
566
|
+
schema[tableName] as SQLiteTable,
|
|
567
|
+
insertInput
|
|
568
|
+
);
|
|
569
|
+
const updateGenerated = generateUpdate(
|
|
570
|
+
db,
|
|
571
|
+
tableName,
|
|
572
|
+
schema[tableName] as SQLiteTable,
|
|
573
|
+
updateInput,
|
|
574
|
+
tableFilters
|
|
575
|
+
);
|
|
576
|
+
const deleteGenerated = generateDelete(
|
|
577
|
+
db,
|
|
578
|
+
tableName,
|
|
579
|
+
schema[tableName] as SQLiteTable,
|
|
580
|
+
tableFilters
|
|
581
|
+
);
|
|
582
|
+
|
|
583
|
+
queries[selectArrGenerated.name] = {
|
|
584
|
+
type: selectArrOutput,
|
|
585
|
+
args: selectArrGenerated.args,
|
|
586
|
+
resolve: selectArrGenerated.resolver,
|
|
587
|
+
};
|
|
588
|
+
queries[selectSingleGenerated.name] = {
|
|
589
|
+
type: selectSingleOutput,
|
|
590
|
+
args: selectSingleGenerated.args,
|
|
591
|
+
resolve: selectSingleGenerated.resolver,
|
|
592
|
+
};
|
|
593
|
+
mutations[insertArrGenerated.name] = {
|
|
594
|
+
type: arrTableItemOutput,
|
|
595
|
+
args: insertArrGenerated.args,
|
|
596
|
+
resolve: insertArrGenerated.resolver,
|
|
597
|
+
};
|
|
598
|
+
mutations[insertSingleGenerated.name] = {
|
|
599
|
+
type: singleTableItemOutput,
|
|
600
|
+
args: insertSingleGenerated.args,
|
|
601
|
+
resolve: insertSingleGenerated.resolver,
|
|
602
|
+
};
|
|
603
|
+
mutations[updateGenerated.name] = {
|
|
604
|
+
type: arrTableItemOutput,
|
|
605
|
+
args: updateGenerated.args,
|
|
606
|
+
resolve: updateGenerated.resolver,
|
|
607
|
+
};
|
|
608
|
+
mutations[deleteGenerated.name] = {
|
|
609
|
+
type: arrTableItemOutput,
|
|
610
|
+
args: deleteGenerated.args,
|
|
611
|
+
resolve: deleteGenerated.resolver,
|
|
612
|
+
};
|
|
613
|
+
[insertInput, updateInput, tableFilters, tableOrder].forEach(
|
|
614
|
+
(e) => (inputs[e.name] = e)
|
|
615
|
+
);
|
|
616
|
+
outputs[selectSingleOutput.name] = selectSingleOutput;
|
|
617
|
+
outputs[singleTableItemOutput.name] = singleTableItemOutput;
|
|
618
|
+
interfaces[tableFieldsInterface.name] = tableFieldsInterface;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return { queries, mutations, inputs, interfaces, types: outputs } as any;
|
|
524
622
|
};
|