drizzle-graphql-plus 0.8.9 → 0.8.10
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/index.cjs +2125 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +251 -0
- package/index.d.ts +251 -0
- package/index.js +2177 -0
- package/index.js.map +1 -0
- package/package.json +16 -15
- package/.github/workflows/release.yaml +0 -74
- package/LICENSE +0 -201
- package/dprint.json +0 -31
- package/drizzle.test-config.ts +0 -29
- package/scripts/build.ts +0 -28
- package/src/index.ts +0 -74
- package/src/types.ts +0 -535
- package/src/util/builders/common.ts +0 -842
- package/src/util/builders/index.ts +0 -5
- package/src/util/builders/mysql.ts +0 -567
- package/src/util/builders/pg.ts +0 -616
- package/src/util/builders/sqlite.ts +0 -622
- package/src/util/builders/types.ts +0 -317
- package/src/util/case-ops/index.ts +0 -9
- package/src/util/data-mappers/index.ts +0 -162
- package/src/util/type-converter/index.ts +0 -148
- package/src/util/type-converter/types.ts +0 -54
- package/tests/mysql-custom.test.ts +0 -2009
- package/tests/mysql.test.ts +0 -4600
- package/tests/pg-custom.test.ts +0 -2054
- package/tests/pg.test.ts +0 -4285
- package/tests/schema/mysql.ts +0 -72
- package/tests/schema/pg.ts +0 -83
- package/tests/schema/sqlite.ts +0 -64
- package/tests/sqlite-custom.test.ts +0 -1956
- package/tests/sqlite.test.ts +0 -3749
- package/tests/tsconfig.json +0 -11
- package/tests/util/query/index.ts +0 -30
- package/tsconfig.build.json +0 -4
- package/tsconfig.dts.json +0 -13
- package/tsconfig.json +0 -48
- package/vitest.config.ts +0 -17
|
@@ -1,842 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
and,
|
|
3
|
-
asc,
|
|
4
|
-
desc,
|
|
5
|
-
eq,
|
|
6
|
-
getTableColumns,
|
|
7
|
-
gt,
|
|
8
|
-
gte,
|
|
9
|
-
ilike,
|
|
10
|
-
inArray,
|
|
11
|
-
is,
|
|
12
|
-
isNotNull,
|
|
13
|
-
isNull,
|
|
14
|
-
like,
|
|
15
|
-
lt,
|
|
16
|
-
lte,
|
|
17
|
-
ne,
|
|
18
|
-
notIlike,
|
|
19
|
-
notInArray,
|
|
20
|
-
notLike,
|
|
21
|
-
One,
|
|
22
|
-
or,
|
|
23
|
-
SQL,
|
|
24
|
-
} from "drizzle-orm";
|
|
25
|
-
import {
|
|
26
|
-
GraphQLBoolean,
|
|
27
|
-
GraphQLEnumType,
|
|
28
|
-
GraphQLError,
|
|
29
|
-
GraphQLInputObjectType,
|
|
30
|
-
GraphQLInt,
|
|
31
|
-
GraphQLList,
|
|
32
|
-
GraphQLNonNull,
|
|
33
|
-
GraphQLObjectType,
|
|
34
|
-
GraphQLString,
|
|
35
|
-
GraphQLInterfaceType,
|
|
36
|
-
} from "graphql";
|
|
37
|
-
|
|
38
|
-
import { capitalize } from "@/util/case-ops";
|
|
39
|
-
import { remapFromGraphQLCore } from "@/util/data-mappers";
|
|
40
|
-
import {
|
|
41
|
-
ConvertedColumn,
|
|
42
|
-
ConvertedInputColumn,
|
|
43
|
-
ConvertedRelationColumnWithArgs,
|
|
44
|
-
drizzleColumnToGraphQLType,
|
|
45
|
-
} from "@/util/type-converter";
|
|
46
|
-
|
|
47
|
-
import type { Column, Table } from "drizzle-orm";
|
|
48
|
-
import type { ResolveTree } from "graphql-parse-resolve-info";
|
|
49
|
-
import type {
|
|
50
|
-
FilterColumnOperators,
|
|
51
|
-
FilterColumnOperatorsCore,
|
|
52
|
-
Filters,
|
|
53
|
-
FiltersCore,
|
|
54
|
-
GeneratedTableTypes,
|
|
55
|
-
GeneratedTableTypesOutputs,
|
|
56
|
-
OrderByArgs,
|
|
57
|
-
ProcessedTableSelectArgs,
|
|
58
|
-
SelectData,
|
|
59
|
-
SelectedColumnsRaw,
|
|
60
|
-
SelectedSQLColumns,
|
|
61
|
-
TableNamedRelations,
|
|
62
|
-
TableSelectArgs,
|
|
63
|
-
} from "./types";
|
|
64
|
-
|
|
65
|
-
const rqbCrashTypes = ["SQLiteBigInt", "SQLiteBlobJson", "SQLiteBlobBuffer"];
|
|
66
|
-
|
|
67
|
-
export const extractSelectedColumnsFromTree = (
|
|
68
|
-
tree: Record<string, ResolveTree>,
|
|
69
|
-
table: Table
|
|
70
|
-
): Record<string, true> => {
|
|
71
|
-
const tableColumns = getTableColumns(table);
|
|
72
|
-
|
|
73
|
-
const treeEntries = Object.entries(tree);
|
|
74
|
-
const selectedColumns: SelectedColumnsRaw = [];
|
|
75
|
-
|
|
76
|
-
for (const [fieldName, fieldData] of treeEntries) {
|
|
77
|
-
if (!tableColumns[fieldData.name]) continue;
|
|
78
|
-
|
|
79
|
-
selectedColumns.push([fieldData.name, true]);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!selectedColumns.length) {
|
|
83
|
-
const columnKeys = Object.entries(tableColumns);
|
|
84
|
-
const columnName =
|
|
85
|
-
columnKeys.find((e) =>
|
|
86
|
-
rqbCrashTypes.find((haram) => e[1].columnType !== haram)
|
|
87
|
-
)?.[0] ?? columnKeys[0]![0];
|
|
88
|
-
|
|
89
|
-
selectedColumns.push([columnName, true]);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return Object.fromEntries(selectedColumns);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Can't automatically determine column type on type level
|
|
97
|
-
* Since drizzle table types extend eachother
|
|
98
|
-
*/
|
|
99
|
-
export const extractSelectedColumnsFromTreeSQLFormat = <
|
|
100
|
-
TColType extends Column = Column
|
|
101
|
-
>(
|
|
102
|
-
tree: Record<string, ResolveTree>,
|
|
103
|
-
table: Table
|
|
104
|
-
): Record<string, TColType> => {
|
|
105
|
-
const tableColumns = getTableColumns(table);
|
|
106
|
-
|
|
107
|
-
const treeEntries = Object.entries(tree);
|
|
108
|
-
const selectedColumns: SelectedSQLColumns = [];
|
|
109
|
-
|
|
110
|
-
for (const [fieldName, fieldData] of treeEntries) {
|
|
111
|
-
if (!tableColumns[fieldData.name]) continue;
|
|
112
|
-
|
|
113
|
-
selectedColumns.push([fieldData.name, tableColumns[fieldData.name]!]);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!selectedColumns.length) {
|
|
117
|
-
const columnKeys = Object.entries(tableColumns);
|
|
118
|
-
const columnName =
|
|
119
|
-
columnKeys.find((e) =>
|
|
120
|
-
rqbCrashTypes.find((haram) => e[1].columnType !== haram)
|
|
121
|
-
)?.[0] ?? columnKeys[0]![0];
|
|
122
|
-
|
|
123
|
-
selectedColumns.push([columnName, tableColumns[columnName]!]);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return Object.fromEntries(selectedColumns) as Record<string, TColType>;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
export const innerOrder = new GraphQLInputObjectType({
|
|
130
|
-
name: "InnerOrder" as const,
|
|
131
|
-
fields: {
|
|
132
|
-
direction: {
|
|
133
|
-
type: new GraphQLNonNull(
|
|
134
|
-
new GraphQLEnumType({
|
|
135
|
-
name: "OrderDirection",
|
|
136
|
-
description: "Order by direction",
|
|
137
|
-
values: {
|
|
138
|
-
asc: {
|
|
139
|
-
value: "asc",
|
|
140
|
-
description: "Ascending order",
|
|
141
|
-
},
|
|
142
|
-
desc: {
|
|
143
|
-
value: "desc",
|
|
144
|
-
description: "Descending order",
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
})
|
|
148
|
-
),
|
|
149
|
-
},
|
|
150
|
-
priority: {
|
|
151
|
-
type: new GraphQLNonNull(GraphQLInt),
|
|
152
|
-
description: "Priority of current field",
|
|
153
|
-
},
|
|
154
|
-
} as const,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
const generateColumnFilterValues = (
|
|
158
|
-
column: Column,
|
|
159
|
-
tableName: string,
|
|
160
|
-
columnName: string
|
|
161
|
-
): GraphQLInputObjectType => {
|
|
162
|
-
const columnGraphQLType = drizzleColumnToGraphQLType(
|
|
163
|
-
column,
|
|
164
|
-
columnName,
|
|
165
|
-
tableName,
|
|
166
|
-
true,
|
|
167
|
-
false,
|
|
168
|
-
true
|
|
169
|
-
);
|
|
170
|
-
const columnArr = new GraphQLList(new GraphQLNonNull(columnGraphQLType.type));
|
|
171
|
-
|
|
172
|
-
const baseFields = {
|
|
173
|
-
eq: {
|
|
174
|
-
type: columnGraphQLType.type,
|
|
175
|
-
description: columnGraphQLType.description,
|
|
176
|
-
},
|
|
177
|
-
ne: {
|
|
178
|
-
type: columnGraphQLType.type,
|
|
179
|
-
description: columnGraphQLType.description,
|
|
180
|
-
},
|
|
181
|
-
lt: {
|
|
182
|
-
type: columnGraphQLType.type,
|
|
183
|
-
description: columnGraphQLType.description,
|
|
184
|
-
},
|
|
185
|
-
lte: {
|
|
186
|
-
type: columnGraphQLType.type,
|
|
187
|
-
description: columnGraphQLType.description,
|
|
188
|
-
},
|
|
189
|
-
gt: {
|
|
190
|
-
type: columnGraphQLType.type,
|
|
191
|
-
description: columnGraphQLType.description,
|
|
192
|
-
},
|
|
193
|
-
gte: {
|
|
194
|
-
type: columnGraphQLType.type,
|
|
195
|
-
description: columnGraphQLType.description,
|
|
196
|
-
},
|
|
197
|
-
like: { type: GraphQLString },
|
|
198
|
-
notLike: { type: GraphQLString },
|
|
199
|
-
ilike: { type: GraphQLString },
|
|
200
|
-
notIlike: { type: GraphQLString },
|
|
201
|
-
inArray: {
|
|
202
|
-
type: columnArr,
|
|
203
|
-
description: `Array<${columnGraphQLType.description}>`,
|
|
204
|
-
},
|
|
205
|
-
notInArray: {
|
|
206
|
-
type: columnArr,
|
|
207
|
-
description: `Array<${columnGraphQLType.description}>`,
|
|
208
|
-
},
|
|
209
|
-
isNull: { type: GraphQLBoolean },
|
|
210
|
-
isNotNull: { type: GraphQLBoolean },
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const type: GraphQLInputObjectType = new GraphQLInputObjectType({
|
|
214
|
-
name: `${capitalize(tableName)}${capitalize(columnName)}Filters`,
|
|
215
|
-
fields: {
|
|
216
|
-
...baseFields,
|
|
217
|
-
OR: {
|
|
218
|
-
type: new GraphQLList(
|
|
219
|
-
new GraphQLNonNull(
|
|
220
|
-
new GraphQLInputObjectType({
|
|
221
|
-
name: `${capitalize(tableName)}${capitalize(
|
|
222
|
-
columnName
|
|
223
|
-
)}filtersOr`,
|
|
224
|
-
fields: {
|
|
225
|
-
...baseFields,
|
|
226
|
-
},
|
|
227
|
-
})
|
|
228
|
-
)
|
|
229
|
-
),
|
|
230
|
-
},
|
|
231
|
-
},
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
return type;
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const orderMap = new WeakMap<Object, Record<string, ConvertedInputColumn>>();
|
|
238
|
-
const generateTableOrderCached = (table: Table) => {
|
|
239
|
-
if (orderMap.has(table)) return orderMap.get(table)!;
|
|
240
|
-
|
|
241
|
-
const columns = getTableColumns(table);
|
|
242
|
-
const columnEntries = Object.entries(columns);
|
|
243
|
-
|
|
244
|
-
const remapped = Object.fromEntries(
|
|
245
|
-
columnEntries.map(([columnName, columnDescription]) => [
|
|
246
|
-
columnName,
|
|
247
|
-
{ type: innerOrder },
|
|
248
|
-
])
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
orderMap.set(table, remapped);
|
|
252
|
-
|
|
253
|
-
return remapped;
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
const filterMap = new WeakMap<Object, Record<string, ConvertedInputColumn>>();
|
|
257
|
-
const generateTableFilterValuesCached = (table: Table, tableName: string) => {
|
|
258
|
-
if (filterMap.has(table)) return filterMap.get(table)!;
|
|
259
|
-
|
|
260
|
-
const columns = getTableColumns(table);
|
|
261
|
-
const columnEntries = Object.entries(columns);
|
|
262
|
-
|
|
263
|
-
const remapped = Object.fromEntries(
|
|
264
|
-
columnEntries.map(([columnName, columnDescription]) => [
|
|
265
|
-
columnName,
|
|
266
|
-
{
|
|
267
|
-
type: generateColumnFilterValues(
|
|
268
|
-
columnDescription,
|
|
269
|
-
tableName,
|
|
270
|
-
columnName
|
|
271
|
-
),
|
|
272
|
-
},
|
|
273
|
-
])
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
filterMap.set(table, remapped);
|
|
277
|
-
|
|
278
|
-
return remapped;
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const fieldMap = new WeakMap<Object, Record<string, ConvertedColumn>>();
|
|
282
|
-
const generateTableSelectTypeFieldsCached = (
|
|
283
|
-
table: Table,
|
|
284
|
-
tableName: string
|
|
285
|
-
): Record<string, ConvertedColumn> => {
|
|
286
|
-
if (fieldMap.has(table)) return fieldMap.get(table)!;
|
|
287
|
-
|
|
288
|
-
const columns = getTableColumns(table);
|
|
289
|
-
const columnEntries = Object.entries(columns);
|
|
290
|
-
|
|
291
|
-
const remapped = Object.fromEntries(
|
|
292
|
-
columnEntries.map(([columnName, columnDescription]) => [
|
|
293
|
-
columnName,
|
|
294
|
-
drizzleColumnToGraphQLType(columnDescription, columnName, tableName),
|
|
295
|
-
])
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
fieldMap.set(table, remapped);
|
|
299
|
-
|
|
300
|
-
return remapped;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
const orderTypeMap = new WeakMap<Object, GraphQLInputObjectType>();
|
|
304
|
-
const generateTableOrderTypeCached = (table: Table, tableName: string) => {
|
|
305
|
-
if (orderTypeMap.has(table)) return orderTypeMap.get(table)!;
|
|
306
|
-
|
|
307
|
-
const orderColumns = generateTableOrderCached(table);
|
|
308
|
-
const order = new GraphQLInputObjectType({
|
|
309
|
-
name: `${capitalize(tableName)}OrderBy`,
|
|
310
|
-
fields: orderColumns,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
orderTypeMap.set(table, order);
|
|
314
|
-
|
|
315
|
-
return order;
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
const filterTypeMap = new WeakMap<Object, GraphQLInputObjectType>();
|
|
319
|
-
const generateTableFilterTypeCached = (table: Table, tableName: string) => {
|
|
320
|
-
if (filterTypeMap.has(table)) return filterTypeMap.get(table)!;
|
|
321
|
-
|
|
322
|
-
const filterColumns = generateTableFilterValuesCached(table, tableName);
|
|
323
|
-
const filters: GraphQLInputObjectType = new GraphQLInputObjectType({
|
|
324
|
-
name: `${capitalize(tableName)}Filters`,
|
|
325
|
-
fields: {
|
|
326
|
-
...filterColumns,
|
|
327
|
-
OR: {
|
|
328
|
-
type: new GraphQLList(
|
|
329
|
-
new GraphQLNonNull(
|
|
330
|
-
new GraphQLInputObjectType({
|
|
331
|
-
name: `${capitalize(tableName)}FiltersOr`,
|
|
332
|
-
fields: filterColumns,
|
|
333
|
-
})
|
|
334
|
-
)
|
|
335
|
-
),
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
filterTypeMap.set(table, filters);
|
|
341
|
-
|
|
342
|
-
return filters;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
const generateSelectFields = <TWithOrder extends boolean>(
|
|
346
|
-
tables: Record<string, Table>,
|
|
347
|
-
tableName: string,
|
|
348
|
-
relationMap: Record<string, Record<string, TableNamedRelations>>,
|
|
349
|
-
typeName: string,
|
|
350
|
-
withOrder: TWithOrder,
|
|
351
|
-
relationsDepthLimit: number | undefined,
|
|
352
|
-
currentDepth: number = 0,
|
|
353
|
-
usedTables: Set<string> = new Set()
|
|
354
|
-
): SelectData<TWithOrder> => {
|
|
355
|
-
const relations = relationMap[tableName];
|
|
356
|
-
const relationEntries: [string, TableNamedRelations][] = relations
|
|
357
|
-
? Object.entries(relations)
|
|
358
|
-
: [];
|
|
359
|
-
|
|
360
|
-
const table = tables[tableName]!;
|
|
361
|
-
|
|
362
|
-
const order = withOrder
|
|
363
|
-
? generateTableOrderTypeCached(table, tableName)
|
|
364
|
-
: undefined;
|
|
365
|
-
|
|
366
|
-
const filters = generateTableFilterTypeCached(table, tableName);
|
|
367
|
-
|
|
368
|
-
const tableFields = generateTableSelectTypeFieldsCached(table, tableName);
|
|
369
|
-
|
|
370
|
-
if (
|
|
371
|
-
usedTables.has(tableName) ||
|
|
372
|
-
(typeof relationsDepthLimit === "number" &&
|
|
373
|
-
currentDepth >= relationsDepthLimit) ||
|
|
374
|
-
!relationEntries.length
|
|
375
|
-
) {
|
|
376
|
-
return {
|
|
377
|
-
order,
|
|
378
|
-
filters,
|
|
379
|
-
tableFields,
|
|
380
|
-
relationFields: {},
|
|
381
|
-
} as SelectData<TWithOrder>;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const rawRelationFields: [string, ConvertedRelationColumnWithArgs][] = [];
|
|
385
|
-
const updatedUsedTables = new Set(usedTables).add(tableName);
|
|
386
|
-
const newDepth = currentDepth + 1;
|
|
387
|
-
|
|
388
|
-
for (const [relationName, { targetTableName, relation }] of relationEntries) {
|
|
389
|
-
const relTypeName = `${typeName}${capitalize(relationName)}Relation`;
|
|
390
|
-
const isOne = is(relation, One);
|
|
391
|
-
|
|
392
|
-
const relData = generateSelectFields(
|
|
393
|
-
tables,
|
|
394
|
-
targetTableName,
|
|
395
|
-
relationMap,
|
|
396
|
-
relTypeName,
|
|
397
|
-
!isOne,
|
|
398
|
-
relationsDepthLimit,
|
|
399
|
-
newDepth,
|
|
400
|
-
updatedUsedTables
|
|
401
|
-
);
|
|
402
|
-
|
|
403
|
-
const relType = new GraphQLObjectType({
|
|
404
|
-
name: relTypeName,
|
|
405
|
-
fields: { ...relData.tableFields, ...relData.relationFields },
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
if (isOne) {
|
|
409
|
-
rawRelationFields.push([
|
|
410
|
-
relationName,
|
|
411
|
-
{
|
|
412
|
-
type: relType,
|
|
413
|
-
args: {
|
|
414
|
-
where: { type: relData.filters },
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
]);
|
|
418
|
-
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
rawRelationFields.push([
|
|
423
|
-
relationName,
|
|
424
|
-
{
|
|
425
|
-
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(relType))),
|
|
426
|
-
args: {
|
|
427
|
-
where: { type: relData.filters },
|
|
428
|
-
orderBy: { type: relData.order! },
|
|
429
|
-
offset: { type: GraphQLInt },
|
|
430
|
-
limit: { type: GraphQLInt },
|
|
431
|
-
},
|
|
432
|
-
},
|
|
433
|
-
]);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const relationFields = Object.fromEntries(rawRelationFields);
|
|
437
|
-
|
|
438
|
-
return {
|
|
439
|
-
order,
|
|
440
|
-
filters,
|
|
441
|
-
tableFields,
|
|
442
|
-
relationFields,
|
|
443
|
-
} as SelectData<TWithOrder>;
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
export const generateTableTypes = <WithReturning extends boolean>(
|
|
447
|
-
tableName: string,
|
|
448
|
-
tables: Record<string, Table>,
|
|
449
|
-
relationMap: Record<string, Record<string, TableNamedRelations>>,
|
|
450
|
-
withReturning: WithReturning,
|
|
451
|
-
relationsDepthLimit: number | undefined
|
|
452
|
-
): GeneratedTableTypes<WithReturning> => {
|
|
453
|
-
const stylizedName = capitalize(tableName);
|
|
454
|
-
const { tableFields, relationFields, filters, order } = generateSelectFields(
|
|
455
|
-
tables,
|
|
456
|
-
tableName,
|
|
457
|
-
relationMap,
|
|
458
|
-
stylizedName,
|
|
459
|
-
true,
|
|
460
|
-
relationsDepthLimit
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
const table = tables[tableName]!;
|
|
464
|
-
const columns = getTableColumns(table);
|
|
465
|
-
const columnEntries = Object.entries(columns);
|
|
466
|
-
|
|
467
|
-
const insertFields = Object.fromEntries(
|
|
468
|
-
columnEntries.map(([columnName, columnDescription]) => [
|
|
469
|
-
columnName,
|
|
470
|
-
drizzleColumnToGraphQLType(
|
|
471
|
-
columnDescription,
|
|
472
|
-
columnName,
|
|
473
|
-
tableName,
|
|
474
|
-
false,
|
|
475
|
-
true,
|
|
476
|
-
true
|
|
477
|
-
),
|
|
478
|
-
])
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
const updateFields = Object.fromEntries(
|
|
482
|
-
columnEntries.map(([columnName, columnDescription]) => [
|
|
483
|
-
columnName,
|
|
484
|
-
drizzleColumnToGraphQLType(
|
|
485
|
-
columnDescription,
|
|
486
|
-
columnName,
|
|
487
|
-
tableName,
|
|
488
|
-
true,
|
|
489
|
-
false,
|
|
490
|
-
true
|
|
491
|
-
),
|
|
492
|
-
])
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
const insertInput = new GraphQLInputObjectType({
|
|
496
|
-
name: `${stylizedName}InsertInput`,
|
|
497
|
-
fields: insertFields,
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
const tableFieldsInterface = new GraphQLInterfaceType({
|
|
501
|
-
name: `${stylizedName}Fields`,
|
|
502
|
-
fields: tableFields,
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
const selectSingleOutput = new GraphQLObjectType({
|
|
506
|
-
name: `${stylizedName}SelectItem`,
|
|
507
|
-
fields: { ...tableFields, ...relationFields },
|
|
508
|
-
interfaces: [tableFieldsInterface],
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
const selectArrOutput = new GraphQLNonNull(
|
|
512
|
-
new GraphQLList(new GraphQLNonNull(selectSingleOutput))
|
|
513
|
-
);
|
|
514
|
-
|
|
515
|
-
const singleTableItemOutput = withReturning
|
|
516
|
-
? new GraphQLObjectType({
|
|
517
|
-
name: `${stylizedName}Item`,
|
|
518
|
-
fields: tableFields,
|
|
519
|
-
interfaces: [tableFieldsInterface],
|
|
520
|
-
})
|
|
521
|
-
: undefined;
|
|
522
|
-
|
|
523
|
-
const arrTableItemOutput = withReturning
|
|
524
|
-
? new GraphQLNonNull(
|
|
525
|
-
new GraphQLList(new GraphQLNonNull(singleTableItemOutput!))
|
|
526
|
-
)
|
|
527
|
-
: undefined;
|
|
528
|
-
|
|
529
|
-
const updateInput = new GraphQLInputObjectType({
|
|
530
|
-
name: `${stylizedName}UpdateInput`,
|
|
531
|
-
fields: updateFields,
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
const inputs = {
|
|
535
|
-
insertInput,
|
|
536
|
-
updateInput,
|
|
537
|
-
tableOrder: order,
|
|
538
|
-
tableFilters: filters,
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
const outputs = (
|
|
542
|
-
withReturning
|
|
543
|
-
? {
|
|
544
|
-
selectSingleOutput,
|
|
545
|
-
selectArrOutput,
|
|
546
|
-
singleTableItemOutput: singleTableItemOutput!,
|
|
547
|
-
arrTableItemOutput: arrTableItemOutput!,
|
|
548
|
-
tableFieldsInterface,
|
|
549
|
-
}
|
|
550
|
-
: {
|
|
551
|
-
selectSingleOutput,
|
|
552
|
-
selectArrOutput,
|
|
553
|
-
tableFieldsInterface,
|
|
554
|
-
}
|
|
555
|
-
) as GeneratedTableTypesOutputs<WithReturning>;
|
|
556
|
-
|
|
557
|
-
return {
|
|
558
|
-
inputs,
|
|
559
|
-
outputs,
|
|
560
|
-
};
|
|
561
|
-
};
|
|
562
|
-
|
|
563
|
-
export const extractOrderBy = <
|
|
564
|
-
TTable extends Table,
|
|
565
|
-
TArgs extends OrderByArgs<any> = OrderByArgs<TTable>
|
|
566
|
-
>(
|
|
567
|
-
table: TTable,
|
|
568
|
-
orderArgs: TArgs
|
|
569
|
-
): SQL[] => {
|
|
570
|
-
const res = [] as SQL[];
|
|
571
|
-
|
|
572
|
-
for (const [column, config] of Object.entries(orderArgs).sort(
|
|
573
|
-
(a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0)
|
|
574
|
-
)) {
|
|
575
|
-
if (!config) continue;
|
|
576
|
-
const { direction } = config;
|
|
577
|
-
|
|
578
|
-
res.push(
|
|
579
|
-
direction === "asc"
|
|
580
|
-
? asc(getTableColumns(table)[column]!)
|
|
581
|
-
: desc(getTableColumns(table)[column]!)
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
return res;
|
|
586
|
-
};
|
|
587
|
-
|
|
588
|
-
export const extractFiltersColumn = <TColumn extends Column>(
|
|
589
|
-
column: TColumn,
|
|
590
|
-
columnName: string,
|
|
591
|
-
operators: FilterColumnOperators<TColumn>
|
|
592
|
-
): SQL | undefined => {
|
|
593
|
-
if (!operators.OR?.length) delete operators.OR;
|
|
594
|
-
|
|
595
|
-
const entries = Object.entries(
|
|
596
|
-
operators as FilterColumnOperatorsCore<TColumn>
|
|
597
|
-
);
|
|
598
|
-
|
|
599
|
-
if (operators.OR) {
|
|
600
|
-
if (entries.length > 1) {
|
|
601
|
-
throw new GraphQLError(
|
|
602
|
-
`WHERE ${columnName}: Cannot specify both fields and 'OR' in column operators!`
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
const variants = [] as SQL[];
|
|
607
|
-
|
|
608
|
-
for (const variant of operators.OR) {
|
|
609
|
-
const extracted = extractFiltersColumn(column, columnName, variant);
|
|
610
|
-
|
|
611
|
-
if (extracted) variants.push(extracted);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
return variants.length
|
|
615
|
-
? variants.length > 1
|
|
616
|
-
? or(...variants)
|
|
617
|
-
: variants[0]
|
|
618
|
-
: undefined;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
const variants = [] as SQL[];
|
|
622
|
-
for (const [operatorName, operatorValue] of entries) {
|
|
623
|
-
if (operatorValue === null || operatorValue === false) continue;
|
|
624
|
-
|
|
625
|
-
let operator: ((...args: any[]) => SQL) | undefined;
|
|
626
|
-
switch (operatorName as keyof FilterColumnOperatorsCore<TColumn>) {
|
|
627
|
-
// @ts-ignore
|
|
628
|
-
case "eq":
|
|
629
|
-
operator = operator ?? eq;
|
|
630
|
-
// @ts-ignore
|
|
631
|
-
case "ne":
|
|
632
|
-
operator = operator ?? ne;
|
|
633
|
-
// @ts-ignore
|
|
634
|
-
case "gt":
|
|
635
|
-
operator = operator ?? gt;
|
|
636
|
-
// @ts-ignore
|
|
637
|
-
case "gte":
|
|
638
|
-
operator = operator ?? gte;
|
|
639
|
-
// @ts-ignore
|
|
640
|
-
case "lt":
|
|
641
|
-
operator = operator ?? lt;
|
|
642
|
-
case "lte":
|
|
643
|
-
operator = operator ?? lte;
|
|
644
|
-
|
|
645
|
-
const singleValue = remapFromGraphQLCore(
|
|
646
|
-
operatorValue,
|
|
647
|
-
column,
|
|
648
|
-
columnName
|
|
649
|
-
);
|
|
650
|
-
variants.push(operator(column, singleValue));
|
|
651
|
-
|
|
652
|
-
break;
|
|
653
|
-
|
|
654
|
-
// @ts-ignore
|
|
655
|
-
case "like":
|
|
656
|
-
operator = operator ?? like;
|
|
657
|
-
// @ts-ignore
|
|
658
|
-
case "notLike":
|
|
659
|
-
operator = operator ?? notLike;
|
|
660
|
-
// @ts-ignore
|
|
661
|
-
case "ilike":
|
|
662
|
-
operator = operator ?? ilike;
|
|
663
|
-
case "notIlike":
|
|
664
|
-
operator = operator ?? notIlike;
|
|
665
|
-
|
|
666
|
-
variants.push(operator(column, operatorValue as string));
|
|
667
|
-
|
|
668
|
-
break;
|
|
669
|
-
|
|
670
|
-
// @ts-ignore
|
|
671
|
-
case "inArray":
|
|
672
|
-
operator = operator ?? inArray;
|
|
673
|
-
case "notInArray":
|
|
674
|
-
operator = operator ?? notInArray;
|
|
675
|
-
|
|
676
|
-
if (!(operatorValue as any[]).length) {
|
|
677
|
-
throw new GraphQLError(
|
|
678
|
-
`WHERE ${columnName}: Unable to use operator ${operatorName} with an empty array!`
|
|
679
|
-
);
|
|
680
|
-
}
|
|
681
|
-
const arrayValue = (operatorValue as any[]).map((val) =>
|
|
682
|
-
remapFromGraphQLCore(val, column, columnName)
|
|
683
|
-
);
|
|
684
|
-
|
|
685
|
-
variants.push(operator(column, arrayValue));
|
|
686
|
-
break;
|
|
687
|
-
|
|
688
|
-
// @ts-ignore
|
|
689
|
-
case "isNull":
|
|
690
|
-
operator = operator ?? isNull;
|
|
691
|
-
case "isNotNull":
|
|
692
|
-
operator = operator ?? isNotNull;
|
|
693
|
-
|
|
694
|
-
variants.push(operator(column));
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
return variants.length
|
|
699
|
-
? variants.length > 1
|
|
700
|
-
? and(...variants)
|
|
701
|
-
: variants[0]
|
|
702
|
-
: undefined;
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
export const extractFilters = <TTable extends Table>(
|
|
706
|
-
table: TTable,
|
|
707
|
-
tableName: string,
|
|
708
|
-
filters: Filters<TTable>
|
|
709
|
-
): SQL | undefined => {
|
|
710
|
-
if (!filters.OR?.length) delete filters.OR;
|
|
711
|
-
|
|
712
|
-
const entries = Object.entries(filters as FiltersCore<TTable>);
|
|
713
|
-
if (!entries.length) return;
|
|
714
|
-
|
|
715
|
-
if (filters.OR) {
|
|
716
|
-
if (entries.length > 1) {
|
|
717
|
-
throw new GraphQLError(
|
|
718
|
-
`WHERE ${tableName}: Cannot specify both fields and 'OR' in table filters!`
|
|
719
|
-
);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
const variants = [] as SQL[];
|
|
723
|
-
|
|
724
|
-
for (const variant of filters.OR) {
|
|
725
|
-
const extracted = extractFilters(table, tableName, variant);
|
|
726
|
-
if (extracted) variants.push(extracted);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
return variants.length
|
|
730
|
-
? variants.length > 1
|
|
731
|
-
? or(...variants)
|
|
732
|
-
: variants[0]
|
|
733
|
-
: undefined;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
const variants = [] as SQL[];
|
|
737
|
-
for (const [columnName, operators] of entries) {
|
|
738
|
-
if (operators === null) continue;
|
|
739
|
-
|
|
740
|
-
const column = getTableColumns(table)[columnName]!;
|
|
741
|
-
variants.push(extractFiltersColumn(column, columnName, operators)!);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
return variants.length
|
|
745
|
-
? variants.length > 1
|
|
746
|
-
? and(...variants)
|
|
747
|
-
: variants[0]
|
|
748
|
-
: undefined;
|
|
749
|
-
};
|
|
750
|
-
|
|
751
|
-
const extractRelationsParamsInner = (
|
|
752
|
-
relationMap: Record<string, Record<string, TableNamedRelations>>,
|
|
753
|
-
tables: Record<string, Table>,
|
|
754
|
-
tableName: string,
|
|
755
|
-
typeName: string,
|
|
756
|
-
originField: ResolveTree,
|
|
757
|
-
isInitial: boolean = false
|
|
758
|
-
) => {
|
|
759
|
-
const relations = relationMap[tableName];
|
|
760
|
-
if (!relations) return undefined;
|
|
761
|
-
|
|
762
|
-
const baseField = Object.entries(originField.fieldsByTypeName).find(
|
|
763
|
-
([key, value]) => key === typeName
|
|
764
|
-
)?.[1];
|
|
765
|
-
if (!baseField) return undefined;
|
|
766
|
-
|
|
767
|
-
const args: Record<string, Partial<ProcessedTableSelectArgs>> = {};
|
|
768
|
-
|
|
769
|
-
for (const [relName, { targetTableName, relation }] of Object.entries(
|
|
770
|
-
relations
|
|
771
|
-
)) {
|
|
772
|
-
const relTypeName = `${
|
|
773
|
-
isInitial ? capitalize(tableName) : typeName
|
|
774
|
-
}${capitalize(relName)}Relation`;
|
|
775
|
-
const relFieldSelection = Object.values(baseField).find(
|
|
776
|
-
(field) => field.name === relName
|
|
777
|
-
)?.fieldsByTypeName[relTypeName];
|
|
778
|
-
if (!relFieldSelection) continue;
|
|
779
|
-
|
|
780
|
-
const columns = extractSelectedColumnsFromTree(
|
|
781
|
-
relFieldSelection,
|
|
782
|
-
tables[targetTableName]!
|
|
783
|
-
);
|
|
784
|
-
|
|
785
|
-
const thisRecord: Partial<ProcessedTableSelectArgs> = {};
|
|
786
|
-
thisRecord.columns = columns;
|
|
787
|
-
|
|
788
|
-
const relationField = Object.values(baseField).find(
|
|
789
|
-
(e) => e.name === relName
|
|
790
|
-
);
|
|
791
|
-
const relationArgs: Partial<TableSelectArgs> | undefined =
|
|
792
|
-
relationField?.args;
|
|
793
|
-
|
|
794
|
-
const orderBy = relationArgs?.orderBy
|
|
795
|
-
? extractOrderBy(tables[targetTableName]!, relationArgs.orderBy!)
|
|
796
|
-
: undefined;
|
|
797
|
-
const where = relationArgs?.where
|
|
798
|
-
? extractFilters(tables[targetTableName]!, relName, relationArgs?.where)
|
|
799
|
-
: undefined;
|
|
800
|
-
const offset = relationArgs?.offset ?? undefined;
|
|
801
|
-
const limit = relationArgs?.limit ?? undefined;
|
|
802
|
-
|
|
803
|
-
thisRecord.orderBy = orderBy;
|
|
804
|
-
thisRecord.where = where;
|
|
805
|
-
thisRecord.offset = offset;
|
|
806
|
-
thisRecord.limit = limit;
|
|
807
|
-
|
|
808
|
-
const relWith = relationField
|
|
809
|
-
? extractRelationsParamsInner(
|
|
810
|
-
relationMap,
|
|
811
|
-
tables,
|
|
812
|
-
targetTableName,
|
|
813
|
-
relTypeName,
|
|
814
|
-
relationField
|
|
815
|
-
)
|
|
816
|
-
: undefined;
|
|
817
|
-
thisRecord.with = relWith;
|
|
818
|
-
|
|
819
|
-
args[relName] = thisRecord;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
return args;
|
|
823
|
-
};
|
|
824
|
-
|
|
825
|
-
export const extractRelationsParams = (
|
|
826
|
-
relationMap: Record<string, Record<string, TableNamedRelations>>,
|
|
827
|
-
tables: Record<string, Table>,
|
|
828
|
-
tableName: string,
|
|
829
|
-
info: ResolveTree | undefined,
|
|
830
|
-
typeName: string
|
|
831
|
-
): Record<string, Partial<ProcessedTableSelectArgs>> | undefined => {
|
|
832
|
-
if (!info) return undefined;
|
|
833
|
-
|
|
834
|
-
return extractRelationsParamsInner(
|
|
835
|
-
relationMap,
|
|
836
|
-
tables,
|
|
837
|
-
tableName,
|
|
838
|
-
typeName,
|
|
839
|
-
info,
|
|
840
|
-
true
|
|
841
|
-
);
|
|
842
|
-
};
|