metal-orm 1.1.3 → 1.1.4
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 +715 -703
- package/dist/index.cjs +655 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +170 -8
- package/dist/index.d.ts +170 -8
- package/dist/index.js +649 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/naming-strategy.mjs +16 -1
- package/src/core/ast/procedure.ts +21 -0
- package/src/core/ast/query.ts +47 -19
- package/src/core/ddl/introspect/utils.ts +56 -56
- package/src/core/dialect/abstract.ts +560 -547
- package/src/core/dialect/base/sql-dialect.ts +43 -29
- package/src/core/dialect/mssql/index.ts +369 -232
- package/src/core/dialect/mysql/index.ts +99 -7
- package/src/core/dialect/postgres/index.ts +121 -60
- package/src/core/dialect/sqlite/index.ts +97 -64
- package/src/core/execution/db-executor.ts +108 -90
- package/src/core/execution/executors/mssql-executor.ts +28 -24
- package/src/core/execution/executors/mysql-executor.ts +62 -27
- package/src/core/execution/executors/sqlite-executor.ts +10 -9
- package/src/index.ts +9 -6
- package/src/orm/execute-procedure.ts +77 -0
- package/src/orm/execute.ts +74 -73
- package/src/orm/interceptor-pipeline.ts +21 -17
- package/src/orm/pooled-executor-factory.ts +41 -20
- package/src/orm/unit-of-work.ts +6 -4
- package/src/query/index.ts +8 -5
- package/src/query-builder/delete.ts +3 -2
- package/src/query-builder/insert-query-state.ts +47 -19
- package/src/query-builder/insert.ts +142 -28
- package/src/query-builder/procedure-call.ts +122 -0
- package/src/query-builder/select/select-operations.ts +5 -2
- package/src/query-builder/select.ts +1146 -1105
- package/src/query-builder/update.ts +3 -2
- package/src/tree/tree-manager.ts +754 -754
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { CompilerContext, CompiledProcedureCall } from '../abstract.js';
|
|
2
|
+
import { JsonPathNode } from '../../ast/expression.js';
|
|
3
|
+
import { InsertQueryNode } from '../../ast/query.js';
|
|
4
|
+
import { SqlDialectBase } from '../base/sql-dialect.js';
|
|
5
|
+
import { MysqlFunctionStrategy } from './functions.js';
|
|
6
|
+
import { ProcedureCallNode } from '../../ast/procedure.js';
|
|
7
|
+
|
|
8
|
+
const sanitizeVariableSuffix = (value: string): string =>
|
|
9
|
+
value.replace(/[^a-zA-Z0-9_]/g, '_');
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* MySQL dialect implementation
|
|
@@ -28,9 +34,95 @@ export class MySqlDialect extends SqlDialectBase {
|
|
|
28
34
|
* @param node - JSON path node
|
|
29
35
|
* @returns MySQL JSON path expression
|
|
30
36
|
*/
|
|
31
|
-
protected compileJsonPath(node: JsonPathNode): string {
|
|
32
|
-
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
33
|
-
// MySQL 5.7+ uses col->'$.path'
|
|
34
|
-
return `${col}->'${node.path}'`;
|
|
37
|
+
protected compileJsonPath(node: JsonPathNode): string {
|
|
38
|
+
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
39
|
+
// MySQL 5.7+ uses col->'$.path'
|
|
40
|
+
return `${col}->'${node.path}'`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
protected compileUpsertClause(ast: InsertQueryNode, ctx: CompilerContext): string {
|
|
44
|
+
if (!ast.onConflict) return '';
|
|
45
|
+
|
|
46
|
+
const clause = ast.onConflict;
|
|
47
|
+
if (clause.action.type === 'DoNothing') {
|
|
48
|
+
const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
|
|
49
|
+
if (!noOpColumn) {
|
|
50
|
+
throw new Error('MySQL ON DUPLICATE KEY UPDATE requires at least one target column.');
|
|
51
|
+
}
|
|
52
|
+
const col = this.quoteIdentifier(noOpColumn.name);
|
|
53
|
+
return ` ON DUPLICATE KEY UPDATE ${col} = ${col}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (clause.action.where) {
|
|
57
|
+
throw new Error('MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.');
|
|
58
|
+
}
|
|
59
|
+
if (!clause.action.set.length) {
|
|
60
|
+
throw new Error('MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const assignments = clause.action.set
|
|
64
|
+
.map(assignment => {
|
|
65
|
+
const target = this.quoteIdentifier(assignment.column.name);
|
|
66
|
+
const value = this.compileOperand(assignment.value, ctx);
|
|
67
|
+
return `${target} = ${value}`;
|
|
68
|
+
})
|
|
69
|
+
.join(', ');
|
|
70
|
+
return ` ON DUPLICATE KEY UPDATE ${assignments}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
compileProcedureCall(ast: ProcedureCallNode): CompiledProcedureCall {
|
|
74
|
+
const ctx = this.createCompilerContext();
|
|
75
|
+
const qualifiedName = ast.ref.schema
|
|
76
|
+
? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}`
|
|
77
|
+
: this.quoteIdentifier(ast.ref.name);
|
|
78
|
+
|
|
79
|
+
const prelude: string[] = [];
|
|
80
|
+
const callArgs: string[] = [];
|
|
81
|
+
const outVars: Array<{ variable: string; name: string }> = [];
|
|
82
|
+
|
|
83
|
+
ast.params.forEach((param, index) => {
|
|
84
|
+
const suffix = sanitizeVariableSuffix(param.name || `p${index + 1}`);
|
|
85
|
+
const variable = `@__metal_${suffix}_${index + 1}`;
|
|
86
|
+
|
|
87
|
+
if (param.direction === 'in') {
|
|
88
|
+
if (!param.value) {
|
|
89
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
|
|
90
|
+
}
|
|
91
|
+
callArgs.push(this.compileOperand(param.value, ctx));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (param.direction === 'inout') {
|
|
96
|
+
if (!param.value) {
|
|
97
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
|
|
98
|
+
}
|
|
99
|
+
prelude.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
callArgs.push(variable);
|
|
103
|
+
outVars.push({ variable, name: param.name });
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const statements: string[] = [];
|
|
107
|
+
if (prelude.length) {
|
|
108
|
+
statements.push(...prelude);
|
|
109
|
+
}
|
|
110
|
+
statements.push(`CALL ${qualifiedName}(${callArgs.join(', ')});`);
|
|
111
|
+
|
|
112
|
+
if (outVars.length) {
|
|
113
|
+
const selectOut = outVars
|
|
114
|
+
.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`)
|
|
115
|
+
.join(', ');
|
|
116
|
+
statements.push(`SELECT ${selectOut};`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
sql: statements.join(' '),
|
|
121
|
+
params: [...ctx.params],
|
|
122
|
+
outParams: {
|
|
123
|
+
source: outVars.length ? 'lastResultSet' : 'none',
|
|
124
|
+
names: outVars.map(item => item.name)
|
|
125
|
+
}
|
|
126
|
+
};
|
|
35
127
|
}
|
|
36
128
|
}
|
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
import { CompilerContext } from '../abstract.js';
|
|
1
|
+
import { CompilerContext, CompiledProcedureCall } from '../abstract.js';
|
|
2
2
|
import { JsonPathNode, ColumnNode, BitwiseExpressionNode } from '../../ast/expression.js';
|
|
3
|
-
import { TableNode } from '../../ast/query.js';
|
|
3
|
+
import { InsertQueryNode, TableNode } from '../../ast/query.js';
|
|
4
4
|
import { SqlDialectBase } from '../base/sql-dialect.js';
|
|
5
5
|
import { PostgresFunctionStrategy } from './functions.js';
|
|
6
6
|
import { PostgresTableFunctionStrategy } from './table-functions.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
* @
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
* @
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
7
|
+
import { ProcedureCallNode } from '../../ast/procedure.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* PostgreSQL dialect implementation
|
|
11
|
+
*/
|
|
12
|
+
export class PostgresDialect extends SqlDialectBase {
|
|
13
|
+
protected readonly dialect = 'postgres';
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new PostgresDialect instance
|
|
16
|
+
*/
|
|
17
|
+
public constructor() {
|
|
18
|
+
super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
|
|
19
|
+
this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
20
|
+
const left = this.compileOperand(node.left, ctx);
|
|
21
|
+
const right = this.compileOperand(node.right, ctx);
|
|
22
|
+
const op = node.operator === '^' ? '#' : node.operator;
|
|
23
|
+
return `${left} ${op} ${right}`;
|
|
24
|
+
});
|
|
25
|
+
this.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
26
|
+
const left = this.compileOperand(node.left, ctx);
|
|
27
|
+
const right = this.compileOperand(node.right, ctx);
|
|
28
|
+
const op = node.operator === '^' ? '#' : node.operator;
|
|
29
|
+
return `(${left} ${op} ${right})`;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Quotes an identifier using PostgreSQL double-quote syntax
|
|
35
|
+
* @param id - Identifier to quote
|
|
36
|
+
* @returns Quoted identifier
|
|
37
|
+
*/
|
|
38
|
+
quoteIdentifier(id: string): string {
|
|
39
|
+
return `"${id}"`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected formatPlaceholder(index: number): string {
|
|
43
|
+
return `$${index}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Compiles JSON path expression using PostgreSQL syntax
|
|
48
|
+
* @param node - JSON path node
|
|
49
|
+
* @returns PostgreSQL JSON path expression
|
|
50
|
+
*/
|
|
51
|
+
protected compileJsonPath(node: JsonPathNode): string {
|
|
52
|
+
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
53
|
+
// Postgres uses col->>'path' for text extraction
|
|
54
|
+
return `${col}->>'${node.path}'`;
|
|
55
|
+
}
|
|
56
|
+
|
|
56
57
|
protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
|
|
57
58
|
void ctx;
|
|
58
59
|
if (!returning || returning.length === 0) return '';
|
|
@@ -60,14 +61,74 @@ export class PostgresDialect extends SqlDialectBase {
|
|
|
60
61
|
return ` RETURNING ${columns}`;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
return
|
|
65
|
-
|
|
64
|
+
protected compileUpsertClause(ast: InsertQueryNode, ctx: CompilerContext): string {
|
|
65
|
+
if (!ast.onConflict) return '';
|
|
66
|
+
|
|
67
|
+
const clause = ast.onConflict;
|
|
68
|
+
const target = clause.target.constraint
|
|
69
|
+
? ` ON CONFLICT ON CONSTRAINT ${this.quoteIdentifier(clause.target.constraint)}`
|
|
70
|
+
: (() => {
|
|
71
|
+
this.ensureConflictColumns(
|
|
72
|
+
clause,
|
|
73
|
+
'PostgreSQL ON CONFLICT requires conflict columns or a constraint name.'
|
|
74
|
+
);
|
|
75
|
+
const cols = clause.target.columns.map(col => this.quoteIdentifier(col.name)).join(', ');
|
|
76
|
+
return ` ON CONFLICT (${cols})`;
|
|
77
|
+
})();
|
|
78
|
+
|
|
79
|
+
if (clause.action.type === 'DoNothing') {
|
|
80
|
+
return `${target} DO NOTHING`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!clause.action.set.length) {
|
|
84
|
+
throw new Error('PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.');
|
|
85
|
+
}
|
|
66
86
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return
|
|
87
|
+
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
88
|
+
const where = clause.action.where
|
|
89
|
+
? ` WHERE ${this.compileExpression(clause.action.where, ctx)}`
|
|
90
|
+
: '';
|
|
91
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
72
92
|
}
|
|
73
|
-
|
|
93
|
+
|
|
94
|
+
supportsDmlReturningClause(): boolean {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
compileProcedureCall(ast: ProcedureCallNode): CompiledProcedureCall {
|
|
99
|
+
const ctx = this.createCompilerContext();
|
|
100
|
+
const qualifiedName = ast.ref.schema
|
|
101
|
+
? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}`
|
|
102
|
+
: this.quoteIdentifier(ast.ref.name);
|
|
103
|
+
|
|
104
|
+
const args: string[] = [];
|
|
105
|
+
for (const param of ast.params) {
|
|
106
|
+
if (param.direction === 'out') continue;
|
|
107
|
+
if (!param.value) {
|
|
108
|
+
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
|
|
109
|
+
}
|
|
110
|
+
args.push(this.compileOperand(param.value, ctx));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const outNames = ast.params
|
|
114
|
+
.filter(param => param.direction === 'out' || param.direction === 'inout')
|
|
115
|
+
.map(param => param.name);
|
|
116
|
+
|
|
117
|
+
const rawSql = `CALL ${qualifiedName}(${args.join(', ')})`;
|
|
118
|
+
return {
|
|
119
|
+
sql: `${rawSql};`,
|
|
120
|
+
params: [...ctx.params],
|
|
121
|
+
outParams: {
|
|
122
|
+
source: outNames.length ? 'firstResultSet' : 'none',
|
|
123
|
+
names: outNames
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* PostgreSQL requires unqualified column names in SET clause
|
|
130
|
+
*/
|
|
131
|
+
protected compileSetTarget(column: ColumnNode, _table: TableNode): string {
|
|
132
|
+
return this.quoteIdentifier(column.name);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -1,69 +1,70 @@
|
|
|
1
|
-
import { CompilerContext } from '../abstract.js';
|
|
1
|
+
import { CompilerContext, CompiledProcedureCall } from '../abstract.js';
|
|
2
2
|
import { JsonPathNode, ColumnNode, BitwiseExpressionNode } from '../../ast/expression.js';
|
|
3
|
-
import { TableNode } from '../../ast/query.js';
|
|
3
|
+
import { InsertQueryNode, TableNode } from '../../ast/query.js';
|
|
4
4
|
import { SqlDialectBase } from '../base/sql-dialect.js';
|
|
5
5
|
import { SqliteFunctionStrategy } from './functions.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
* @
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
* @
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
6
|
+
import { ProcedureCallNode } from '../../ast/procedure.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SQLite dialect implementation
|
|
10
|
+
*/
|
|
11
|
+
export class SqliteDialect extends SqlDialectBase {
|
|
12
|
+
protected readonly dialect = 'sqlite';
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new SqliteDialect instance
|
|
15
|
+
*/
|
|
16
|
+
public constructor() {
|
|
17
|
+
super(new SqliteFunctionStrategy());
|
|
18
|
+
this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
19
|
+
const left = this.compileOperand(node.left, ctx);
|
|
20
|
+
const right = this.compileOperand(node.right, ctx);
|
|
21
|
+
if (node.operator === '^') {
|
|
22
|
+
return `(${left} | ${right}) & ~(${left} & ${right})`;
|
|
23
|
+
}
|
|
24
|
+
return `${left} ${node.operator} ${right}`;
|
|
25
|
+
});
|
|
26
|
+
this.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
27
|
+
const left = this.compileOperand(node.left, ctx);
|
|
28
|
+
const right = this.compileOperand(node.right, ctx);
|
|
29
|
+
if (node.operator === '^') {
|
|
30
|
+
return `((${left} | ${right}) & ~(${left} & ${right}))`;
|
|
31
|
+
}
|
|
32
|
+
return `(${left} ${node.operator} ${right})`;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Quotes an identifier using SQLite double-quote syntax
|
|
38
|
+
* @param id - Identifier to quote
|
|
39
|
+
* @returns Quoted identifier
|
|
40
|
+
*/
|
|
41
|
+
quoteIdentifier(id: string): string {
|
|
42
|
+
return `"${id}"`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Compiles JSON path expression using SQLite syntax
|
|
47
|
+
* @param node - JSON path node
|
|
48
|
+
* @returns SQLite JSON path expression
|
|
49
|
+
*/
|
|
50
|
+
protected compileJsonPath(node: JsonPathNode): string {
|
|
51
|
+
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
52
|
+
// SQLite uses json_extract(col, '$.path')
|
|
53
|
+
return `json_extract(${col}, '${node.path}')`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected compileQualifiedColumn(column: ColumnNode, _table: TableNode): string {
|
|
57
|
+
void _table;
|
|
58
|
+
return this.quoteIdentifier(column.name);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
|
|
62
|
+
void ctx;
|
|
63
|
+
if (!returning || returning.length === 0) return '';
|
|
64
|
+
const columns = this.formatReturningColumns(returning);
|
|
65
|
+
return ` RETURNING ${columns}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
67
68
|
protected formatReturningColumns(returning: ColumnNode[]): string {
|
|
68
69
|
return returning
|
|
69
70
|
.map(column => {
|
|
@@ -73,7 +74,39 @@ export class SqliteDialect extends SqlDialectBase {
|
|
|
73
74
|
.join(', ');
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
protected compileUpsertClause(ast: InsertQueryNode, ctx: CompilerContext): string {
|
|
78
|
+
if (!ast.onConflict) return '';
|
|
79
|
+
|
|
80
|
+
const clause = ast.onConflict;
|
|
81
|
+
if (clause.target.constraint) {
|
|
82
|
+
throw new Error('SQLite ON CONFLICT does not support named constraints.');
|
|
83
|
+
}
|
|
84
|
+
this.ensureConflictColumns(clause, 'SQLite ON CONFLICT requires conflict columns.');
|
|
85
|
+
|
|
86
|
+
const cols = clause.target.columns.map(col => this.quoteIdentifier(col.name)).join(', ');
|
|
87
|
+
const target = ` ON CONFLICT (${cols})`;
|
|
88
|
+
|
|
89
|
+
if (clause.action.type === 'DoNothing') {
|
|
90
|
+
return `${target} DO NOTHING`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!clause.action.set.length) {
|
|
94
|
+
throw new Error('SQLite ON CONFLICT DO UPDATE requires at least one assignment.');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
98
|
+
const where = clause.action.where
|
|
99
|
+
? ` WHERE ${this.compileExpression(clause.action.where, ctx)}`
|
|
100
|
+
: '';
|
|
101
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
76
104
|
supportsDmlReturningClause(): boolean {
|
|
77
105
|
return true;
|
|
78
106
|
}
|
|
79
|
-
|
|
107
|
+
|
|
108
|
+
compileProcedureCall(_ast: ProcedureCallNode): CompiledProcedureCall {
|
|
109
|
+
void _ast;
|
|
110
|
+
throw new Error('Stored procedures are not supported by the SQLite dialect.');
|
|
111
|
+
}
|
|
112
|
+
}
|