@pothos/plugin-drizzle 0.18.1 → 0.19.0
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 +345 -0
- package/README.md +784 -221
- package/dts/connection-helpers.d.ts +18 -8
- package/dts/connection-helpers.d.ts.map +1 -1
- package/dts/drizzle-field-builder.d.ts +4 -11
- package/dts/drizzle-field-builder.d.ts.map +1 -1
- package/dts/global-types.d.ts.map +1 -1
- package/dts/index.d.ts.map +1 -1
- package/dts/model-loader.d.ts +18 -17
- package/dts/model-loader.d.ts.map +1 -1
- package/dts/types.d.ts +80 -20
- package/dts/types.d.ts.map +1 -1
- package/dts/utils/adapter.d.ts +39 -0
- package/dts/utils/adapter.d.ts.map +1 -0
- package/dts/utils/await-selections.d.ts +12 -0
- package/dts/utils/await-selections.d.ts.map +1 -0
- package/dts/utils/config.d.ts +23 -3
- package/dts/utils/config.d.ts.map +1 -1
- package/dts/utils/cursors.d.ts +6 -6
- package/dts/utils/cursors.d.ts.map +1 -1
- package/dts/utils/map-query.d.ts +22 -21
- package/dts/utils/map-query.d.ts.map +1 -1
- package/dts/utils/path-info.d.ts +13 -0
- package/dts/utils/path-info.d.ts.map +1 -0
- package/dts/utils/relation-filter.d.ts +48 -0
- package/dts/utils/relation-filter.d.ts.map +1 -0
- package/dts/utils/selections.d.ts +2 -21
- package/dts/utils/selections.d.ts.map +1 -1
- package/esm/connection-helpers.d.ts +18 -8
- package/esm/connection-helpers.d.ts.map +1 -1
- package/esm/connection-helpers.js +52 -19
- package/esm/connection-helpers.js.map +1 -1
- package/esm/drizzle-field-builder.d.ts +4 -11
- package/esm/drizzle-field-builder.d.ts.map +1 -1
- package/esm/drizzle-field-builder.js +138 -96
- package/esm/drizzle-field-builder.js.map +1 -1
- package/esm/field-builder.js +61 -47
- package/esm/field-builder.js.map +1 -1
- package/esm/global-types.d.ts.map +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +37 -61
- package/esm/index.js.map +1 -1
- package/esm/model-loader.d.ts +18 -17
- package/esm/model-loader.d.ts.map +1 -1
- package/esm/model-loader.js +76 -45
- package/esm/model-loader.js.map +1 -1
- package/esm/schema-builder.js +40 -149
- package/esm/schema-builder.js.map +1 -1
- package/esm/types.d.ts +80 -20
- package/esm/types.d.ts.map +1 -1
- package/esm/types.js.map +1 -1
- package/esm/utils/adapter.d.ts +39 -0
- package/esm/utils/adapter.d.ts.map +1 -0
- package/esm/utils/adapter.js +137 -0
- package/esm/utils/adapter.js.map +1 -0
- package/esm/utils/await-selections.d.ts +12 -0
- package/esm/utils/await-selections.d.ts.map +1 -0
- package/esm/utils/await-selections.js +19 -0
- package/esm/utils/await-selections.js.map +1 -0
- package/esm/utils/config.d.ts +23 -3
- package/esm/utils/config.d.ts.map +1 -1
- package/esm/utils/config.js +1 -4
- package/esm/utils/config.js.map +1 -1
- package/esm/utils/cursors.d.ts +6 -6
- package/esm/utils/cursors.d.ts.map +1 -1
- package/esm/utils/cursors.js +55 -90
- package/esm/utils/cursors.js.map +1 -1
- package/esm/utils/map-query.d.ts +22 -21
- package/esm/utils/map-query.d.ts.map +1 -1
- package/esm/utils/map-query.js +40 -354
- package/esm/utils/map-query.js.map +1 -1
- package/esm/utils/path-info.d.ts +13 -0
- package/esm/utils/path-info.d.ts.map +1 -0
- package/esm/utils/path-info.js +37 -0
- package/esm/utils/path-info.js.map +1 -0
- package/esm/utils/relation-filter.d.ts +48 -0
- package/esm/utils/relation-filter.d.ts.map +1 -0
- package/esm/utils/relation-filter.js +92 -0
- package/esm/utils/relation-filter.js.map +1 -0
- package/esm/utils/selections.d.ts +2 -21
- package/esm/utils/selections.d.ts.map +1 -1
- package/esm/utils/selections.js +1 -133
- package/esm/utils/selections.js.map +1 -1
- package/lib/connection-helpers.js +51 -18
- package/lib/connection-helpers.js.map +1 -1
- package/lib/drizzle-field-builder.js +136 -94
- package/lib/drizzle-field-builder.js.map +1 -1
- package/lib/field-builder.js +58 -44
- package/lib/field-builder.js.map +1 -1
- package/lib/index.js +36 -60
- package/lib/index.js.map +1 -1
- package/lib/model-loader.js +76 -45
- package/lib/model-loader.js.map +1 -1
- package/lib/schema-builder.js +40 -149
- package/lib/schema-builder.js.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils/adapter.js +147 -0
- package/lib/utils/adapter.js.map +1 -0
- package/lib/utils/await-selections.js +20 -0
- package/lib/utils/await-selections.js.map +1 -0
- package/lib/utils/config.js +1 -4
- package/lib/utils/config.js.map +1 -1
- package/lib/utils/cursors.js +47 -88
- package/lib/utils/cursors.js.map +1 -1
- package/lib/utils/map-query.js +28 -359
- package/lib/utils/map-query.js.map +1 -1
- package/lib/utils/path-info.js +39 -0
- package/lib/utils/path-info.js.map +1 -0
- package/lib/utils/relation-filter.js +91 -0
- package/lib/utils/relation-filter.js.map +1 -0
- package/lib/utils/selections.js +3 -158
- package/lib/utils/selections.js.map +1 -1
- package/package.json +8 -6
- package/src/connection-helpers.ts +167 -53
- package/src/drizzle-field-builder.ts +296 -176
- package/src/field-builder.ts +110 -77
- package/src/global-types.ts +0 -32
- package/src/index.ts +42 -68
- package/src/model-loader.ts +110 -71
- package/src/schema-builder.ts +76 -169
- package/src/types.ts +175 -44
- package/src/utils/adapter.ts +197 -0
- package/src/utils/await-selections.ts +31 -0
- package/src/utils/config.ts +1 -5
- package/src/utils/cursors.ts +53 -81
- package/src/utils/map-query.ts +51 -734
- package/src/utils/path-info.ts +40 -0
- package/src/utils/relation-filter.ts +185 -0
- package/src/utils/selections.ts +2 -207
- package/dts/utils/deep-equal.d.ts +0 -2
- package/dts/utils/deep-equal.d.ts.map +0 -1
- package/dts/utils/drizzle-graphql.d.ts +0 -2
- package/dts/utils/drizzle-graphql.d.ts.map +0 -1
- package/dts/utils/loader-map.d.ts +0 -11
- package/dts/utils/loader-map.d.ts.map +0 -1
- package/dts/utils/usage.d.ts +0 -5
- package/dts/utils/usage.d.ts.map +0 -1
- package/esm/utils/deep-equal.d.ts +0 -2
- package/esm/utils/deep-equal.d.ts.map +0 -1
- package/esm/utils/deep-equal.js +0 -45
- package/esm/utils/deep-equal.js.map +0 -1
- package/esm/utils/drizzle-graphql.d.ts +0 -2
- package/esm/utils/drizzle-graphql.d.ts.map +0 -1
- package/esm/utils/drizzle-graphql.js +0 -232
- package/esm/utils/drizzle-graphql.js.map +0 -1
- package/esm/utils/loader-map.d.ts +0 -11
- package/esm/utils/loader-map.d.ts.map +0 -1
- package/esm/utils/loader-map.js +0 -35
- package/esm/utils/loader-map.js.map +0 -1
- package/esm/utils/usage.d.ts +0 -5
- package/esm/utils/usage.d.ts.map +0 -1
- package/esm/utils/usage.js +0 -59
- package/esm/utils/usage.js.map +0 -1
- package/lib/utils/deep-equal.js +0 -55
- package/lib/utils/deep-equal.js.map +0 -1
- package/lib/utils/drizzle-graphql.js +0 -236
- package/lib/utils/drizzle-graphql.js.map +0 -1
- package/lib/utils/loader-map.js +0 -56
- package/lib/utils/loader-map.js.map +0 -1
- package/lib/utils/usage.js +0 -83
- package/lib/utils/usage.js.map +0 -1
- package/src/utils/deep-equal.ts +0 -57
- package/src/utils/drizzle-graphql.ts +0 -274
- package/src/utils/loader-map.ts +0 -49
- package/src/utils/usage.ts +0 -62
package/src/utils/cursors.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
decodeBase64,
|
|
3
|
+
decodeCursorChunk,
|
|
3
4
|
encodeBase64,
|
|
5
|
+
encodeCursorChunk,
|
|
6
|
+
encodeCursorTuple,
|
|
7
|
+
getConnectionPageSize,
|
|
4
8
|
type MaybePromise,
|
|
5
9
|
PothosValidationError,
|
|
6
10
|
type SchemaTypes,
|
|
11
|
+
validateConnectionArguments,
|
|
7
12
|
} from '@pothos/core';
|
|
8
13
|
import {
|
|
9
14
|
asc,
|
|
@@ -20,35 +25,17 @@ import {
|
|
|
20
25
|
type Table,
|
|
21
26
|
type TableRelationalConfig,
|
|
22
27
|
} from 'drizzle-orm';
|
|
23
|
-
import type { GraphQLResolveInfo } from 'graphql';
|
|
24
28
|
import type { ConnectionOrderBy, QueryForDrizzleConnection } from '../types.js';
|
|
29
|
+
import type { DrizzlePlan } from './adapter.js';
|
|
25
30
|
import type { PothosDrizzleSchemaConfig } from './config.js';
|
|
26
|
-
import {
|
|
31
|
+
import { queryFromPlan } from './map-query.js';
|
|
27
32
|
import { omitUndefinedKeys, type SelectionMap } from './selections.js';
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (value instanceof Date) {
|
|
38
|
-
return `D:${String(Number(value))}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
switch (typeof value) {
|
|
42
|
-
case 'number':
|
|
43
|
-
return `N:${value}`;
|
|
44
|
-
case 'string':
|
|
45
|
-
return `S:${value}`;
|
|
46
|
-
case 'bigint':
|
|
47
|
-
return `I:${value}`;
|
|
48
|
-
default:
|
|
49
|
-
throw new PothosValidationError(`Unsupported cursor type ${typeof value}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
34
|
+
// The tagging is `@pothos/core`'s `encodeCursorChunk`, shared with the prisma plugins so the
|
|
35
|
+
// three can't drift apart again. A nullish ordering value is a position this plugin compares
|
|
36
|
+
// against with `is null`, and it now writes as a `Z:` chunk: it used to interpolate as the string
|
|
37
|
+
// `null`, which is not a chunk, so the cursor came back out as "Invalid cursor" on the next page.
|
|
38
|
+
export const formatCursorChunk = encodeCursorChunk;
|
|
52
39
|
|
|
53
40
|
export function formatDrizzleCursor(
|
|
54
41
|
record: Record<string, unknown>,
|
|
@@ -80,7 +67,6 @@ export function getIDSerializer(fields: Column[], config: PothosDrizzleSchemaCon
|
|
|
80
67
|
|
|
81
68
|
return (value: Record<string, unknown>) => {
|
|
82
69
|
if (fields.length > 1) {
|
|
83
|
-
fields.map((field) => field.keyAsName);
|
|
84
70
|
return `${JSON.stringify(fields.map((col) => value[config.columnToTsName(col)]))}`;
|
|
85
71
|
}
|
|
86
72
|
|
|
@@ -109,9 +95,7 @@ export function getColumnSerializer(
|
|
|
109
95
|
if (fields.length > 1) {
|
|
110
96
|
// each value carries its own type tag, the same ones a single value gets.
|
|
111
97
|
// Plain JSON would turn a Date into a string and refuse a bigint outright.
|
|
112
|
-
return
|
|
113
|
-
fields.map((field) => formatCursorChunk(value[cursorFieldKey(field, config)])),
|
|
114
|
-
)}`;
|
|
98
|
+
return encodeCursorTuple(fields.map((field) => value[cursorFieldKey(field, config)]));
|
|
115
99
|
}
|
|
116
100
|
|
|
117
101
|
return formatCursorChunk(value[cursorFieldKey(fields[0], config)]);
|
|
@@ -156,28 +140,9 @@ export function parseSerializedDrizzleColumn(value: unknown): unknown {
|
|
|
156
140
|
}
|
|
157
141
|
|
|
158
142
|
try {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
case 'S':
|
|
163
|
-
return rawValue;
|
|
164
|
-
case 'N':
|
|
165
|
-
return Number.parseInt(rawValue, 10);
|
|
166
|
-
case 'D':
|
|
167
|
-
return new Date(Number.parseInt(rawValue, 10));
|
|
168
|
-
case 'J':
|
|
169
|
-
// compound values from before each one carried a tag: whatever JSON
|
|
170
|
-
// preserved is the best that can be recovered
|
|
171
|
-
return JSON.parse(rawValue) as unknown;
|
|
172
|
-
case 'T':
|
|
173
|
-
return (JSON.parse(rawValue) as (string | null)[]).map((chunk) =>
|
|
174
|
-
chunk === null ? null : parseSerializedDrizzleColumn(chunk),
|
|
175
|
-
);
|
|
176
|
-
case 'I':
|
|
177
|
-
return BigInt(rawValue);
|
|
178
|
-
default:
|
|
179
|
-
throw new PothosValidationError(`Invalid cursor type ${type}`);
|
|
180
|
-
}
|
|
143
|
+
// `@pothos/core`'s `decodeCursorChunk` reads every tag, including the `J:` a compound cursor
|
|
144
|
+
// used before each part carried one -- see `getCursorParser` for what happens to that array.
|
|
145
|
+
return decodeCursorChunk(value);
|
|
181
146
|
} catch {
|
|
182
147
|
throw new PothosValidationError(`Invalid serialized data: ${value}`);
|
|
183
148
|
}
|
|
@@ -202,7 +167,9 @@ export function parseSerializedIDColumn(id: string, field: Column): unknown {
|
|
|
202
167
|
}
|
|
203
168
|
|
|
204
169
|
if (field.dataType === 'object date') {
|
|
205
|
-
|
|
170
|
+
// `formatIDChunk` writes the epoch milliseconds; `new Date` of that string is an Invalid
|
|
171
|
+
// Date, since it is not a date format `Date` parses.
|
|
172
|
+
return new Date(Number(id));
|
|
206
173
|
}
|
|
207
174
|
|
|
208
175
|
throw new PothosValidationError(`Unsupported ID type ${field.dataType}`);
|
|
@@ -215,14 +182,16 @@ export function parseSerializedIDColumn(id: string, field: Column): unknown {
|
|
|
215
182
|
}
|
|
216
183
|
}
|
|
217
184
|
|
|
218
|
-
|
|
185
|
+
// Keyed by the typescript name, as `getIDSerializer` reads by: the record is a row of the table,
|
|
186
|
+
// and every consumer (the node ref's `parseId`, the model loader) looks columns up that way.
|
|
187
|
+
export function getIDParser(fields: readonly Column[], config: PothosDrizzleSchemaConfig) {
|
|
219
188
|
if (fields.length === 0) {
|
|
220
189
|
throw new PothosValidationError('Column parser must have at least one field');
|
|
221
190
|
}
|
|
222
191
|
|
|
223
192
|
return (value: string) => {
|
|
224
193
|
if (fields.length === 1) {
|
|
225
|
-
return { [fields[0]
|
|
194
|
+
return { [config.columnToTsName(fields[0])]: parseSerializedIDColumn(value, fields[0]) };
|
|
226
195
|
}
|
|
227
196
|
|
|
228
197
|
try {
|
|
@@ -243,7 +212,7 @@ export function getIDParser(fields: readonly Column[]) {
|
|
|
243
212
|
const record: Record<string, unknown> = {};
|
|
244
213
|
|
|
245
214
|
fields.forEach((field, i) => {
|
|
246
|
-
record[field
|
|
215
|
+
record[config.columnToTsName(field)] = parsed[i];
|
|
247
216
|
});
|
|
248
217
|
|
|
249
218
|
return record;
|
|
@@ -307,6 +276,10 @@ export function getCursorParser(keys: readonly string[]) {
|
|
|
307
276
|
// the columns that came before it. Those still describe a position, just a
|
|
308
277
|
// less precise one, so the page is keyed off the prefix the cursor covers
|
|
309
278
|
// rather than rejected. Cursors returned by that page carry every column.
|
|
279
|
+
//
|
|
280
|
+
// The array is a `T:` chunk's values, each still its own type. A cursor issued before this
|
|
281
|
+
// release decodes from a `J:` chunk instead, whose parts arrive as whatever plain JSON
|
|
282
|
+
// preserved -- see the deprecated `J:` case in `@pothos/core`'s `decodeCursorChunk`.
|
|
310
283
|
const values = Array.isArray(parsed) ? parsed : [parsed];
|
|
311
284
|
|
|
312
285
|
if (values.length === 0) {
|
|
@@ -553,8 +526,8 @@ function keysetFilter(entries: OrderByEntry[], cursor: string, paging: 'after' |
|
|
|
553
526
|
export function drizzleCursorConnectionQuery({
|
|
554
527
|
args,
|
|
555
528
|
ctx,
|
|
556
|
-
maxSize
|
|
557
|
-
defaultSize
|
|
529
|
+
maxSize,
|
|
530
|
+
defaultSize,
|
|
558
531
|
orderBy,
|
|
559
532
|
extras,
|
|
560
533
|
where,
|
|
@@ -562,13 +535,7 @@ export function drizzleCursorConnectionQuery({
|
|
|
562
535
|
table,
|
|
563
536
|
}: DrizzleCursorConnectionQueryOptions) {
|
|
564
537
|
const { before, after, first, last } = args;
|
|
565
|
-
|
|
566
|
-
throw new PothosValidationError('Argument "first" must be a non-negative integer');
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
if (last != null && last < 0) {
|
|
570
|
-
throw new PothosValidationError('Argument "last" must be a non-negative integer');
|
|
571
|
-
}
|
|
538
|
+
validateConnectionArguments(args);
|
|
572
539
|
|
|
573
540
|
if (first != null && last != null) {
|
|
574
541
|
throw new PothosValidationError(
|
|
@@ -580,8 +547,13 @@ export function drizzleCursorConnectionQuery({
|
|
|
580
547
|
const defaultSizeForConnection =
|
|
581
548
|
typeof defaultSize === 'function' ? defaultSize(args, ctx) : defaultSize;
|
|
582
549
|
|
|
583
|
-
const limit =
|
|
584
|
-
|
|
550
|
+
const { limit } = getConnectionPageSize({
|
|
551
|
+
args,
|
|
552
|
+
defaultSize: defaultSizeForConnection,
|
|
553
|
+
maxSize: maxSizeForConnection,
|
|
554
|
+
});
|
|
555
|
+
// `last: 0` asks for the last zero rows, so it pages backwards like any other `last`.
|
|
556
|
+
const inverted = first == null && last != null;
|
|
585
557
|
|
|
586
558
|
const parsedOrderBy = parseOrderBy(config, table, orderBy, inverted, extras);
|
|
587
559
|
|
|
@@ -624,8 +596,11 @@ export function wrapConnectionResult<T extends {}>(
|
|
|
624
596
|
totalCount?: number | (() => MaybePromise<number>) | null,
|
|
625
597
|
) {
|
|
626
598
|
const gotFullResults = results.length === Math.abs(limit);
|
|
627
|
-
|
|
628
|
-
|
|
599
|
+
// `first`/`last` are compared against null rather than by truthiness, so `last: 0` reports the
|
|
600
|
+
// `pageInfo` of a backward page of zero rows rather than of a forward one.
|
|
601
|
+
const backward = args.first == null && args.last != null;
|
|
602
|
+
const hasNextPage = args.before ? true : args.last != null ? false : gotFullResults;
|
|
603
|
+
const hasPreviousPage = args.after ? true : backward ? gotFullResults : false;
|
|
629
604
|
const nodes = gotFullResults ? results.slice(0, -1) : results;
|
|
630
605
|
|
|
631
606
|
const connection = {
|
|
@@ -658,7 +633,7 @@ export function wrapConnectionResult<T extends {}>(
|
|
|
658
633
|
},
|
|
659
634
|
);
|
|
660
635
|
|
|
661
|
-
if (
|
|
636
|
+
if (backward) {
|
|
662
637
|
edges.reverse();
|
|
663
638
|
}
|
|
664
639
|
|
|
@@ -671,8 +646,8 @@ export function wrapConnectionResult<T extends {}>(
|
|
|
671
646
|
|
|
672
647
|
export async function resolveDrizzleCursorConnection<T extends {}>(
|
|
673
648
|
tableName: string,
|
|
674
|
-
|
|
675
|
-
|
|
649
|
+
// The settled plan of the connection's rows; the builder handed to `resolve` merges into it.
|
|
650
|
+
plan: DrizzlePlan | undefined,
|
|
676
651
|
config: PothosDrizzleSchemaConfig,
|
|
677
652
|
options: Omit<DrizzleCursorConnectionQueryOptions, 'orderBy' | 'config' | 'table'> & {
|
|
678
653
|
totalCount?: () => MaybePromise<number>;
|
|
@@ -697,10 +672,9 @@ export async function resolveDrizzleCursorConnection<T extends {}>(
|
|
|
697
672
|
});
|
|
698
673
|
formatter = getCursorFormatter(cursorFields, config);
|
|
699
674
|
|
|
700
|
-
query =
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
select: omitUndefinedKeys({
|
|
675
|
+
query = queryFromPlan(
|
|
676
|
+
plan,
|
|
677
|
+
omitUndefinedKeys({
|
|
704
678
|
...connectionQuery,
|
|
705
679
|
extras: q.extras,
|
|
706
680
|
columns: {
|
|
@@ -714,11 +688,7 @@ export async function resolveDrizzleCursorConnection<T extends {}>(
|
|
|
714
688
|
}
|
|
715
689
|
: q.where || connectionQuery.where,
|
|
716
690
|
}) as never,
|
|
717
|
-
|
|
718
|
-
typeName,
|
|
719
|
-
config,
|
|
720
|
-
// withUsageCheck: !!this.builder.options.prisma?.onUnusedQuery,
|
|
721
|
-
});
|
|
691
|
+
);
|
|
722
692
|
|
|
723
693
|
return query;
|
|
724
694
|
});
|
|
@@ -743,10 +713,12 @@ export async function resolveDrizzleCursorConnection<T extends {}>(
|
|
|
743
713
|
};
|
|
744
714
|
}
|
|
745
715
|
|
|
716
|
+
const { limit } = query;
|
|
717
|
+
|
|
746
718
|
return wrapConnectionResult(
|
|
747
719
|
results,
|
|
748
720
|
options.args,
|
|
749
|
-
|
|
721
|
+
limit as number,
|
|
750
722
|
formatter!,
|
|
751
723
|
undefined,
|
|
752
724
|
parent,
|