drizzle-graphql-plus 0.8.7 → 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.
@@ -0,0 +1,842 @@
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
+ };