@lobomfz/db 0.3.9 → 0.4.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/README.md +3 -3
- package/package.json +8 -5
- package/src/database.ts +235 -42
- package/src/dialect/serialize.ts +1 -1
- package/src/env.ts +2 -1
- package/src/fts/resolve.ts +208 -0
- package/src/fts/sql.ts +148 -0
- package/src/fts/tokenizer.ts +27 -0
- package/src/generated.ts +1 -1
- package/src/index.ts +16 -2
- package/src/json.ts +13 -0
- package/src/migration/diff.ts +194 -1
- package/src/migration/execute.ts +42 -0
- package/src/migration/introspect.ts +133 -1
- package/src/migration/types.ts +68 -1
- package/src/plugin.ts +269 -9
- package/src/types.ts +111 -13
- package/src/validation-error.ts +8 -4
- package/src/vector-index/load.ts +67 -0
- package/src/vector-index/nearest.ts +68 -0
- package/src/vector-index/resolve.ts +78 -0
- package/src/vector-index/sql.ts +76 -0
- package/src/vector.ts +13 -0
- package/src/write-validation-plugin.ts +419 -52
|
@@ -1,35 +1,172 @@
|
|
|
1
1
|
import { type, type Type } from "arktype";
|
|
2
2
|
import {
|
|
3
3
|
type KyselyPlugin,
|
|
4
|
+
type InsertQueryNode as KyselyInsertQueryNode,
|
|
5
|
+
type UpdateQueryNode as KyselyUpdateQueryNode,
|
|
6
|
+
type OnConflictNode as KyselyOnConflictNode,
|
|
7
|
+
type ColumnUpdateNode as KyselyColumnUpdateNode,
|
|
8
|
+
type ValuesItemNode,
|
|
9
|
+
type OperationNode,
|
|
4
10
|
type RootOperationNode,
|
|
5
11
|
ColumnNode,
|
|
12
|
+
ColumnUpdateNode,
|
|
6
13
|
DefaultInsertValueNode,
|
|
14
|
+
InsertQueryNode,
|
|
15
|
+
OnConflictNode,
|
|
16
|
+
PrimitiveValueListNode,
|
|
17
|
+
ReferenceNode,
|
|
7
18
|
TableNode,
|
|
19
|
+
ValueListNode,
|
|
8
20
|
ValueNode,
|
|
9
21
|
ValuesNode,
|
|
10
22
|
} from "kysely";
|
|
11
23
|
|
|
12
|
-
import type {
|
|
13
|
-
import {
|
|
24
|
+
import type { StructureProp } from "./types.js";
|
|
25
|
+
import { ValidationError } from "./validation-error.js";
|
|
26
|
+
|
|
27
|
+
type TableWriteSchema = {
|
|
28
|
+
schema: Type;
|
|
29
|
+
columns: string[];
|
|
30
|
+
columnSet: Set<string>;
|
|
31
|
+
optionalNonNullColumns: Set<string>;
|
|
32
|
+
insertNullColumns: Set<string>;
|
|
33
|
+
vectorColumns: Map<string, number>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type InsertRow = {
|
|
37
|
+
values: Record<string, unknown>;
|
|
38
|
+
passthrough: Map<string, OperationNode>;
|
|
39
|
+
};
|
|
14
40
|
|
|
15
41
|
export class WriteValidationPlugin implements KyselyPlugin {
|
|
16
|
-
|
|
17
|
-
private columns: ColumnsMap,
|
|
18
|
-
private validation: { onWrite: boolean },
|
|
19
|
-
) {}
|
|
42
|
+
private schemas = new Map<string, TableWriteSchema>();
|
|
20
43
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
44
|
+
constructor(schemas: Map<string, Type>) {
|
|
45
|
+
this.registerSchemas(schemas);
|
|
46
|
+
}
|
|
25
47
|
|
|
26
|
-
|
|
48
|
+
transformQuery: KyselyPlugin["transformQuery"] = (args) => {
|
|
49
|
+
return this.transformWriteNode(args.node);
|
|
27
50
|
};
|
|
28
51
|
|
|
29
52
|
transformResult: KyselyPlugin["transformResult"] = async (args) => {
|
|
30
53
|
return args.result;
|
|
31
54
|
};
|
|
32
55
|
|
|
56
|
+
private registerSchemas(schemas: Map<string, Type>) {
|
|
57
|
+
for (const [table, schema] of schemas) {
|
|
58
|
+
const structureProps = (schema as any).structure?.props as StructureProp[] | undefined;
|
|
59
|
+
const columns = structureProps?.map((prop) => prop.key) ?? [];
|
|
60
|
+
|
|
61
|
+
const vectorColumns = new Map<string, number>();
|
|
62
|
+
|
|
63
|
+
for (const prop of structureProps ?? []) {
|
|
64
|
+
const meta = this.extractFieldMeta(prop);
|
|
65
|
+
|
|
66
|
+
if (meta?._generated === "vector" && typeof meta._vectorDim === "number") {
|
|
67
|
+
vectorColumns.set(prop.key, meta._vectorDim);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.schemas.set(table, {
|
|
72
|
+
schema,
|
|
73
|
+
columns,
|
|
74
|
+
columnSet: new Set(columns),
|
|
75
|
+
optionalNonNullColumns: new Set(
|
|
76
|
+
structureProps
|
|
77
|
+
?.filter((prop) => !prop.required && !this.acceptsNull(prop.value))
|
|
78
|
+
.map((prop) => prop.key) ?? [],
|
|
79
|
+
),
|
|
80
|
+
insertNullColumns: new Set(
|
|
81
|
+
structureProps
|
|
82
|
+
?.filter((prop) => this.acceptsNull(prop.value) && prop.inner.default === undefined)
|
|
83
|
+
.map((prop) => prop.key) ?? [],
|
|
84
|
+
),
|
|
85
|
+
vectorColumns,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private validateAndCoerceVector(
|
|
91
|
+
table: string,
|
|
92
|
+
column: string,
|
|
93
|
+
dim: number,
|
|
94
|
+
value: unknown,
|
|
95
|
+
): Uint8Array {
|
|
96
|
+
const vec =
|
|
97
|
+
value instanceof Float32Array
|
|
98
|
+
? value
|
|
99
|
+
: Array.isArray(value)
|
|
100
|
+
? Float32Array.from(value as number[])
|
|
101
|
+
: null;
|
|
102
|
+
|
|
103
|
+
if (!vec) {
|
|
104
|
+
throw new ValidationError(
|
|
105
|
+
table,
|
|
106
|
+
`expected Float32Array or number[] for vector column, got ${typeof value}`,
|
|
107
|
+
column,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (vec.length !== dim) {
|
|
112
|
+
throw new ValidationError(
|
|
113
|
+
table,
|
|
114
|
+
`vector dim mismatch: expected ${dim}, received ${vec.length}`,
|
|
115
|
+
column,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (let i = 0; i < vec.length; i++) {
|
|
120
|
+
if (!Number.isFinite(vec[i]!)) {
|
|
121
|
+
throw new ValidationError(
|
|
122
|
+
table,
|
|
123
|
+
`non-finite vector element at index ${i}: ${vec[i]}`,
|
|
124
|
+
column,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return new Uint8Array(vec.buffer, vec.byteOffset, vec.byteLength);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private coerceVectorsInRow(
|
|
133
|
+
table: string,
|
|
134
|
+
tableSchema: TableWriteSchema,
|
|
135
|
+
values: Record<string, unknown>,
|
|
136
|
+
) {
|
|
137
|
+
for (const [column, dim] of tableSchema.vectorColumns) {
|
|
138
|
+
if (!Object.prototype.hasOwnProperty.call(values, column)) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const value = values[column];
|
|
143
|
+
|
|
144
|
+
if (value === null || value === undefined) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
values[column] = this.validateAndCoerceVector(table, column, dim, value);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private acceptsNull(field: StructureProp["value"]) {
|
|
153
|
+
return field.branches.some((branch) => branch.unit === null || branch.domain === "null");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private extractFieldMeta(prop: StructureProp) {
|
|
157
|
+
const rootMeta = (prop.value as any).meta as
|
|
158
|
+
| { _generated?: string; _vectorDim?: number }
|
|
159
|
+
| undefined;
|
|
160
|
+
const branchMeta = prop.value.branches.find(
|
|
161
|
+
(b) => (b as any).meta && Object.keys((b as any).meta).length > 0,
|
|
162
|
+
);
|
|
163
|
+
const fromBranch = (branchMeta as any)?.meta as
|
|
164
|
+
| { _generated?: string; _vectorDim?: number }
|
|
165
|
+
| undefined;
|
|
166
|
+
|
|
167
|
+
return { ...fromBranch, ...rootMeta };
|
|
168
|
+
}
|
|
169
|
+
|
|
33
170
|
private getTableFromNode(node: RootOperationNode) {
|
|
34
171
|
switch (node.kind) {
|
|
35
172
|
case "InsertQueryNode":
|
|
@@ -48,90 +185,320 @@ export class WriteValidationPlugin implements KyselyPlugin {
|
|
|
48
185
|
}
|
|
49
186
|
}
|
|
50
187
|
|
|
51
|
-
private
|
|
52
|
-
|
|
53
|
-
|
|
188
|
+
private firstErrorColumn(result: { [index: number]: { path: ArrayLike<unknown> } | undefined }) {
|
|
189
|
+
const column = result[0]?.path[0];
|
|
190
|
+
|
|
191
|
+
if (typeof column === "string") {
|
|
192
|
+
return column;
|
|
54
193
|
}
|
|
55
194
|
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private morph(table: string, schema: Type, value: Record<string, unknown>) {
|
|
56
199
|
const result = schema(value);
|
|
57
200
|
|
|
58
201
|
if (result instanceof type.errors) {
|
|
59
|
-
throw new
|
|
202
|
+
throw new ValidationError(table, result.summary, this.firstErrorColumn(result));
|
|
60
203
|
}
|
|
204
|
+
|
|
205
|
+
return result as Record<string, unknown>;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private pickSchema(schema: Type, columns: Iterable<string>) {
|
|
209
|
+
return (schema as any).pick(...columns) as Type;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private stripNullOptionalFields(tableSchema: TableWriteSchema, value: Record<string, unknown>) {
|
|
213
|
+
const stripped = { ...value };
|
|
214
|
+
|
|
215
|
+
for (const column of tableSchema.optionalNonNullColumns) {
|
|
216
|
+
if (stripped[column] === null) {
|
|
217
|
+
delete stripped[column];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return stripped;
|
|
61
222
|
}
|
|
62
223
|
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
|
|
224
|
+
private prepareInsertValue(tableSchema: TableWriteSchema, value: Record<string, unknown>) {
|
|
225
|
+
const prepared = this.stripNullOptionalFields(tableSchema, value);
|
|
226
|
+
|
|
227
|
+
for (const column of tableSchema.insertNullColumns) {
|
|
228
|
+
if (!Object.prototype.hasOwnProperty.call(prepared, column)) {
|
|
229
|
+
prepared[column] = null;
|
|
230
|
+
}
|
|
66
231
|
}
|
|
67
232
|
|
|
233
|
+
return prepared;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private transformWriteNode(node: RootOperationNode) {
|
|
68
237
|
const table = this.getTableFromNode(node);
|
|
69
238
|
|
|
70
239
|
if (!table) {
|
|
71
|
-
return;
|
|
240
|
+
return node;
|
|
72
241
|
}
|
|
73
242
|
|
|
74
|
-
|
|
243
|
+
if (node.kind === "InsertQueryNode") {
|
|
244
|
+
return this.transformInsert(node, table);
|
|
245
|
+
}
|
|
75
246
|
|
|
76
|
-
if (
|
|
77
|
-
return;
|
|
247
|
+
if (node.kind === "UpdateQueryNode") {
|
|
248
|
+
return this.transformUpdate(node, table);
|
|
78
249
|
}
|
|
79
250
|
|
|
80
|
-
|
|
81
|
-
|
|
251
|
+
return node;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private getInsertRow(columns: string[], valueList: ValuesItemNode) {
|
|
255
|
+
const row: InsertRow = {
|
|
256
|
+
values: {},
|
|
257
|
+
passthrough: new Map(),
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
if (PrimitiveValueListNode.is(valueList)) {
|
|
261
|
+
for (let i = 0; i < columns.length; i++) {
|
|
262
|
+
row.values[columns[i]!] = valueList.values[i];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return row;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (!ValueListNode.is(valueList)) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
for (let i = 0; i < columns.length; i++) {
|
|
273
|
+
const column = columns[i]!;
|
|
274
|
+
const value = valueList.values[i];
|
|
275
|
+
|
|
276
|
+
if (!value || DefaultInsertValueNode.is(value)) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
82
279
|
|
|
83
|
-
if (
|
|
280
|
+
if (ValueNode.is(value)) {
|
|
281
|
+
row.values[column] = value.value;
|
|
84
282
|
continue;
|
|
85
283
|
}
|
|
86
284
|
|
|
87
|
-
|
|
285
|
+
row.passthrough.set(column, value);
|
|
88
286
|
}
|
|
287
|
+
|
|
288
|
+
return row;
|
|
89
289
|
}
|
|
90
290
|
|
|
91
|
-
private
|
|
92
|
-
|
|
93
|
-
|
|
291
|
+
private morphInsertRow(table: string, tableSchema: TableWriteSchema, row: InsertRow) {
|
|
292
|
+
const schemaLiteralValues = Object.fromEntries(
|
|
293
|
+
Object.entries(row.values).filter(([column]) => tableSchema.columnSet.has(column)),
|
|
294
|
+
);
|
|
295
|
+
const nonSchemaLiteralValues = Object.fromEntries(
|
|
296
|
+
Object.entries(row.values).filter(([column]) => !tableSchema.columnSet.has(column)),
|
|
297
|
+
);
|
|
298
|
+
const schemaLiteralColumns = Object.keys(schemaLiteralValues);
|
|
299
|
+
|
|
300
|
+
if (schemaLiteralColumns.length === 0) {
|
|
301
|
+
return row;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const morphedSchemaValues = this.morph(
|
|
305
|
+
table,
|
|
306
|
+
this.pickSchema(tableSchema.schema, schemaLiteralColumns),
|
|
307
|
+
this.prepareInsertValue(tableSchema, schemaLiteralValues),
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
this.coerceVectorsInRow(table, tableSchema, morphedSchemaValues);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
values: { ...nonSchemaLiteralValues, ...morphedSchemaValues },
|
|
314
|
+
passthrough: row.passthrough,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
94
317
|
|
|
95
|
-
|
|
96
|
-
|
|
318
|
+
private getInsertColumns(
|
|
319
|
+
tableSchema: TableWriteSchema,
|
|
320
|
+
originalColumns: string[],
|
|
321
|
+
rows: InsertRow[],
|
|
322
|
+
) {
|
|
323
|
+
const columns = [...originalColumns];
|
|
324
|
+
|
|
325
|
+
for (const column of tableSchema.columns) {
|
|
326
|
+
if (columns.includes(column)) {
|
|
327
|
+
continue;
|
|
97
328
|
}
|
|
98
329
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
330
|
+
if (rows.some((row) => Object.prototype.hasOwnProperty.call(row.values, column))) {
|
|
331
|
+
columns.push(column);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
102
334
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
335
|
+
for (const row of rows) {
|
|
336
|
+
for (const column of Object.keys(row.values)) {
|
|
337
|
+
if (!columns.includes(column)) {
|
|
338
|
+
columns.push(column);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
107
342
|
|
|
108
|
-
|
|
343
|
+
return columns;
|
|
344
|
+
}
|
|
109
345
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
346
|
+
private createInsertValueList(columns: string[], row: InsertRow) {
|
|
347
|
+
return ValueListNode.create(
|
|
348
|
+
columns.map((column) => {
|
|
349
|
+
const passthrough = row.passthrough.get(column);
|
|
113
350
|
|
|
114
|
-
|
|
351
|
+
if (passthrough) {
|
|
352
|
+
return passthrough;
|
|
115
353
|
}
|
|
354
|
+
|
|
355
|
+
if (Object.prototype.hasOwnProperty.call(row.values, column)) {
|
|
356
|
+
return ValueNode.create(row.values[column]);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return DefaultInsertValueNode.create();
|
|
360
|
+
}),
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private transformInsert(node: KyselyInsertQueryNode, table: string) {
|
|
365
|
+
const onConflict = node.onConflict
|
|
366
|
+
? this.transformOnConflict(table, node.onConflict)
|
|
367
|
+
: undefined;
|
|
368
|
+
const tableSchema = this.schemas.get(table);
|
|
369
|
+
|
|
370
|
+
if (!tableSchema) {
|
|
371
|
+
if (onConflict) {
|
|
372
|
+
return InsertQueryNode.cloneWith(node, { onConflict });
|
|
116
373
|
}
|
|
117
374
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
375
|
+
return node;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const columns = node.columns?.map((column) => column.column.name);
|
|
379
|
+
|
|
380
|
+
if (!columns || !node.values || !ValuesNode.is(node.values)) {
|
|
381
|
+
if (onConflict) {
|
|
382
|
+
return InsertQueryNode.cloneWith(node, { onConflict });
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return node;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const rows: InsertRow[] = [];
|
|
389
|
+
|
|
390
|
+
for (const valueList of node.values.values) {
|
|
391
|
+
const row = this.getInsertRow(columns, valueList);
|
|
392
|
+
|
|
393
|
+
if (!row) {
|
|
394
|
+
if (onConflict) {
|
|
395
|
+
return InsertQueryNode.cloneWith(node, { onConflict });
|
|
121
396
|
}
|
|
397
|
+
|
|
398
|
+
return node;
|
|
122
399
|
}
|
|
123
400
|
|
|
124
|
-
|
|
401
|
+
rows.push(this.morphInsertRow(table, tableSchema, row));
|
|
125
402
|
}
|
|
126
403
|
|
|
127
|
-
|
|
128
|
-
|
|
404
|
+
const insertColumns = this.getInsertColumns(tableSchema, columns, rows);
|
|
405
|
+
|
|
406
|
+
return InsertQueryNode.cloneWith(node, {
|
|
407
|
+
columns: insertColumns.map((column) => ColumnNode.create(column)),
|
|
408
|
+
values: ValuesNode.create(rows.map((row) => this.createInsertValueList(insertColumns, row))),
|
|
409
|
+
onConflict,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private transformUpdates(table: string, updates: readonly KyselyColumnUpdateNode[]) {
|
|
414
|
+
const tableSchema = this.schemas.get(table);
|
|
415
|
+
|
|
416
|
+
if (!tableSchema) {
|
|
417
|
+
return updates;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const literalColumns = new Set<string>();
|
|
421
|
+
const literalValues: Record<string, unknown> = {};
|
|
422
|
+
const nullOptionalColumns = new Set<string>();
|
|
423
|
+
|
|
424
|
+
for (const update of updates) {
|
|
425
|
+
if (!ColumnNode.is(update.column) || !ValueNode.is(update.value)) {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const column = update.column.column.name;
|
|
430
|
+
|
|
431
|
+
if (!tableSchema.columnSet.has(column)) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (update.value.value === null && tableSchema.optionalNonNullColumns.has(column)) {
|
|
436
|
+
nullOptionalColumns.add(column);
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
literalColumns.add(column);
|
|
441
|
+
literalValues[column] = update.value.value;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (literalColumns.size === 0 && nullOptionalColumns.size === 0) {
|
|
445
|
+
return updates;
|
|
129
446
|
}
|
|
130
447
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
448
|
+
const morphed =
|
|
449
|
+
literalColumns.size === 0
|
|
450
|
+
? {}
|
|
451
|
+
: this.morph(
|
|
452
|
+
table,
|
|
453
|
+
this.pickSchema(tableSchema.schema, literalColumns),
|
|
454
|
+
this.stripNullOptionalFields(tableSchema, literalValues),
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
this.coerceVectorsInRow(table, tableSchema, morphed);
|
|
458
|
+
|
|
459
|
+
return updates.flatMap((update) => {
|
|
460
|
+
if (!ColumnNode.is(update.column) || !ValueNode.is(update.value)) {
|
|
461
|
+
return [update];
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const column = update.column.column.name;
|
|
465
|
+
|
|
466
|
+
if (!literalColumns.has(column) || !tableSchema.columnSet.has(column)) {
|
|
467
|
+
if (nullOptionalColumns.has(column)) {
|
|
468
|
+
return [ColumnUpdateNode.create(update.column, ValueNode.create(null))];
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return [update];
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (!Object.prototype.hasOwnProperty.call(morphed, column)) {
|
|
475
|
+
return [
|
|
476
|
+
ColumnUpdateNode.create(update.column, ReferenceNode.create(ColumnNode.create(column))),
|
|
477
|
+
];
|
|
134
478
|
}
|
|
479
|
+
|
|
480
|
+
return [ColumnUpdateNode.create(update.column, ValueNode.create(morphed[column]))];
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private transformOnConflict(table: string, node: KyselyOnConflictNode) {
|
|
485
|
+
if (!node.updates) {
|
|
486
|
+
return node;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return OnConflictNode.cloneWith(node, {
|
|
490
|
+
updates: this.transformUpdates(table, node.updates),
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
private transformUpdate(node: KyselyUpdateQueryNode, table: string) {
|
|
495
|
+
if (!node.updates) {
|
|
496
|
+
return node;
|
|
135
497
|
}
|
|
498
|
+
|
|
499
|
+
return Object.freeze({
|
|
500
|
+
...node,
|
|
501
|
+
updates: this.transformUpdates(table, node.updates),
|
|
502
|
+
});
|
|
136
503
|
}
|
|
137
504
|
}
|