@pothos/plugin-drizzle 0.16.2 → 0.17.1

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +5 -3
  3. package/dts/drizzle-field-builder.d.ts.map +1 -1
  4. package/dts/index.d.ts.map +1 -1
  5. package/dts/types.d.ts +14 -4
  6. package/dts/types.d.ts.map +1 -1
  7. package/dts/utils/map-query.d.ts.map +1 -1
  8. package/dts/utils/selections.d.ts.map +1 -1
  9. package/esm/connection-helpers.js +3 -4
  10. package/esm/connection-helpers.js.map +1 -1
  11. package/esm/drizzle-field-builder.d.ts.map +1 -1
  12. package/esm/drizzle-field-builder.js +10 -11
  13. package/esm/drizzle-field-builder.js.map +1 -1
  14. package/esm/index.d.ts.map +1 -1
  15. package/esm/index.js +11 -4
  16. package/esm/index.js.map +1 -1
  17. package/esm/schema-builder.js +5 -5
  18. package/esm/schema-builder.js.map +1 -1
  19. package/esm/types.d.ts +14 -4
  20. package/esm/types.d.ts.map +1 -1
  21. package/esm/types.js.map +1 -1
  22. package/esm/utils/config.js +1 -1
  23. package/esm/utils/config.js.map +1 -1
  24. package/esm/utils/cursors.js +4 -5
  25. package/esm/utils/cursors.js.map +1 -1
  26. package/esm/utils/loader-map.js +1 -1
  27. package/esm/utils/loader-map.js.map +1 -1
  28. package/esm/utils/map-query.d.ts.map +1 -1
  29. package/esm/utils/map-query.js +56 -31
  30. package/esm/utils/map-query.js.map +1 -1
  31. package/esm/utils/selections.d.ts.map +1 -1
  32. package/esm/utils/selections.js +4 -2
  33. package/esm/utils/selections.js.map +1 -1
  34. package/lib/connection-helpers.js +3 -4
  35. package/lib/connection-helpers.js.map +1 -1
  36. package/lib/drizzle-field-builder.js +10 -11
  37. package/lib/drizzle-field-builder.js.map +1 -1
  38. package/lib/index.js +10 -3
  39. package/lib/index.js.map +1 -1
  40. package/lib/schema-builder.js +5 -5
  41. package/lib/schema-builder.js.map +1 -1
  42. package/lib/types.js.map +1 -1
  43. package/lib/utils/config.js +1 -1
  44. package/lib/utils/config.js.map +1 -1
  45. package/lib/utils/cursors.js +4 -5
  46. package/lib/utils/cursors.js.map +1 -1
  47. package/lib/utils/loader-map.js +1 -1
  48. package/lib/utils/loader-map.js.map +1 -1
  49. package/lib/utils/map-query.js +55 -30
  50. package/lib/utils/map-query.js.map +1 -1
  51. package/lib/utils/selections.js +4 -2
  52. package/lib/utils/selections.js.map +1 -1
  53. package/package.json +6 -6
  54. package/src/drizzle-field-builder.ts +32 -6
  55. package/src/index.ts +17 -8
  56. package/src/types.ts +48 -25
  57. package/src/utils/map-query.ts +73 -5
  58. package/src/utils/selections.ts +4 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pothos/plugin-drizzle",
3
- "version": "0.16.2",
3
+ "version": "0.17.1",
4
4
  "description": "A Pothos plugin for drizzle",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./dts/index.d.ts",
@@ -39,20 +39,20 @@
39
39
  "graphql": "^16.10.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@libsql/client": "^0.15.15",
42
+ "@libsql/client": "^0.17.2",
43
43
  "drizzle-graphql": "^0.8.5",
44
44
  "drizzle-kit": "1.0.0-beta.10-42c284e",
45
45
  "drizzle-orm": "1.0.0-beta.10-42c284e",
46
46
  "graphql-scalars": "^1.25.0",
47
47
  "graphql-tag": "^2.12.6",
48
- "postgres": "^3.4.7",
48
+ "postgres": "^3.4.9",
49
+ "@pothos/core": "4.12.0",
49
50
  "@pothos/plugin-add-graphql": "4.3.0",
50
51
  "@pothos/plugin-errors": "4.9.0",
51
- "@pothos/plugin-relay": "4.6.2",
52
+ "@pothos/plugin-relay": "4.7.0",
52
53
  "@pothos/plugin-scope-auth": "4.1.6",
53
54
  "@pothos/plugin-with-input": "4.1.4",
54
- "@pothos/test-utils": "2.1.3",
55
- "@pothos/core": "4.12.0"
55
+ "@pothos/test-utils": "2.1.3"
56
56
  },
57
57
  "scripts": {
58
58
  "type": "tsc --project tsconfig.type.json",
@@ -41,6 +41,7 @@ import type { DrizzleRef } from './interface-ref';
41
41
  import type {
42
42
  DrizzleConnectionShape,
43
43
  ListRelation,
44
+ PathInfo,
44
45
  RelatedConnectionOptions,
45
46
  RelatedCountOptions,
46
47
  RelatedFieldOptions,
@@ -219,9 +220,23 @@ export class DrizzleObjectFieldBuilder<
219
220
  )!;
220
221
  };
221
222
 
222
- const getQuery = (args: PothosSchemaTypes.DefaultConnectionArguments, ctx: {}) => {
223
- const { limit, orderBy, where, ...fieldQuery } =
224
- (typeof query === 'function' ? query(args, ctx) : query) ?? {};
223
+ const getQuery = (
224
+ args: PothosSchemaTypes.DefaultConnectionArguments,
225
+ ctx: {},
226
+ pathInfo?: import('./types').PathInfo,
227
+ ) => {
228
+ const { limit, orderBy, where, ...fieldQuery } = ((typeof query === 'function'
229
+ ? (query as (args: {}, ctx: {}, pathInfo?: import('./types').PathInfo) => {})(
230
+ args,
231
+ ctx,
232
+ pathInfo,
233
+ )
234
+ : query) ?? {}) as {
235
+ limit?: number;
236
+ orderBy?: unknown;
237
+ where?: SQL;
238
+ columns?: Record<string, boolean>;
239
+ };
225
240
 
226
241
  const { cursorColumns, columns, ...connectionQuery } = drizzleCursorConnectionQuery({
227
242
  ctx,
@@ -255,6 +270,7 @@ export class DrizzleObjectFieldBuilder<
255
270
  context: object,
256
271
  nestedQuery: (query: unknown, path?: unknown) => { select?: object },
257
272
  getSelection: (path: string[]) => FieldNode | null,
273
+ pathInfo: import('./types').PathInfo,
258
274
  ) => {
259
275
  typeName ??= this.builder.configStore.getTypeConfig(ref).name;
260
276
 
@@ -279,7 +295,7 @@ export class DrizzleObjectFieldBuilder<
279
295
  };
280
296
  }
281
297
 
282
- const nested = nestedQuery(getQuery(args, context).select, {
298
+ const nested = nestedQuery(getQuery(args, context, pathInfo).select, {
283
299
  getType: () => typeName!,
284
300
  paths: [[{ name: 'nodes' }], [{ name: 'edges' }, { name: 'node' }]],
285
301
  }) as SelectionMap;
@@ -500,14 +516,24 @@ export class DrizzleObjectFieldBuilder<
500
516
 
501
517
  const { query = {}, extensions, ...rest } = options;
502
518
 
503
- const relationSelect = (args: object, context: object, nestedQuery: (query: unknown) => {}) => {
519
+ const relationSelect = (
520
+ args: object,
521
+ context: object,
522
+ nestedQuery: (query: unknown) => {},
523
+ _resolveSelection: unknown,
524
+ pathInfo: PathInfo,
525
+ ) => {
504
526
  const relQuery = {
505
527
  columns: {},
506
528
  with: {
507
529
  [name]: {
508
530
  ...nestedQuery(query),
509
531
  ...((typeof query === 'function'
510
- ? (query as (args: {}, context: {}) => {})(args, context)
532
+ ? (query as (args: {}, context: {}, pathInfo: PathInfo) => {})(
533
+ args,
534
+ context,
535
+ pathInfo,
536
+ )
511
537
  : query) as {}),
512
538
  },
513
539
  },
package/src/index.ts CHANGED
@@ -121,14 +121,23 @@ export class PothosDrizzlePlugin<Types extends SchemaTypes> extends BasePlugin<T
121
121
  args: {},
122
122
  ctx: Types['Context'],
123
123
  nestedQuery: (query: unknown, path?: string[]) => never,
124
- ) => ({
125
- columns: {},
126
- ...(select as (args: unknown, ctx: unknown, nestedQuery: unknown) => {})(
127
- args,
128
- ctx,
129
- nestedQuery,
130
- ),
131
- })
124
+ _resolveSelection: unknown,
125
+ pathInfo: import('./types').PathInfo,
126
+ ) => {
127
+ // Attach PathInfo properties to nestedQuery for t.field select callbacks
128
+ const nestedQueryWithPath = Object.assign(nestedQuery, {
129
+ path: pathInfo.path,
130
+ segments: pathInfo.segments,
131
+ });
132
+ return {
133
+ columns: {},
134
+ ...(select as (args: unknown, ctx: unknown, nestedQuery: unknown) => {})(
135
+ args,
136
+ ctx,
137
+ nestedQueryWithPath,
138
+ ),
139
+ };
140
+ }
132
141
  : {
133
142
  columns: {},
134
143
  ...select,
package/src/types.ts CHANGED
@@ -44,6 +44,18 @@ import type { DrizzleRef } from './interface-ref';
44
44
  import type { IndirectInclude } from './utils/map-query';
45
45
  import type { SelectionMap } from './utils/selections';
46
46
 
47
+ export interface FieldPathInfo {
48
+ field: string;
49
+ alias: string;
50
+ parentType: string;
51
+ isList: boolean;
52
+ }
53
+
54
+ export interface PathInfo {
55
+ path: string[];
56
+ segments: FieldPathInfo[];
57
+ }
58
+
47
59
  export type DrizzleClient<TCountSource = Table | SQL | SQLWrapper> = {
48
60
  readonly _: {
49
61
  readonly schema: unknown;
@@ -323,10 +335,11 @@ export type DrizzleObjectFieldOptions<
323
335
  | ((
324
336
  args: InputShapeFromFields<Args>,
325
337
  ctx: Types['Context'],
326
- nestedSelection: <Selection extends boolean | {}>(
338
+ nestedSelection: (<Selection extends boolean | {}>(
327
339
  selection?: Selection,
328
340
  path?: string[],
329
- ) => Selection,
341
+ ) => Selection) &
342
+ PathInfo,
330
343
  ) => DBQueryConfig<'one', Types['DrizzleRelations'], ExtractTable<Types, ParentShape>>)
331
344
  );
332
345
  };
@@ -345,6 +358,7 @@ export type DrizzleFieldSelection =
345
358
  type?: string,
346
359
  ) => DBQueryConfig<'one'> | boolean,
347
360
  resolveSelection: (path: string[]) => FieldNode | null,
361
+ pathInfo: PathInfo,
348
362
  ) => SelectionMap);
349
363
 
350
364
  export type ExtractTable<Types extends SchemaTypes, Shape> = Shape extends {
@@ -480,7 +494,13 @@ export type QueryForField<
480
494
  'columns' | 'extra' | 'with'
481
495
  >
482
496
  ) extends infer QueryConfig
483
- ? QueryConfig | ((args: InputShapeFromFields<Args>, context: Types['Context']) => QueryConfig)
497
+ ?
498
+ | QueryConfig
499
+ | ((
500
+ args: InputShapeFromFields<Args>,
501
+ context: Types['Context'],
502
+ pathInfo: PathInfo,
503
+ ) => QueryConfig)
484
504
  : never;
485
505
 
486
506
  export type QueryForDrizzleField<
@@ -503,7 +523,7 @@ export type QueryForRelatedConnection<
503
523
  > & {
504
524
  orderBy?: ConnectionOrderBy<Table> | ((table: Table) => ConnectionOrderBy<Table>);
505
525
  } extends infer QueryConfig
506
- ? QueryConfig | ((args: Args, context: Types['Context']) => QueryConfig)
526
+ ? QueryConfig | ((args: Args, context: Types['Context'], pathInfo: PathInfo) => QueryConfig)
507
527
  : never;
508
528
 
509
529
  export type QueryForDrizzleConnection<
@@ -674,28 +694,31 @@ export type DrizzleConnectionShape<
674
694
  T,
675
695
  Parent,
676
696
  Args extends InputFieldMap,
677
- > = Merge<
678
- ShapeFromConnection<PothosSchemaTypes.ConnectionShapeHelper<Types, T, false>> extends infer Shape
679
- ? Shape & {
680
- parent: Parent;
681
- args: InputShapeFromFields<Args> & PothosSchemaTypes.DefaultConnectionArguments;
682
- }
683
- : never
684
- > extends infer C
685
- ? [C] extends [
686
- {
687
- edges: infer Edges;
688
- },
689
- ]
690
- ? Merge<
691
- Omit<C, 'edges'> & {
692
- edges: Edges extends Iterable<MaybePromise<infer Edge> | null | undefined>
693
- ? Merge<Edge & { connection: C }>[]
694
- : never;
697
+ > =
698
+ Merge<
699
+ ShapeFromConnection<
700
+ PothosSchemaTypes.ConnectionShapeHelper<Types, T, false>
701
+ > extends infer Shape
702
+ ? Shape & {
703
+ parent: Parent;
704
+ args: InputShapeFromFields<Args> & PothosSchemaTypes.DefaultConnectionArguments;
695
705
  }
696
- >
697
- : C
698
- : never;
706
+ : never
707
+ > extends infer C
708
+ ? [C] extends [
709
+ {
710
+ edges: infer Edges;
711
+ },
712
+ ]
713
+ ? Merge<
714
+ Omit<C, 'edges'> & {
715
+ edges: Edges extends Iterable<MaybePromise<infer Edge> | null | undefined>
716
+ ? Merge<Edge & { connection: C }>[]
717
+ : never;
718
+ }
719
+ >
720
+ : C
721
+ : never;
699
722
 
700
723
  export type WithBrand<T> = T & { [typeBrandKey]: string };
701
724
 
@@ -15,11 +15,12 @@ import {
15
15
  getNamedType,
16
16
  type InlineFragmentNode,
17
17
  isInterfaceType,
18
+ isListType,
18
19
  isObjectType,
19
20
  Kind,
20
21
  type SelectionSetNode,
21
22
  } from 'graphql';
22
- import type { DrizzleFieldSelection } from '../types';
23
+ import type { DrizzleFieldSelection, FieldPathInfo, PathInfo } from '../types';
23
24
  import type { PothosDrizzleSchemaConfig } from './config';
24
25
  import { type LoaderMappings, setLoaderMappings } from './loader-map';
25
26
  import {
@@ -47,6 +48,7 @@ function addTypeSelectionsForField(
47
48
  selection: FieldNode,
48
49
  indirectPath: string[],
49
50
  deferred?: boolean,
51
+ segments: FieldPathInfo[] = [],
50
52
  ) {
51
53
  if (selection.name.value.startsWith('__')) {
52
54
  return;
@@ -78,6 +80,7 @@ function addTypeSelectionsForField(
78
80
  field,
79
81
  path,
80
82
  deferred,
83
+ segments,
81
84
  );
82
85
  },
83
86
  deferred,
@@ -92,6 +95,7 @@ function addTypeSelectionsForField(
92
95
  selection,
93
96
  indirectPath,
94
97
  deferred,
98
+ segments,
95
99
  );
96
100
  return;
97
101
  }
@@ -105,7 +109,16 @@ function addTypeSelectionsForField(
105
109
  }
106
110
 
107
111
  if (selection.selectionSet && (!deferred || !state.skipDeferredFragments)) {
108
- addNestedSelections(config, type, context, info, state, selection.selectionSet, indirectPath);
112
+ addNestedSelections(
113
+ config,
114
+ type,
115
+ context,
116
+ info,
117
+ state,
118
+ selection.selectionSet,
119
+ indirectPath,
120
+ segments,
121
+ );
109
122
  }
110
123
  }
111
124
 
@@ -225,12 +238,13 @@ function addNestedSelections(
225
238
  state: SelectionState,
226
239
  selections: SelectionSetNode,
227
240
  indirectPath: string[],
241
+ segments: FieldPathInfo[] = [],
228
242
  ) {
229
243
  let parentType = type;
230
244
  for (const selection of selections.selections) {
231
245
  switch (selection.kind) {
232
246
  case Kind.FIELD:
233
- addFieldSelection(config, type, context, info, state, selection, indirectPath);
247
+ addFieldSelection(config, type, context, info, state, selection, indirectPath, segments);
234
248
 
235
249
  continue;
236
250
  case Kind.FRAGMENT_SPREAD:
@@ -257,6 +271,7 @@ function addNestedSelections(
257
271
  state,
258
272
  info.fragments[selection.name.value].selectionSet,
259
273
  indirectPath,
274
+ segments,
260
275
  );
261
276
 
262
277
  continue;
@@ -285,6 +300,7 @@ function addNestedSelections(
285
300
  state,
286
301
  selection.selectionSet,
287
302
  indirectPath,
303
+ segments,
288
304
  );
289
305
 
290
306
  continue;
@@ -305,6 +321,7 @@ function addFieldSelection(
305
321
  state: SelectionState,
306
322
  selection: FieldNode,
307
323
  indirectPath: string[],
324
+ segments: FieldPathInfo[] = [],
308
325
  ) {
309
326
  if (selection.name.value.startsWith('__') || fieldSkipped(info, selection)) {
310
327
  return;
@@ -314,11 +331,26 @@ function addFieldSelection(
314
331
  throw new PothosValidationError(`Unknown field ${selection.name.value} on ${type.name}`);
315
332
  }
316
333
 
334
+ const allSegments = [
335
+ ...segments,
336
+ {
337
+ field: selection.name.value,
338
+ alias: selection.alias?.value ?? selection.name.value,
339
+ parentType: type.name,
340
+ isList: isListType(field.type) || isListType(getNamedType(field.type)),
341
+ },
342
+ ];
343
+
317
344
  const fieldSelect = field.extensions?.pothosDrizzleSelect as DrizzleFieldSelection | undefined;
318
345
 
319
346
  let fieldSelectionMap: DBQueryConfig<'one'> | undefined;
320
347
  let mappings: LoaderMappings = {};
321
348
  if (typeof fieldSelect === 'function') {
349
+ const pathInfo: PathInfo = {
350
+ path: allSegments.map((s) => `${s.parentType}.${s.field}`),
351
+ segments: allSegments,
352
+ };
353
+
322
354
  const args = getMappedArgumentValues(field, selection, context, info) as Record<
323
355
  string,
324
356
  unknown
@@ -369,11 +401,22 @@ function addFieldSelection(
369
401
  resolvedField,
370
402
  path,
371
403
  deferred,
404
+ allSegments,
372
405
  );
373
406
  },
374
407
  );
375
408
  }
376
- addTypeSelectionsForField(config, returnType, context, info, fieldState, selection, []);
409
+ addTypeSelectionsForField(
410
+ config,
411
+ returnType,
412
+ context,
413
+ info,
414
+ fieldState,
415
+ selection,
416
+ [],
417
+ undefined,
418
+ allSegments,
419
+ );
377
420
  mappings = fieldState.mappings;
378
421
  return selectionToQuery(config, fieldState);
379
422
  },
@@ -394,6 +437,7 @@ function addFieldSelection(
394
437
  );
395
438
  return node;
396
439
  },
440
+ pathInfo,
397
441
  );
398
442
  } else {
399
443
  fieldSelectionMap = fieldSelect!;
@@ -522,7 +566,31 @@ export function stateFromInfo<T extends SelectionMap>({
522
566
  } else {
523
567
  state = createStateForSelection(config, info, type, undefined, initialSelection);
524
568
 
525
- addTypeSelectionsForField(config, type, context, info, state, info.fieldNodes[0], []);
569
+ // Create initial segment for the root query field
570
+ const rootFieldNode = info.fieldNodes[0];
571
+ const rootField = info.parentType.getFields()[rootFieldNode.name.value];
572
+ const initialSegments: FieldPathInfo[] = rootField
573
+ ? [
574
+ {
575
+ field: rootFieldNode.name.value,
576
+ alias: rootFieldNode.alias?.value ?? rootFieldNode.name.value,
577
+ parentType: info.parentType.name,
578
+ isList: isListType(rootField.type) || isListType(getNamedType(rootField.type)),
579
+ },
580
+ ]
581
+ : [];
582
+
583
+ addTypeSelectionsForField(
584
+ config,
585
+ type,
586
+ context,
587
+ info,
588
+ state,
589
+ info.fieldNodes[0],
590
+ [],
591
+ undefined,
592
+ initialSegments,
593
+ );
526
594
  }
527
595
 
528
596
  if (!state) {
@@ -149,8 +149,10 @@ export function mergeSelection(
149
149
  }
150
150
 
151
151
  if (columns && !state.allColumns) {
152
- for (const key of Object.keys(columns)) {
153
- state.columns.add(key);
152
+ for (const [key, value] of Object.entries(columns)) {
153
+ if (value) {
154
+ state.columns.add(key);
155
+ }
154
156
  }
155
157
  } else {
156
158
  state.allColumns = true;