@pothos/plugin-drizzle 0.17.6 → 0.18.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.
- package/CHANGELOG.md +39 -0
- package/dts/connection-helpers.d.ts.map +1 -1
- package/dts/drizzle-field-builder.d.ts.map +1 -1
- package/dts/types.d.ts +6 -2
- package/dts/types.d.ts.map +1 -1
- package/dts/utils/config.d.ts +3 -0
- package/dts/utils/config.d.ts.map +1 -1
- package/dts/utils/cursors.d.ts +11 -7
- package/dts/utils/cursors.d.ts.map +1 -1
- package/dts/utils/map-query.d.ts.map +1 -1
- package/esm/connection-helpers.d.ts.map +1 -1
- package/esm/connection-helpers.js +5 -4
- package/esm/connection-helpers.js.map +1 -1
- package/esm/drizzle-field-builder.d.ts.map +1 -1
- package/esm/drizzle-field-builder.js +5 -4
- package/esm/drizzle-field-builder.js.map +1 -1
- package/esm/types.d.ts +6 -2
- package/esm/types.d.ts.map +1 -1
- package/esm/types.js +1 -0
- package/esm/types.js.map +1 -1
- package/esm/utils/config.d.ts +3 -0
- package/esm/utils/config.d.ts.map +1 -1
- package/esm/utils/config.js +95 -17
- package/esm/utils/config.js.map +1 -1
- package/esm/utils/cursors.d.ts +11 -7
- package/esm/utils/cursors.d.ts.map +1 -1
- package/esm/utils/cursors.js +194 -113
- package/esm/utils/cursors.js.map +1 -1
- package/esm/utils/map-query.d.ts.map +1 -1
- package/esm/utils/map-query.js +24 -6
- package/esm/utils/map-query.js.map +1 -1
- package/lib/connection-helpers.js +5 -4
- package/lib/connection-helpers.js.map +1 -1
- package/lib/drizzle-field-builder.js +5 -4
- package/lib/drizzle-field-builder.js.map +1 -1
- package/lib/types.js +4 -0
- package/lib/types.js.map +1 -1
- package/lib/utils/config.js +95 -17
- package/lib/utils/config.js.map +1 -1
- package/lib/utils/cursors.js +196 -112
- package/lib/utils/cursors.js.map +1 -1
- package/lib/utils/map-query.js +24 -6
- package/lib/utils/map-query.js.map +1 -1
- package/package.json +4 -4
- package/src/connection-helpers.ts +6 -4
- package/src/drizzle-field-builder.ts +7 -4
- package/src/types.ts +9 -4
- package/src/utils/config.ts +117 -20
- package/src/utils/cursors.ts +248 -87
- package/src/utils/map-query.ts +41 -15
|
@@ -10,6 +10,7 @@ import type { DrizzleRef } from './interface-ref.js';
|
|
|
10
10
|
import type { QueryForDrizzleConnection } from './types.js';
|
|
11
11
|
import { getSchemaConfig } from './utils/config.js';
|
|
12
12
|
import {
|
|
13
|
+
type DrizzleCursorConnectionQueryOptions,
|
|
13
14
|
drizzleCursorConnectionQuery,
|
|
14
15
|
getCursorFormatter,
|
|
15
16
|
wrapConnectionResult,
|
|
@@ -93,8 +94,8 @@ export function drizzleConnectionHelpers<
|
|
|
93
94
|
ctx: Types['Context'],
|
|
94
95
|
parent?: Parent,
|
|
95
96
|
) {
|
|
96
|
-
const { select,
|
|
97
|
-
const formatCursor = getCursorFormatter(
|
|
97
|
+
const { select, cursorFields } = getQueryArgs(args, ctx);
|
|
98
|
+
const formatCursor = getCursorFormatter(cursorFields, config);
|
|
98
99
|
return wrapConnectionResult(
|
|
99
100
|
list,
|
|
100
101
|
args,
|
|
@@ -122,7 +123,7 @@ export function drizzleConnectionHelpers<
|
|
|
122
123
|
(typeof query === 'function' ? query(args, ctx) : query) ?? {};
|
|
123
124
|
const table = config.relations[tableName];
|
|
124
125
|
|
|
125
|
-
const {
|
|
126
|
+
const { cursorFields, columns, ...connectionQuery } = drizzleCursorConnectionQuery({
|
|
126
127
|
ctx,
|
|
127
128
|
maxSize,
|
|
128
129
|
defaultSize: typeof defaultSize === 'function' ? defaultSize(args, ctx) : defaultSize,
|
|
@@ -130,6 +131,7 @@ export function drizzleConnectionHelpers<
|
|
|
130
131
|
orderBy:
|
|
131
132
|
(typeof orderBy === 'function' ? orderBy(table) : orderBy) ??
|
|
132
133
|
getSchemaConfig(builder).getPrimaryKey(tableName),
|
|
134
|
+
extras: (fieldQuery as { extras?: DrizzleCursorConnectionQueryOptions['extras'] }).extras,
|
|
133
135
|
where,
|
|
134
136
|
config,
|
|
135
137
|
table,
|
|
@@ -145,7 +147,7 @@ export function drizzleConnectionHelpers<
|
|
|
145
147
|
},
|
|
146
148
|
limit: Math.abs(limit ?? connectionQuery.limit),
|
|
147
149
|
},
|
|
148
|
-
|
|
150
|
+
cursorFields,
|
|
149
151
|
};
|
|
150
152
|
};
|
|
151
153
|
|
|
@@ -51,6 +51,7 @@ import type {
|
|
|
51
51
|
} from './types.js';
|
|
52
52
|
import { getClient, getSchemaConfig } from './utils/config.js';
|
|
53
53
|
import {
|
|
54
|
+
type DrizzleCursorConnectionQueryOptions,
|
|
54
55
|
drizzleCursorConnectionQuery,
|
|
55
56
|
getCursorFormatter,
|
|
56
57
|
wrapConnectionResult,
|
|
@@ -236,9 +237,10 @@ export class DrizzleObjectFieldBuilder<
|
|
|
236
237
|
orderBy?: unknown;
|
|
237
238
|
where?: SQL;
|
|
238
239
|
columns?: Record<string, boolean>;
|
|
240
|
+
extras?: DrizzleCursorConnectionQueryOptions['extras'];
|
|
239
241
|
};
|
|
240
242
|
|
|
241
|
-
const {
|
|
243
|
+
const { cursorFields, columns, ...connectionQuery } = drizzleCursorConnectionQuery({
|
|
242
244
|
ctx,
|
|
243
245
|
maxSize,
|
|
244
246
|
defaultSize,
|
|
@@ -246,6 +248,7 @@ export class DrizzleObjectFieldBuilder<
|
|
|
246
248
|
orderBy:
|
|
247
249
|
(typeof orderBy === 'function' ? orderBy(relatedTable.table) : orderBy) ??
|
|
248
250
|
getSchemaConfig(this.builder).getPrimaryKey(relationField.targetTableName),
|
|
251
|
+
extras: fieldQuery.extras,
|
|
249
252
|
where,
|
|
250
253
|
config: schemaConfig,
|
|
251
254
|
table: relatedTable,
|
|
@@ -261,7 +264,7 @@ export class DrizzleObjectFieldBuilder<
|
|
|
261
264
|
},
|
|
262
265
|
limit: Math.abs(limit ?? connectionQuery.limit),
|
|
263
266
|
},
|
|
264
|
-
|
|
267
|
+
cursorFields,
|
|
265
268
|
};
|
|
266
269
|
};
|
|
267
270
|
|
|
@@ -376,13 +379,13 @@ export class DrizzleObjectFieldBuilder<
|
|
|
376
379
|
};
|
|
377
380
|
}
|
|
378
381
|
|
|
379
|
-
const { select,
|
|
382
|
+
const { select, cursorFields } = getQuery(args, context);
|
|
380
383
|
|
|
381
384
|
return wrapConnectionResult(
|
|
382
385
|
parentRecord[name] as readonly {}[],
|
|
383
386
|
args,
|
|
384
387
|
select.limit,
|
|
385
|
-
getCursorFormatter(
|
|
388
|
+
getCursorFormatter(cursorFields, schemaConfig),
|
|
386
389
|
undefined,
|
|
387
390
|
parent,
|
|
388
391
|
countValue,
|
package/src/types.ts
CHANGED
|
@@ -68,6 +68,9 @@ type GetTableConfigFn<TTable = Table> = (table: TTable) => {
|
|
|
68
68
|
primaryKeys: {
|
|
69
69
|
readonly columns: Column[];
|
|
70
70
|
}[];
|
|
71
|
+
uniqueConstraints?: {
|
|
72
|
+
readonly columns: Column[];
|
|
73
|
+
}[];
|
|
71
74
|
readonly columns: Column[];
|
|
72
75
|
};
|
|
73
76
|
|
|
@@ -677,11 +680,12 @@ export type RelatedConnectionOptions<
|
|
|
677
680
|
export type ConnectionOrderBy<T extends TableRelationalConfig> =
|
|
678
681
|
| Column
|
|
679
682
|
| Column[]
|
|
683
|
+
// keys name a column, or an extra the same query selects. `string & {}` keeps
|
|
684
|
+
// the column names in autocomplete while letting extra names through
|
|
680
685
|
| {
|
|
681
|
-
[K in
|
|
682
|
-
| '
|
|
683
|
-
| 'desc'
|
|
684
|
-
| undefined;
|
|
686
|
+
[K in
|
|
687
|
+
| (T['table']['_'] extends { columns: infer Columns } ? keyof Columns : never)
|
|
688
|
+
| (string & {})]?: 'asc' | 'desc' | undefined;
|
|
685
689
|
};
|
|
686
690
|
|
|
687
691
|
export type ShapeFromConnection<T> = T extends { shape: unknown } ? T['shape'] : never;
|
|
@@ -736,4 +740,5 @@ export interface DrizzleGraphQLInputExtensions {
|
|
|
736
740
|
inputType: 'insert' | 'filters' | 'orderBy' | 'update';
|
|
737
741
|
}
|
|
738
742
|
|
|
743
|
+
export { DrizzleInterfaceRef, type DrizzleRef } from './interface-ref.js';
|
|
739
744
|
export { DrizzleObjectRef } from './object-ref.js';
|
package/src/utils/config.ts
CHANGED
|
@@ -5,7 +5,10 @@ import type { DrizzleClient } from '../types.js';
|
|
|
5
5
|
export interface PothosDrizzleSchemaConfig {
|
|
6
6
|
skipDeferredFragments: boolean;
|
|
7
7
|
relations: AnyRelations;
|
|
8
|
+
findPrimaryKey: (tableName: string) => Column[] | null;
|
|
9
|
+
findTieBreaker: (tableName: string) => Column[] | null;
|
|
8
10
|
getPrimaryKey: (tableName: string) => Column[];
|
|
11
|
+
getUniqueConstraints: (tableName: string) => Column[][];
|
|
9
12
|
columnToTsName: (column: Column) => string;
|
|
10
13
|
}
|
|
11
14
|
const configCache = createContextCache(
|
|
@@ -27,6 +30,113 @@ const configCache = createContextCache(
|
|
|
27
30
|
}
|
|
28
31
|
});
|
|
29
32
|
|
|
33
|
+
const buildTableConfig = (tableName: string) => {
|
|
34
|
+
const table = relations[tableName].table as Table;
|
|
35
|
+
const tableConfig = builder.options.drizzle.getTableConfig(table);
|
|
36
|
+
const tableColumns = Object.values(getColumns(table));
|
|
37
|
+
|
|
38
|
+
// The pg dialect builds primaryKeys and uniqueConstraints from
|
|
39
|
+
// ExtraConfigColumns rather than the table's own columns, so the objects
|
|
40
|
+
// it hands back are not the ones columnNameMappings knows about, and do
|
|
41
|
+
// not carry notNull. Look each one back up by name.
|
|
42
|
+
const toTableColumn = (column: Column) =>
|
|
43
|
+
tableColumns.find((candidate) => candidate.name === column.name) ?? column;
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
columns: tableConfig.columns.map(toTableColumn),
|
|
47
|
+
primaryKeys: tableConfig.primaryKeys.map((key) => key.columns.map(toTableColumn)),
|
|
48
|
+
uniqueConstraints: (tableConfig.uniqueConstraints ?? []).map((constraint) =>
|
|
49
|
+
constraint.columns.map(toTableColumn),
|
|
50
|
+
),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const tableConfigs = new Map<string, ReturnType<typeof buildTableConfig>>();
|
|
55
|
+
|
|
56
|
+
// drizzle rebuilds this from the table's config callback on every call
|
|
57
|
+
const getTableConfig = (tableName: string) => {
|
|
58
|
+
let tableConfig = tableConfigs.get(tableName);
|
|
59
|
+
|
|
60
|
+
if (!tableConfig) {
|
|
61
|
+
tableConfig = buildTableConfig(tableName);
|
|
62
|
+
tableConfigs.set(tableName, tableConfig);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return tableConfig;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Every set of columns the database guarantees is unique. Unique indexes
|
|
69
|
+
// are not included: missing one only costs a redundant order column, while
|
|
70
|
+
// wrongly reporting a set as unique would break pagination.
|
|
71
|
+
const getUniqueConstraints = (tableName: string) => {
|
|
72
|
+
const tableConfig = getTableConfig(tableName);
|
|
73
|
+
|
|
74
|
+
return [
|
|
75
|
+
...tableConfig.columns
|
|
76
|
+
.filter((column) => column.primary || column.isUnique)
|
|
77
|
+
.map((column) => [column]),
|
|
78
|
+
...tableConfig.primaryKeys,
|
|
79
|
+
...tableConfig.uniqueConstraints,
|
|
80
|
+
].filter((columns) => columns.length > 0);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// What a cursor can rely on to break ties. Primary key columns are
|
|
84
|
+
// non-nullable whatever the drizzle schema says, because SQL requires it,
|
|
85
|
+
// so a composite key declared without notNull() on each column still
|
|
86
|
+
// counts. A column that is only unique has to say so itself: comparing a
|
|
87
|
+
// cursor against null matches nothing, and rows sharing a null tie anyway.
|
|
88
|
+
const findTieBreaker = (tableName: string) => {
|
|
89
|
+
const tableConfig = getTableConfig(tableName);
|
|
90
|
+
|
|
91
|
+
const primaryKey = tableConfig.columns.find((column) => column.primary);
|
|
92
|
+
|
|
93
|
+
if (primaryKey) {
|
|
94
|
+
return [primaryKey];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const compositeKey = tableConfig.primaryKeys.find((columns) => columns.length > 0);
|
|
98
|
+
|
|
99
|
+
if (compositeKey) {
|
|
100
|
+
return compositeKey;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const uniqueColumn = tableConfig.columns.find((column) => column.isUnique && column.notNull);
|
|
104
|
+
|
|
105
|
+
if (uniqueColumn) {
|
|
106
|
+
return [uniqueColumn];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const uniqueConstraint = tableConfig.uniqueConstraints.find(
|
|
110
|
+
(columns) => columns.length > 0 && columns.every((column) => column.notNull),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return uniqueConstraint ?? null;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const findPrimaryKey = (tableName: string) => {
|
|
117
|
+
const tableConfig = getTableConfig(tableName);
|
|
118
|
+
|
|
119
|
+
const primaryKey = tableConfig.columns.find((column) => column.primary);
|
|
120
|
+
|
|
121
|
+
if (primaryKey) {
|
|
122
|
+
return [primaryKey];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const primaryKeys = tableConfig.primaryKeys.find((columns) => columns.length > 0);
|
|
126
|
+
|
|
127
|
+
if (primaryKeys) {
|
|
128
|
+
return primaryKeys;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const uniqueColumn = tableConfig.columns.find((column) => column.isUnique);
|
|
132
|
+
|
|
133
|
+
if (uniqueColumn) {
|
|
134
|
+
return [uniqueColumn];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return null;
|
|
138
|
+
};
|
|
139
|
+
|
|
30
140
|
return {
|
|
31
141
|
skipDeferredFragments: builder.options.drizzle.skipDeferredFragments ?? true,
|
|
32
142
|
columnToTsName: (column) => {
|
|
@@ -38,30 +148,17 @@ const configCache = createContextCache(
|
|
|
38
148
|
|
|
39
149
|
return tsName;
|
|
40
150
|
},
|
|
151
|
+
findPrimaryKey,
|
|
152
|
+
findTieBreaker,
|
|
153
|
+
getUniqueConstraints,
|
|
41
154
|
getPrimaryKey: (tableName) => {
|
|
42
|
-
const
|
|
43
|
-
relations[tableName].table as Table,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const primaryKey = tableConfig.columns.find((column) => column.primary);
|
|
47
|
-
|
|
48
|
-
if (primaryKey) {
|
|
49
|
-
return [primaryKey];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const primaryKeys = tableConfig.primaryKeys.find((key) => key.columns.length > 0);
|
|
53
|
-
|
|
54
|
-
if (primaryKeys) {
|
|
55
|
-
return primaryKeys.columns;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const uniqueColumn = tableConfig.columns.find((column) => column.isUnique);
|
|
155
|
+
const primaryKey = findPrimaryKey(tableName);
|
|
59
156
|
|
|
60
|
-
if (
|
|
61
|
-
|
|
157
|
+
if (!primaryKey) {
|
|
158
|
+
throw new Error(`Could not find primary key for table ${tableName}`);
|
|
62
159
|
}
|
|
63
160
|
|
|
64
|
-
|
|
161
|
+
return primaryKey;
|
|
65
162
|
},
|
|
66
163
|
relations,
|
|
67
164
|
};
|