Skip to content

Commit 7cb641e

Browse files
committed
PGVector, PGGeometry support (Tests WIP)
1 parent 3173e12 commit 7cb641e

File tree

15 files changed

+3565
-2603
lines changed

15 files changed

+3565
-2603
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ runPg.ts
1313
Tests/.temp
1414
Tests/Migrations
1515
.DS_Store
16-
drizzle.test-heavy.ts
16+
drizzle.test-heavy.ts
17+
changes.md

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
"cpy": "^11.0.1",
4545
"dockerode": "^4.0.2",
4646
"dprint": "^0.45.1",
47-
"drizzle-kit": "^0.21.4",
48-
"drizzle-orm": "0.31.1",
47+
"drizzle-kit": "^0.22.8",
48+
"drizzle-orm": "0.31.2",
4949
"get-port": "^7.0.0",
5050
"glob": "^10.3.10",
5151
"graphql": "^16.3.0",

pnpm-lock.yaml

Lines changed: 13 additions & 247 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/util/builders/common.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export const innerOrder = new GraphQLInputObjectType({
179179
});
180180

181181
const generateColumnFilterValues = (column: Column, tableName: string, columnName: string): GraphQLInputObjectType => {
182-
const columnGraphQLType = drizzleColumnToGraphQLType(column, columnName, tableName, true);
182+
const columnGraphQLType = drizzleColumnToGraphQLType(column, columnName, tableName, true, false, true);
183183
const columnArr = new GraphQLList(new GraphQLNonNull(columnGraphQLType.type));
184184

185185
const baseFields = {
@@ -437,14 +437,14 @@ export const generateTableTypes = <
437437
const insertFields = Object.fromEntries(
438438
columnEntries.map(([columnName, columnDescription]) => [
439439
columnName,
440-
drizzleColumnToGraphQLType(columnDescription, columnName, tableName, false, true),
440+
drizzleColumnToGraphQLType(columnDescription, columnName, tableName, false, true, true),
441441
]),
442442
);
443443

444444
const updateFields = Object.fromEntries(
445445
columnEntries.map(([columnName, columnDescription]) => [
446446
columnName,
447-
drizzleColumnToGraphQLType(columnDescription, columnName, tableName, true),
447+
drizzleColumnToGraphQLType(columnDescription, columnName, tableName, true, false, true),
448448
]),
449449
);
450450

src/util/builders/mysql.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ const generateSelectArray = (
8989

9090
const result = await query;
9191

92-
return remapToGraphQLArrayOutput(result, tableName, relationMap);
92+
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
9393
} catch (e) {
9494
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
9595
throw new GraphQLError((<any> e).message);
@@ -159,7 +159,7 @@ const generateSelectSingle = (
159159
const result = await query;
160160
if (!result) return undefined;
161161

162-
return remapToGraphQLSingleOutput(result, tableName, relationMap);
162+
return remapToGraphQLSingleOutput(result, tableName, table, relationMap);
163163
} catch (e) {
164164
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
165165
throw new GraphQLError((<any> e).message);

src/util/builders/pg.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ const generateSelectArray = (
8989

9090
const result = await query;
9191

92-
return remapToGraphQLArrayOutput(result, tableName, relationMap);
92+
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
9393
} catch (e) {
9494
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
9595
throw new GraphQLError((<any> e).message);
@@ -157,7 +157,7 @@ const generateSelectSingle = (
157157
const result = await query;
158158
if (!result) return undefined;
159159

160-
return remapToGraphQLSingleOutput(result, tableName, relationMap);
160+
return remapToGraphQLSingleOutput(result, tableName, table, relationMap);
161161
} catch (e) {
162162
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
163163
throw new GraphQLError((<any> e).message);
@@ -195,7 +195,7 @@ const generateInsertArray = (
195195

196196
const result = await db.insert(table).values(input).returning(columns).onConflictDoNothing();
197197

198-
return remapToGraphQLArrayOutput(result, tableName);
198+
return remapToGraphQLArrayOutput(result, tableName, table);
199199
} catch (e) {
200200
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
201201
throw new GraphQLError((<any> e).message);
@@ -234,7 +234,7 @@ const generateInsertSingle = (
234234

235235
if (!result[0]) return undefined;
236236

237-
return remapToGraphQLSingleOutput(result[0], tableName);
237+
return remapToGraphQLSingleOutput(result[0], tableName, table);
238238
} catch (e) {
239239
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
240240
throw new GraphQLError((<any> e).message);
@@ -285,7 +285,7 @@ const generateUpdate = (
285285

286286
const result = await query;
287287

288-
return remapToGraphQLArrayOutput(result, tableName);
288+
return remapToGraphQLArrayOutput(result, tableName, table);
289289
} catch (e) {
290290
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
291291
throw new GraphQLError((<any> e).message);
@@ -330,7 +330,7 @@ const generateDelete = (
330330

331331
const result = await query;
332332

333-
return remapToGraphQLArrayOutput(result, tableName);
333+
return remapToGraphQLArrayOutput(result, tableName, table);
334334
} catch (e) {
335335
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
336336
throw new GraphQLError((<any> e).message);

src/util/builders/sqlite.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ const generateSelectArray = (
8989

9090
const result = await query;
9191

92-
return remapToGraphQLArrayOutput(result, tableName, relationMap);
92+
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
9393
} catch (e) {
9494
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
9595
throw new GraphQLError((<any> e).message);
@@ -157,7 +157,7 @@ const generateSelectSingle = (
157157
const result = await query;
158158
if (!result) return undefined;
159159

160-
return remapToGraphQLSingleOutput(result, tableName, relationMap);
160+
return remapToGraphQLSingleOutput(result, tableName, table, relationMap);
161161
} catch (e) {
162162
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
163163
throw new GraphQLError((<any> e).message);
@@ -199,7 +199,7 @@ const generateInsertArray = (
199199
.returning(columns as Record<string, SQLiteColumn>)
200200
.onConflictDoNothing();
201201

202-
return remapToGraphQLArrayOutput(result, tableName);
202+
return remapToGraphQLArrayOutput(result, tableName, table);
203203
} catch (e) {
204204
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
205205
throw new GraphQLError((<any> e).message);
@@ -238,7 +238,7 @@ const generateInsertSingle = (
238238

239239
if (!result[0]) return undefined;
240240

241-
return remapToGraphQLSingleOutput(result[0], tableName);
241+
return remapToGraphQLSingleOutput(result[0], tableName, table);
242242
} catch (e) {
243243
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
244244
throw new GraphQLError((<any> e).message);
@@ -289,7 +289,7 @@ const generateUpdate = (
289289

290290
const result = await query;
291291

292-
return remapToGraphQLArrayOutput(result, tableName);
292+
return remapToGraphQLArrayOutput(result, tableName, table);
293293
} catch (e) {
294294
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
295295
throw new GraphQLError((<any> e).message);
@@ -334,7 +334,7 @@ const generateDelete = (
334334

335335
const result = await query;
336336

337-
return remapToGraphQLArrayOutput(result, tableName);
337+
return remapToGraphQLArrayOutput(result, tableName, table);
338338
} catch (e) {
339339
if (typeof e === 'object' && typeof (<any> e).message === 'string') {
340340
throw new GraphQLError((<any> e).message);

src/util/builders/types.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,24 @@ export type ColTypeIsNullOrUndefinedWithDefault<TColumn extends Column, TColType
6464

6565
export type GetColumnGqlDataType<TColumn extends Column> = TColumn['dataType'] extends 'boolean'
6666
? ColTypeIsNull<TColumn, boolean>
67-
: TColumn['dataType'] extends 'json' | 'date' | 'string' | 'bigint'
67+
: TColumn['dataType'] extends 'json'
68+
? TColumn['_']['columnType'] extends 'PgGeometryObject' ? ColTypeIsNull<TColumn, {
69+
x: number;
70+
y: number;
71+
}>
72+
: ColTypeIsNull<TColumn, string>
73+
: TColumn['dataType'] extends 'date' | 'string' | 'bigint'
6874
? TColumn['enumValues'] extends [string, ...string[]] ? ColTypeIsNull<TColumn, TColumn['enumValues'][number]>
6975
: ColTypeIsNull<TColumn, string>
7076
: TColumn['dataType'] extends 'number' ? ColTypeIsNull<TColumn, number>
7177
: TColumn['dataType'] extends 'buffer' ? ColTypeIsNull<TColumn, number[]>
72-
: TColumn extends PgArray<any, any> ? ColTypeIsNull<
78+
: TColumn['dataType'] extends 'array' ? TColumn['columnType'] extends 'PgVector' ? ColTypeIsNull<TColumn, number[]>
79+
: TColumn['columnType'] extends 'PgGeometry' ? ColTypeIsNullOrUndefinedWithDefault<TColumn, [number, number]>
80+
: ColTypeIsNull<
7381
TColumn,
7482
Array<
75-
GetColumnGqlDataType<TColumn['baseColumn']> extends infer InnerColType
76-
? InnerColType extends null | undefined ? never
83+
GetColumnGqlDataType<TColumn extends { baseColumn: Column } ? TColumn['baseColumn'] : never> extends
84+
infer InnerColType ? InnerColType extends null | undefined ? never
7785
: InnerColType
7886
: never
7987
>
@@ -82,17 +90,26 @@ export type GetColumnGqlDataType<TColumn extends Column> = TColumn['dataType'] e
8290

8391
export type GetColumnGqlInsertDataType<TColumn extends Column> = TColumn['dataType'] extends 'boolean'
8492
? ColTypeIsNullOrUndefinedWithDefault<TColumn, boolean>
85-
: TColumn['dataType'] extends 'json' | 'date' | 'string' | 'bigint'
93+
: TColumn['dataType'] extends 'json'
94+
? TColumn['_']['columnType'] extends 'PgGeometryObject' ? ColTypeIsNullOrUndefinedWithDefault<TColumn, {
95+
x: number;
96+
y: number;
97+
}>
98+
: ColTypeIsNullOrUndefinedWithDefault<TColumn, string>
99+
: TColumn['dataType'] extends 'date' | 'string' | 'bigint'
86100
? TColumn['enumValues'] extends [string, ...string[]]
87101
? ColTypeIsNullOrUndefinedWithDefault<TColumn, TColumn['enumValues'][number]>
88102
: ColTypeIsNullOrUndefinedWithDefault<TColumn, string>
89103
: TColumn['dataType'] extends 'number' ? ColTypeIsNullOrUndefinedWithDefault<TColumn, number>
90104
: TColumn['dataType'] extends 'buffer' ? ColTypeIsNullOrUndefinedWithDefault<TColumn, number[]>
91-
: TColumn extends PgArray<any, any> ? ColTypeIsNullOrUndefinedWithDefault<
105+
: TColumn['dataType'] extends 'array'
106+
? TColumn['columnType'] extends 'PgVector' ? ColTypeIsNullOrUndefinedWithDefault<TColumn, number[]>
107+
: TColumn['columnType'] extends 'PgGeometry' ? ColTypeIsNullOrUndefinedWithDefault<TColumn, [number, number]>
108+
: ColTypeIsNullOrUndefinedWithDefault<
92109
TColumn,
93110
Array<
94-
GetColumnGqlDataType<TColumn['baseColumn']> extends infer InnerColType
95-
? InnerColType extends null | undefined ? never
111+
GetColumnGqlDataType<TColumn extends { baseColumn: Column } ? TColumn['baseColumn'] : never> extends
112+
infer InnerColType ? InnerColType extends null | undefined ? never
96113
: InnerColType
97114
: never
98115
>
@@ -101,15 +118,25 @@ export type GetColumnGqlInsertDataType<TColumn extends Column> = TColumn['dataTy
101118

102119
export type GetColumnGqlUpdateDataType<TColumn extends Column> = TColumn['dataType'] extends 'boolean'
103120
? boolean | null | undefined
104-
: TColumn['dataType'] extends 'json' | 'date' | 'string' | 'bigint'
121+
: TColumn['dataType'] extends 'json' ? TColumn['_']['columnType'] extends 'PgGeometryObject' ?
122+
| {
123+
x: number;
124+
y: number;
125+
}
126+
| null
127+
| undefined
128+
: string | null | undefined
129+
: TColumn['dataType'] extends 'date' | 'string' | 'bigint'
105130
? TColumn['enumValues'] extends [string, ...string[]] ? TColumn['enumValues'][number] | null | undefined
106131
: string | null | undefined
107132
: TColumn['dataType'] extends 'number' ? number | null | undefined
108133
: TColumn['dataType'] extends 'buffer' ? number[] | null | undefined
109-
: TColumn extends PgArray<any, any> ?
134+
: TColumn['dataType'] extends 'array' ? TColumn['columnType'] extends 'PgVector' ? number[] | null | undefined
135+
: TColumn['columnType'] extends 'PgGeometry' ? [number, number] | null | undefined
136+
:
110137
| Array<
111-
GetColumnGqlDataType<TColumn['baseColumn']> extends infer InnerColType
112-
? InnerColType extends null | undefined ? never
138+
GetColumnGqlDataType<TColumn extends { baseColumn: Column } ? TColumn['baseColumn'] : never> extends
139+
infer InnerColType ? InnerColType extends null | undefined ? never
113140
: InnerColType
114141
: never
115142
>

src/util/data-mappers/index.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { type Column, getTableColumns, type Relation, type Table } from 'drizzle-orm';
1+
import { type Column, getTableColumns, type Table } from 'drizzle-orm';
22
import { GraphQLError } from 'graphql';
33
import { TableNamedRelations } from '../builders';
44

55
export const remapToGraphQLCore = (
66
key: string,
77
value: any,
88
tableName: string,
9+
column: Column,
910
relationMap?: Record<string, Record<string, TableNamedRelations>>,
1011
): any => {
1112
if (value instanceof Date) return value.toISOString();
@@ -16,14 +17,30 @@ export const remapToGraphQLCore = (
1617

1718
if (Array.isArray(value)) {
1819
const relations = relationMap?.[tableName];
19-
if (relations?.[key]) return remapToGraphQLArrayOutput(value, relations[key]!.targetTableName, relationMap);
20+
if (relations?.[key]) {
21+
return remapToGraphQLArrayOutput(
22+
value,
23+
relations[key]!.targetTableName,
24+
relations[key]!.relation.referencedTable,
25+
relationMap,
26+
);
27+
}
28+
if (column.columnType === 'PgGeometry' || column.columnType === 'PgVector') return value;
2029

21-
return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, relationMap));
30+
return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
2231
}
2332

2433
if (typeof value === 'object') {
2534
const relations = relationMap?.[tableName];
26-
if (relations?.[key]) return remapToGraphQLSingleOutput(value, relations[key]!.targetTableName, relationMap);
35+
if (relations?.[key]) {
36+
return remapToGraphQLSingleOutput(
37+
value,
38+
relations[key]!.targetTableName,
39+
relations[key]!.relation.referencedTable,
40+
relationMap,
41+
);
42+
}
43+
if (column.columnType === 'PgGeometryObject') return value;
2744

2845
return JSON.stringify(value);
2946
}
@@ -34,13 +51,14 @@ export const remapToGraphQLCore = (
3451
export const remapToGraphQLSingleOutput = (
3552
queryOutput: Record<string, any>,
3653
tableName: string,
54+
table: Table,
3755
relationMap?: Record<string, Record<string, TableNamedRelations>>,
3856
) => {
3957
for (const [key, value] of Object.entries(queryOutput)) {
4058
if (value === undefined || value === null) {
4159
delete queryOutput[key];
4260
} else {
43-
queryOutput[key] = remapToGraphQLCore(key, value, tableName, relationMap);
61+
queryOutput[key] = remapToGraphQLCore(key, value, tableName, table[key as keyof Table]! as Column, relationMap);
4462
}
4563
}
4664

@@ -50,9 +68,12 @@ export const remapToGraphQLSingleOutput = (
5068
export const remapToGraphQLArrayOutput = (
5169
queryOutput: Record<string, any>[],
5270
tableName: string,
71+
table: Table,
5372
relationMap?: Record<string, Record<string, TableNamedRelations>>,
5473
) => {
55-
for (const entry of queryOutput) remapToGraphQLSingleOutput(entry, tableName, relationMap);
74+
for (const entry of queryOutput) {
75+
remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
76+
}
5677

5778
return queryOutput;
5879
};
@@ -75,6 +96,8 @@ export const remapFromGraphQLCore = (value: any, column: Column, columnName: str
7596
}
7697

7798
case 'json': {
99+
if (column.columnType === 'PgGeometryObject') return value;
100+
78101
try {
79102
return JSON.parse(value);
80103
} catch (e) {
@@ -89,6 +112,12 @@ export const remapFromGraphQLCore = (value: any, column: Column, columnName: str
89112
throw new GraphQLError(`Field '${columnName}' is not an array!`);
90113
}
91114

115+
if (column.columnType === 'PgGeometry' && value.length !== 2) {
116+
throw new GraphQLError(
117+
`Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`,
118+
);
119+
}
120+
92121
return value;
93122
}
94123

0 commit comments

Comments
 (0)