@pothos/plugin-drizzle 0.0.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 +7 -0
- package/LICENSE +6 -0
- package/README.md +437 -0
- package/TODO.md +21 -0
- package/drizzle/meta/_journal.json +1 -0
- package/drizzle.config.ts +10 -0
- package/dts/drizzle-field-builder.d.ts +124 -0
- package/dts/drizzle-field-builder.d.ts.map +1 -0
- package/dts/field-builder.d.ts +2 -0
- package/dts/field-builder.d.ts.map +1 -0
- package/dts/global-types.d.ts +92 -0
- package/dts/global-types.d.ts.map +1 -0
- package/dts/index.d.ts +13 -0
- package/dts/index.d.ts.map +1 -0
- package/dts/interface-ref.d.ts +9 -0
- package/dts/interface-ref.d.ts.map +1 -0
- package/dts/model-loader.d.ts +44 -0
- package/dts/model-loader.d.ts.map +1 -0
- package/dts/node-ref.d.ts +5 -0
- package/dts/node-ref.d.ts.map +1 -0
- package/dts/object-ref.d.ts +14 -0
- package/dts/object-ref.d.ts.map +1 -0
- package/dts/schema-builder.d.ts +2 -0
- package/dts/schema-builder.d.ts.map +1 -0
- package/dts/types.d.ts +147 -0
- package/dts/types.d.ts.map +1 -0
- package/dts/utils/config.d.ts +7 -0
- package/dts/utils/config.d.ts.map +1 -0
- package/dts/utils/cursors.d.ts +58 -0
- package/dts/utils/cursors.d.ts.map +1 -0
- package/dts/utils/deep-equal.d.ts +2 -0
- package/dts/utils/deep-equal.d.ts.map +1 -0
- package/dts/utils/drizzle-graphql.d.ts +18 -0
- package/dts/utils/drizzle-graphql.d.ts.map +1 -0
- package/dts/utils/loader-map.d.ts +11 -0
- package/dts/utils/loader-map.d.ts.map +1 -0
- package/dts/utils/map-query.d.ts +30 -0
- package/dts/utils/map-query.d.ts.map +1 -0
- package/dts/utils/refs.d.ts +5 -0
- package/dts/utils/refs.d.ts.map +1 -0
- package/dts/utils/selections.d.ts +22 -0
- package/dts/utils/selections.d.ts.map +1 -0
- package/dts/utils/usage.d.ts +5 -0
- package/dts/utils/usage.d.ts.map +1 -0
- package/esm/drizzle-field-builder.d.ts +216 -0
- package/esm/drizzle-field-builder.d.ts.map +1 -0
- package/esm/field-builder.d.ts +2 -0
- package/esm/field-builder.d.ts.map +1 -0
- package/esm/global-types.d.ts +124 -0
- package/esm/global-types.d.ts.map +1 -0
- package/esm/index.d.ts +13 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/interface-ref.d.ts +9 -0
- package/esm/interface-ref.d.ts.map +1 -0
- package/esm/model-loader.d.ts +45 -0
- package/esm/model-loader.d.ts.map +1 -0
- package/esm/node-ref.d.ts +5 -0
- package/esm/node-ref.d.ts.map +1 -0
- package/esm/object-ref.d.ts +14 -0
- package/esm/object-ref.d.ts.map +1 -0
- package/esm/package.json +3 -0
- package/esm/schema-builder.d.ts +2 -0
- package/esm/schema-builder.d.ts.map +1 -0
- package/esm/src/drizzle-field-builder.js +215 -0
- package/esm/src/drizzle-field-builder.js.map +1 -0
- package/esm/src/field-builder.js +77 -0
- package/esm/src/field-builder.js.map +1 -0
- package/esm/src/global-types.js +2 -0
- package/esm/src/global-types.js.map +1 -0
- package/esm/src/index.js +107 -0
- package/esm/src/index.js.map +1 -0
- package/esm/src/interface-ref.js +26 -0
- package/esm/src/interface-ref.js.map +1 -0
- package/esm/src/model-loader.js +168 -0
- package/esm/src/model-loader.js.map +1 -0
- package/esm/src/node-ref.js +4 -0
- package/esm/src/node-ref.js.map +1 -0
- package/esm/src/object-ref.js +38 -0
- package/esm/src/object-ref.js.map +1 -0
- package/esm/src/schema-builder.js +190 -0
- package/esm/src/schema-builder.js.map +1 -0
- package/esm/src/types.js +2 -0
- package/esm/src/types.js.map +1 -0
- package/esm/src/utils/config.js +15 -0
- package/esm/src/utils/config.js.map +1 -0
- package/esm/src/utils/cursors.js +316 -0
- package/esm/src/utils/cursors.js.map +1 -0
- package/esm/src/utils/deep-equal.js +44 -0
- package/esm/src/utils/deep-equal.js.map +1 -0
- package/esm/src/utils/drizzle-graphql.js +176 -0
- package/esm/src/utils/drizzle-graphql.js.map +1 -0
- package/esm/src/utils/loader-map.js +35 -0
- package/esm/src/utils/loader-map.js.map +1 -0
- package/esm/src/utils/map-query.js +284 -0
- package/esm/src/utils/map-query.js.map +1 -0
- package/esm/src/utils/refs.js +14 -0
- package/esm/src/utils/refs.js.map +1 -0
- package/esm/src/utils/selections.js +136 -0
- package/esm/src/utils/selections.js.map +1 -0
- package/esm/src/utils/usage.js +59 -0
- package/esm/src/utils/usage.js.map +1 -0
- package/esm/types.d.ts +161 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/utils/config.d.ts +7 -0
- package/esm/utils/config.d.ts.map +1 -0
- package/esm/utils/cursors.d.ts +58 -0
- package/esm/utils/cursors.d.ts.map +1 -0
- package/esm/utils/deep-equal.d.ts +2 -0
- package/esm/utils/deep-equal.d.ts.map +1 -0
- package/esm/utils/drizzle-graphql.d.ts +18 -0
- package/esm/utils/drizzle-graphql.d.ts.map +1 -0
- package/esm/utils/loader-map.d.ts +11 -0
- package/esm/utils/loader-map.d.ts.map +1 -0
- package/esm/utils/map-query.d.ts +30 -0
- package/esm/utils/map-query.d.ts.map +1 -0
- package/esm/utils/refs.d.ts +5 -0
- package/esm/utils/refs.d.ts.map +1 -0
- package/esm/utils/selections.d.ts +22 -0
- package/esm/utils/selections.d.ts.map +1 -0
- package/esm/utils/usage.d.ts +5 -0
- package/esm/utils/usage.d.ts.map +1 -0
- package/lib/src/drizzle-field-builder.js +225 -0
- package/lib/src/drizzle-field-builder.js.map +1 -0
- package/lib/src/field-builder.js +82 -0
- package/lib/src/field-builder.js.map +1 -0
- package/lib/src/global-types.js +6 -0
- package/lib/src/global-types.js.map +1 -0
- package/lib/src/index.js +180 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/interface-ref.js +36 -0
- package/lib/src/interface-ref.js.map +1 -0
- package/lib/src/model-loader.js +176 -0
- package/lib/src/model-loader.js.map +1 -0
- package/lib/src/node-ref.js +15 -0
- package/lib/src/node-ref.js.map +1 -0
- package/lib/src/object-ref.js +56 -0
- package/lib/src/object-ref.js.map +1 -0
- package/lib/src/schema-builder.js +236 -0
- package/lib/src/schema-builder.js.map +1 -0
- package/lib/src/types.js +13 -0
- package/lib/src/types.js.map +1 -0
- package/lib/src/utils/config.js +26 -0
- package/lib/src/utils/config.js.map +1 -0
- package/lib/src/utils/cursors.js +362 -0
- package/lib/src/utils/cursors.js.map +1 -0
- package/lib/src/utils/deep-equal.js +55 -0
- package/lib/src/utils/deep-equal.js.map +1 -0
- package/lib/src/utils/drizzle-graphql.js +192 -0
- package/lib/src/utils/drizzle-graphql.js.map +1 -0
- package/lib/src/utils/loader-map.js +57 -0
- package/lib/src/utils/loader-map.js.map +1 -0
- package/lib/src/utils/map-query.js +308 -0
- package/lib/src/utils/map-query.js.map +1 -0
- package/lib/src/utils/refs.js +33 -0
- package/lib/src/utils/refs.js.map +1 -0
- package/lib/src/utils/selections.js +163 -0
- package/lib/src/utils/selections.js.map +1 -0
- package/lib/src/utils/usage.js +84 -0
- package/lib/src/utils/usage.js.map +1 -0
- package/package.json +66 -0
- package/src/drizzle-field-builder.ts +500 -0
- package/src/field-builder.ts +168 -0
- package/src/global-types.ts +481 -0
- package/src/index.ts +175 -0
- package/src/interface-ref.ts +24 -0
- package/src/model-loader.ts +235 -0
- package/src/node-ref.ts +8 -0
- package/src/object-ref.ts +51 -0
- package/src/schema-builder.ts +299 -0
- package/src/types.ts +640 -0
- package/src/utils/config.ts +28 -0
- package/src/utils/cursors.ts +446 -0
- package/src/utils/deep-equal.ts +58 -0
- package/src/utils/drizzle-graphql.ts +235 -0
- package/src/utils/loader-map.ts +51 -0
- package/src/utils/map-query.ts +582 -0
- package/src/utils/refs.ts +25 -0
- package/src/utils/selections.ts +209 -0
- package/src/utils/usage.ts +64 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { asc, Column, desc, getOperators, SQL, Table, TableRelationalConfig } from 'drizzle-orm';
|
|
2
|
+
import { GraphQLError } from 'graphql';
|
|
3
|
+
|
|
4
|
+
export const remapFromGraphQLCore = (value: any, column: Column, columnName: string) => {
|
|
5
|
+
switch (column.dataType) {
|
|
6
|
+
case 'date': {
|
|
7
|
+
const formatted = new Date(value);
|
|
8
|
+
if (Number.isNaN(formatted.getTime()))
|
|
9
|
+
throw new GraphQLError(`Field '${columnName}' is not a valid date!`);
|
|
10
|
+
|
|
11
|
+
return formatted;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
case 'buffer': {
|
|
15
|
+
if (!Array.isArray(value)) {
|
|
16
|
+
throw new GraphQLError(`Field '${columnName}' is not an array!`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Buffer.from(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
case 'json': {
|
|
23
|
+
if (column.columnType === 'PgGeometryObject') return value;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(value);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
throw new GraphQLError(
|
|
29
|
+
`Invalid JSON in field '${columnName}':\n${e instanceof Error ? e.message : 'Unknown error'}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
case 'array': {
|
|
35
|
+
if (!Array.isArray(value)) {
|
|
36
|
+
throw new GraphQLError(`Field '${columnName}' is not an array!`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (column.columnType === 'PgGeometry' && value.length !== 2) {
|
|
40
|
+
throw new GraphQLError(
|
|
41
|
+
`Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
case 'bigint': {
|
|
49
|
+
try {
|
|
50
|
+
return BigInt(value);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
throw new GraphQLError(`Field '${columnName}' is not a BigInt!`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
default: {
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const remapFromGraphQLSingleInput = (
|
|
63
|
+
queryInput: Record<string, any>,
|
|
64
|
+
table: TableRelationalConfig,
|
|
65
|
+
) => {
|
|
66
|
+
for (const [key, value] of Object.entries(queryInput)) {
|
|
67
|
+
if (value === undefined) {
|
|
68
|
+
delete queryInput[key];
|
|
69
|
+
} else {
|
|
70
|
+
const column = table.columns[key];
|
|
71
|
+
if (!column) throw new GraphQLError(`Unknown column: ${key}`);
|
|
72
|
+
|
|
73
|
+
if (value === null && column.notNull) {
|
|
74
|
+
delete queryInput[key];
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
queryInput[key] = remapFromGraphQLCore(value, column, key);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return queryInput;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const remapFromGraphQLArrayInput = (
|
|
86
|
+
queryInput: Record<string, any>[],
|
|
87
|
+
table: TableRelationalConfig,
|
|
88
|
+
) => {
|
|
89
|
+
for (const entry of queryInput) remapFromGraphQLSingleInput(entry, table);
|
|
90
|
+
|
|
91
|
+
return queryInput;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export type OrderByArgs<TTable extends TableRelationalConfig> = {
|
|
95
|
+
[Key in keyof TTable['columns']]?: {
|
|
96
|
+
direction: 'asc' | 'desc';
|
|
97
|
+
priority: number;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const extractOrderBy = <
|
|
102
|
+
TTable extends TableRelationalConfig,
|
|
103
|
+
TArgs extends OrderByArgs<any> = OrderByArgs<TTable>,
|
|
104
|
+
>(
|
|
105
|
+
table: TTable,
|
|
106
|
+
orderArgs: TArgs,
|
|
107
|
+
): SQL[] => {
|
|
108
|
+
const res = [] as SQL[];
|
|
109
|
+
|
|
110
|
+
for (const [column, config] of Object.entries(orderArgs).sort(
|
|
111
|
+
(a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0),
|
|
112
|
+
)) {
|
|
113
|
+
if (!config) continue;
|
|
114
|
+
const { direction } = config;
|
|
115
|
+
|
|
116
|
+
res.push(direction === 'asc' ? asc(table.columns[column]!) : desc(table.columns[column]!));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return res;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const ops = getOperators();
|
|
123
|
+
|
|
124
|
+
export const extractFiltersColumn = <TColumn extends Column>(
|
|
125
|
+
column: TColumn,
|
|
126
|
+
columnName: string,
|
|
127
|
+
operators: Record<string, unknown> & { OR?: Record<string, unknown>[] },
|
|
128
|
+
): SQL | undefined => {
|
|
129
|
+
if (!operators.OR?.length) delete operators.OR;
|
|
130
|
+
|
|
131
|
+
const entries = Object.entries(operators);
|
|
132
|
+
|
|
133
|
+
if (operators.OR) {
|
|
134
|
+
if (entries.length > 1) {
|
|
135
|
+
throw new GraphQLError(
|
|
136
|
+
`WHERE ${columnName}: Cannot specify both fields and 'OR' in column operators!`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const variants = [] as SQL[];
|
|
141
|
+
|
|
142
|
+
for (const variant of operators.OR) {
|
|
143
|
+
const extracted = extractFiltersColumn(column, columnName, variant);
|
|
144
|
+
|
|
145
|
+
if (extracted) variants.push(extracted);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return variants.length ? (variants.length > 1 ? ops.or(...variants) : variants[0]) : undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const variants = [] as SQL[];
|
|
152
|
+
for (const [operatorName, operatorValue] of entries) {
|
|
153
|
+
if (operatorValue === null || operatorValue === false) continue;
|
|
154
|
+
|
|
155
|
+
switch (operatorName) {
|
|
156
|
+
case 'eq':
|
|
157
|
+
case 'ne':
|
|
158
|
+
case 'gt':
|
|
159
|
+
case 'gte':
|
|
160
|
+
case 'lt':
|
|
161
|
+
case 'lte':
|
|
162
|
+
const singleValue = remapFromGraphQLCore(operatorValue, column, columnName);
|
|
163
|
+
variants.push(ops[operatorName](column, singleValue));
|
|
164
|
+
|
|
165
|
+
break;
|
|
166
|
+
case 'like':
|
|
167
|
+
case 'notLike':
|
|
168
|
+
case 'ilike':
|
|
169
|
+
case 'notIlike':
|
|
170
|
+
variants.push(ops[operatorName](column, operatorValue as string));
|
|
171
|
+
break;
|
|
172
|
+
case 'inArray':
|
|
173
|
+
case 'notInArray':
|
|
174
|
+
if (!(operatorValue as any[]).length) {
|
|
175
|
+
throw new GraphQLError(
|
|
176
|
+
`WHERE ${columnName}: Unable to use operator ${operatorName} with an empty array!`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
const arrayValue = (operatorValue as any[]).map((val) =>
|
|
180
|
+
remapFromGraphQLCore(val, column, columnName),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
variants.push(ops[operatorName](column, arrayValue));
|
|
184
|
+
break;
|
|
185
|
+
case 'isNull':
|
|
186
|
+
case 'isNotNull':
|
|
187
|
+
variants.push(ops[operatorName](column));
|
|
188
|
+
break;
|
|
189
|
+
default:
|
|
190
|
+
throw new GraphQLError(`Unknown operator: ${operatorName}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return variants.length ? (variants.length > 1 ? ops.and(...variants) : variants[0]) : undefined;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const extractFilters = <TTable extends TableRelationalConfig>(
|
|
198
|
+
table: TTable,
|
|
199
|
+
tableName: string,
|
|
200
|
+
filters: Record<string, unknown> & {
|
|
201
|
+
OR?: Record<string, unknown>[];
|
|
202
|
+
},
|
|
203
|
+
): SQL | undefined => {
|
|
204
|
+
if (!filters.OR?.length) delete filters.OR;
|
|
205
|
+
|
|
206
|
+
const entries = Object.entries(filters);
|
|
207
|
+
if (!entries.length) return;
|
|
208
|
+
|
|
209
|
+
if (filters.OR) {
|
|
210
|
+
if (entries.length > 1) {
|
|
211
|
+
throw new GraphQLError(
|
|
212
|
+
`WHERE ${tableName}: Cannot specify both fields and 'OR' in table filters!`,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const variants = [] as SQL[];
|
|
217
|
+
|
|
218
|
+
for (const variant of filters.OR) {
|
|
219
|
+
const extracted = extractFilters(table, tableName, variant);
|
|
220
|
+
if (extracted) variants.push(extracted);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return variants.length ? (variants.length > 1 ? ops.or(...variants) : variants[0]) : undefined;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const variants = [] as SQL[];
|
|
227
|
+
for (const [columnName, operators] of entries) {
|
|
228
|
+
if (operators === null) continue;
|
|
229
|
+
|
|
230
|
+
const column = table.columns[columnName]!;
|
|
231
|
+
variants.push(extractFiltersColumn(column, columnName, operators as Record<string, unknown>)!);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return variants.length ? (variants.length > 1 ? ops.and(...variants) : variants[0]) : undefined;
|
|
235
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { GraphQLResolveInfo } from 'graphql';
|
|
2
|
+
import { createContextCache } from '@pothos/core';
|
|
3
|
+
|
|
4
|
+
export type LoaderMappings = Record<
|
|
5
|
+
string,
|
|
6
|
+
{
|
|
7
|
+
field: string;
|
|
8
|
+
type: string;
|
|
9
|
+
mappings: LoaderMappings;
|
|
10
|
+
indirectPath: string[];
|
|
11
|
+
}
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
const cache = createContextCache((ctx) => new Map<string, LoaderMappings>());
|
|
15
|
+
|
|
16
|
+
export function cacheKey(type: string, path: GraphQLResolveInfo['path'], subPath: string[] = []) {
|
|
17
|
+
let key = '';
|
|
18
|
+
let current: GraphQLResolveInfo['path'] | undefined = path;
|
|
19
|
+
|
|
20
|
+
while (current) {
|
|
21
|
+
if (typeof current.key === 'string') {
|
|
22
|
+
key = key ? `${current.key}.${key}` : current.key;
|
|
23
|
+
}
|
|
24
|
+
current = current.prev;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const entry of subPath) {
|
|
28
|
+
key = `${key}.${entry}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return `${type}@${key}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function setLoaderMappings(ctx: object, info: GraphQLResolveInfo, value: LoaderMappings) {
|
|
35
|
+
Object.keys(value).forEach((field) => {
|
|
36
|
+
const map = cache(ctx);
|
|
37
|
+
|
|
38
|
+
const mapping = value[field];
|
|
39
|
+
const subPath = [...mapping.indirectPath, field];
|
|
40
|
+
const key = cacheKey(mapping.type, info.path, subPath);
|
|
41
|
+
|
|
42
|
+
map.set(key, mapping.mappings);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getLoaderMapping(ctx: object, path: GraphQLResolveInfo['path'], type: string) {
|
|
47
|
+
const map = cache(ctx);
|
|
48
|
+
const key = cacheKey(type, path, []);
|
|
49
|
+
|
|
50
|
+
return map.get(key) ?? null;
|
|
51
|
+
}
|