metal-orm 1.1.24 → 1.1.26
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/dist/index.cjs +770 -710
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +294 -318
- package/dist/index.d.ts +294 -318
- package/dist/index.js +745 -709
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/dialect/abstract.ts +7 -229
- package/src/core/dialect/base/returning-strategy.ts +40 -39
- package/src/core/dialect/base/sql-compiler-set.ts +33 -0
- package/src/core/dialect/base/sql-dialect-composer.ts +294 -0
- package/src/core/dialect/base/standard-sql-services.ts +2 -6
- package/src/core/dialect/base/upsert-strategy.ts +44 -0
- package/src/core/dialect/capabilities/procedure-compiler.ts +10 -8
- package/src/core/dialect/dialect-factory.ts +17 -49
- package/src/core/dialect/mssql/compiler-factory.ts +12 -0
- package/src/core/dialect/mssql/delete-compiler.ts +40 -0
- package/src/core/dialect/mssql/index.ts +52 -370
- package/src/core/dialect/mssql/insert-compiler.ts +112 -0
- package/src/core/dialect/mssql/output.ts +46 -0
- package/src/core/dialect/mssql/procedure-compiler.ts +81 -0
- package/src/core/dialect/mssql/select-compiler.ts +116 -0
- package/src/core/dialect/mssql/update-compiler.ts +37 -0
- package/src/core/dialect/mysql/index.ts +66 -126
- package/src/core/dialect/mysql/procedure-compiler.ts +67 -0
- package/src/core/dialect/mysql/upsert.ts +42 -0
- package/src/core/dialect/postgres/index.ts +75 -114
- package/src/core/dialect/postgres/procedure-compiler.ts +41 -0
- package/src/core/dialect/postgres/returning.ts +4 -0
- package/src/core/dialect/postgres/upsert.ts +43 -0
- package/src/core/dialect/sqlite/index.ts +65 -90
- package/src/core/dialect/sqlite/returning.ts +30 -0
- package/src/core/dialect/sqlite/upsert.ts +43 -0
- package/src/index.ts +22 -10
- package/src/core/dialect/base/sql-dialect.ts +0 -176
|
@@ -1,135 +1,96 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ProcedureCallNode } from '../../ast/procedure.js';
|
|
2
|
+
import type { BitwiseExpressionNode, ColumnNode, JsonPathNode } from '../../ast/expression.js';
|
|
3
|
+
import type {
|
|
4
|
+
DeleteQueryNode,
|
|
5
|
+
InsertQueryNode,
|
|
6
|
+
SelectQueryNode,
|
|
7
|
+
TableNode,
|
|
8
|
+
UpdateQueryNode
|
|
9
|
+
} from '../../ast/query.js';
|
|
10
|
+
import type { CompiledQuery, Dialect } from '../abstract.js';
|
|
2
11
|
import type { CompiledProcedureCall, ProcedureCompiler } from '../capabilities/procedure-compiler.js';
|
|
3
|
-
import {
|
|
4
|
-
import { InsertQueryNode, TableNode } from '../../ast/query.js';
|
|
5
|
-
import { SqlDialectBase } from '../base/sql-dialect.js';
|
|
12
|
+
import { composeSqlDialect } from '../base/sql-dialect-composer.js';
|
|
6
13
|
import { PostgresFunctionStrategy } from './functions.js';
|
|
7
14
|
import { PostgresTableFunctionStrategy } from './table-functions.js';
|
|
8
|
-
import {
|
|
15
|
+
import { PostgresProcedureCompiler } from './procedure-compiler.js';
|
|
16
|
+
import { PostgresReturningStrategy } from './returning.js';
|
|
17
|
+
import { PostgresUpsertStrategy } from './upsert.js';
|
|
18
|
+
|
|
19
|
+
const quoteIdentifier = (id: string): string => `"${id}"`;
|
|
20
|
+
|
|
21
|
+
export type PostgresDialectImplementation = Dialect & ProcedureCompiler;
|
|
22
|
+
|
|
23
|
+
/** Creates the PostgreSQL dialect entirely from composable compiler components. */
|
|
24
|
+
export const createPostgresDialect = (): PostgresDialectImplementation => {
|
|
25
|
+
const composition = composeSqlDialect({
|
|
26
|
+
name: 'postgres',
|
|
27
|
+
quoteIdentifier,
|
|
28
|
+
formatPlaceholder: index => `$${index}`,
|
|
29
|
+
functionStrategy: new PostgresFunctionStrategy(),
|
|
30
|
+
tableFunctionStrategy: new PostgresTableFunctionStrategy(),
|
|
31
|
+
returningStrategy: new PostgresReturningStrategy(),
|
|
32
|
+
upsertStrategy: new PostgresUpsertStrategy(),
|
|
33
|
+
supportsDmlReturning: true,
|
|
34
|
+
compileSetTarget: (column: ColumnNode, _table: TableNode) => {
|
|
35
|
+
void _table;
|
|
36
|
+
return quoteIdentifier(column.name);
|
|
37
|
+
},
|
|
38
|
+
compileJsonPath(node: JsonPathNode): string {
|
|
39
|
+
const column = `${quoteIdentifier(node.column.table)}.${quoteIdentifier(node.column.name)}`;
|
|
40
|
+
return `${column}->>'${node.path}'`;
|
|
41
|
+
},
|
|
42
|
+
configureExpressions(api) {
|
|
43
|
+
api.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
44
|
+
const left = api.compileOperand(node.left, ctx);
|
|
45
|
+
const right = api.compileOperand(node.right, ctx);
|
|
46
|
+
const operator = node.operator === '^' ? '#' : node.operator;
|
|
47
|
+
return `${left} ${operator} ${right}`;
|
|
48
|
+
});
|
|
49
|
+
api.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
50
|
+
const left = api.compileOperand(node.left, ctx);
|
|
51
|
+
const right = api.compileOperand(node.right, ctx);
|
|
52
|
+
const operator = node.operator === '^' ? '#' : node.operator;
|
|
53
|
+
return `(${left} ${operator} ${right})`;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
9
57
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
21
|
-
const left = this.compileOperand(node.left, ctx);
|
|
22
|
-
const right = this.compileOperand(node.right, ctx);
|
|
23
|
-
const op = node.operator === '^' ? '#' : node.operator;
|
|
24
|
-
return `${left} ${op} ${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
|
-
const op = node.operator === '^' ? '#' : node.operator;
|
|
30
|
-
return `(${left} ${op} ${right})`;
|
|
31
|
-
});
|
|
32
|
-
}
|
|
58
|
+
const procedures = new PostgresProcedureCompiler(composition.runtime);
|
|
59
|
+
return {
|
|
60
|
+
...composition.dialect,
|
|
61
|
+
compileProcedureCall: ast => procedures.compileProcedureCall(ast)
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** Ergonomic constructor facade over the composed PostgreSQL dialect. */
|
|
66
|
+
export class PostgresDialect implements Dialect, ProcedureCompiler {
|
|
67
|
+
private readonly impl: PostgresDialectImplementation = createPostgresDialect();
|
|
33
68
|
|
|
34
|
-
/**
|
|
35
|
-
* Quotes an identifier using PostgreSQL double-quote syntax
|
|
36
|
-
* @param id - Identifier to quote
|
|
37
|
-
* @returns Quoted identifier
|
|
38
|
-
*/
|
|
39
69
|
quoteIdentifier(id: string): string {
|
|
40
|
-
return
|
|
70
|
+
return this.impl.quoteIdentifier(id);
|
|
41
71
|
}
|
|
42
72
|
|
|
43
|
-
|
|
44
|
-
return
|
|
73
|
+
supportsDmlReturningClause(): boolean {
|
|
74
|
+
return this.impl.supportsDmlReturningClause();
|
|
45
75
|
}
|
|
46
76
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* @param node - JSON path node
|
|
50
|
-
* @returns PostgreSQL JSON path expression
|
|
51
|
-
*/
|
|
52
|
-
protected compileJsonPath(node: JsonPathNode): string {
|
|
53
|
-
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
54
|
-
// Postgres uses col->>'path' for text extraction
|
|
55
|
-
return `${col}->>'${node.path}'`;
|
|
77
|
+
compileSelect(ast: SelectQueryNode): CompiledQuery {
|
|
78
|
+
return this.impl.compileSelect(ast);
|
|
56
79
|
}
|
|
57
80
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!returning || returning.length === 0) return '';
|
|
61
|
-
const columns = this.formatReturningColumns(returning);
|
|
62
|
-
return ` RETURNING ${columns}`;
|
|
81
|
+
compileInsert(ast: InsertQueryNode): CompiledQuery {
|
|
82
|
+
return this.impl.compileInsert(ast);
|
|
63
83
|
}
|
|
64
84
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const clause = ast.onConflict;
|
|
69
|
-
const target = clause.target.constraint
|
|
70
|
-
? ` ON CONFLICT ON CONSTRAINT ${this.quoteIdentifier(clause.target.constraint)}`
|
|
71
|
-
: (() => {
|
|
72
|
-
this.ensureConflictColumns(
|
|
73
|
-
clause,
|
|
74
|
-
'PostgreSQL ON CONFLICT requires conflict columns or a constraint name.'
|
|
75
|
-
);
|
|
76
|
-
const cols = clause.target.columns.map(col => this.quoteIdentifier(col.name)).join(', ');
|
|
77
|
-
return ` ON CONFLICT (${cols})`;
|
|
78
|
-
})();
|
|
79
|
-
|
|
80
|
-
if (clause.action.type === 'DoNothing') {
|
|
81
|
-
return `${target} DO NOTHING`;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!clause.action.set.length) {
|
|
85
|
-
throw new Error('PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
89
|
-
const where = clause.action.where
|
|
90
|
-
? ` WHERE ${this.compileExpression(clause.action.where, ctx)}`
|
|
91
|
-
: '';
|
|
92
|
-
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
85
|
+
compileUpdate(ast: UpdateQueryNode): CompiledQuery {
|
|
86
|
+
return this.impl.compileUpdate(ast);
|
|
93
87
|
}
|
|
94
88
|
|
|
95
|
-
|
|
96
|
-
return
|
|
89
|
+
compileDelete(ast: DeleteQueryNode): CompiledQuery {
|
|
90
|
+
return this.impl.compileDelete(ast);
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
compileProcedureCall(ast: ProcedureCallNode): CompiledProcedureCall {
|
|
100
|
-
|
|
101
|
-
const qualifiedName = ast.ref.schema
|
|
102
|
-
? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}`
|
|
103
|
-
: this.quoteIdentifier(ast.ref.name);
|
|
104
|
-
|
|
105
|
-
const args: string[] = [];
|
|
106
|
-
for (const param of ast.params) {
|
|
107
|
-
if (param.direction === 'out') continue;
|
|
108
|
-
if (!param.value) {
|
|
109
|
-
throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
|
|
110
|
-
}
|
|
111
|
-
args.push(this.compileOperand(param.value, ctx));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const outNames = ast.params
|
|
115
|
-
.filter(param => param.direction === 'out' || param.direction === 'inout')
|
|
116
|
-
.map(param => param.name);
|
|
117
|
-
|
|
118
|
-
const rawSql = `CALL ${qualifiedName}(${args.join(', ')})`;
|
|
119
|
-
return {
|
|
120
|
-
sql: `${rawSql};`,
|
|
121
|
-
params: [...ctx.params],
|
|
122
|
-
outParams: {
|
|
123
|
-
source: outNames.length ? 'firstResultSet' : 'none',
|
|
124
|
-
names: outNames
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* PostgreSQL requires unqualified column names in SET clause
|
|
131
|
-
*/
|
|
132
|
-
protected compileSetTarget(column: ColumnNode, _table: TableNode): string {
|
|
133
|
-
return this.quoteIdentifier(column.name);
|
|
94
|
+
return this.impl.compileProcedureCall(ast);
|
|
134
95
|
}
|
|
135
96
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ProcedureCallNode } from '../../ast/procedure.js';
|
|
2
|
+
import type {
|
|
3
|
+
CompiledProcedureCall,
|
|
4
|
+
ProcedureCompiler,
|
|
5
|
+
ProcedureCompilerServices
|
|
6
|
+
} from '../capabilities/procedure-compiler.js';
|
|
7
|
+
|
|
8
|
+
export class PostgresProcedureCompiler implements ProcedureCompiler {
|
|
9
|
+
constructor(private readonly services: ProcedureCompilerServices) {}
|
|
10
|
+
|
|
11
|
+
compileProcedureCall(ast: ProcedureCallNode): CompiledProcedureCall {
|
|
12
|
+
const ctx = this.services.createCompilerContext();
|
|
13
|
+
const qualifiedName = ast.ref.schema
|
|
14
|
+
? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}`
|
|
15
|
+
: this.services.quoteIdentifier(ast.ref.name);
|
|
16
|
+
|
|
17
|
+
const args: string[] = [];
|
|
18
|
+
for (const param of ast.params) {
|
|
19
|
+
if (param.direction === 'out') continue;
|
|
20
|
+
if (!param.value) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
args.push(this.services.compileOperand(param.value, ctx));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const outNames = ast.params
|
|
29
|
+
.filter(param => param.direction === 'out' || param.direction === 'inout')
|
|
30
|
+
.map(param => param.name);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
sql: `CALL ${qualifiedName}(${args.join(', ')});`,
|
|
34
|
+
params: [...ctx.params],
|
|
35
|
+
outParams: {
|
|
36
|
+
source: outNames.length ? 'firstResultSet' : 'none',
|
|
37
|
+
names: outNames
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CompilerContext } from '../abstract.js';
|
|
2
|
+
import type { InsertQueryNode } from '../../ast/query.js';
|
|
3
|
+
import type {
|
|
4
|
+
UpsertCompilationServices,
|
|
5
|
+
UpsertStrategy
|
|
6
|
+
} from '../base/upsert-strategy.js';
|
|
7
|
+
|
|
8
|
+
export class PostgresUpsertStrategy implements UpsertStrategy {
|
|
9
|
+
compile(
|
|
10
|
+
ast: InsertQueryNode,
|
|
11
|
+
ctx: CompilerContext,
|
|
12
|
+
services: UpsertCompilationServices
|
|
13
|
+
): string {
|
|
14
|
+
if (!ast.onConflict) return '';
|
|
15
|
+
|
|
16
|
+
const clause = ast.onConflict;
|
|
17
|
+
const target = clause.target.constraint
|
|
18
|
+
? ` ON CONFLICT ON CONSTRAINT ${services.quoteIdentifier(clause.target.constraint)}`
|
|
19
|
+
: (() => {
|
|
20
|
+
if (!clause.target.columns.length) {
|
|
21
|
+
throw new Error('PostgreSQL ON CONFLICT requires conflict columns or a constraint name.');
|
|
22
|
+
}
|
|
23
|
+
const columns = clause.target.columns
|
|
24
|
+
.map(column => services.quoteIdentifier(column.name))
|
|
25
|
+
.join(', ');
|
|
26
|
+
return ` ON CONFLICT (${columns})`;
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
if (clause.action.type === 'DoNothing') {
|
|
30
|
+
return `${target} DO NOTHING`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!clause.action.set.length) {
|
|
34
|
+
throw new Error('PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const assignments = services.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
38
|
+
const where = clause.action.where
|
|
39
|
+
? ` WHERE ${services.compileExpression(clause.action.where, ctx)}`
|
|
40
|
+
: '';
|
|
41
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,106 +1,81 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { BitwiseExpressionNode, ColumnNode, JsonPathNode } from '../../ast/expression.js';
|
|
2
|
+
import type {
|
|
3
|
+
DeleteQueryNode,
|
|
4
|
+
InsertQueryNode,
|
|
5
|
+
SelectQueryNode,
|
|
6
|
+
TableNode,
|
|
7
|
+
UpdateQueryNode
|
|
8
|
+
} from '../../ast/query.js';
|
|
9
|
+
import type { CompiledQuery, Dialect } from '../abstract.js';
|
|
10
|
+
import { composeSqlDialect } from '../base/sql-dialect-composer.js';
|
|
5
11
|
import { SqliteFunctionStrategy } from './functions.js';
|
|
12
|
+
import { SqliteReturningStrategy } from './returning.js';
|
|
13
|
+
import { SqliteUpsertStrategy } from './upsert.js';
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
* SQLite dialect implementation
|
|
9
|
-
*/
|
|
10
|
-
export class SqliteDialect extends SqlDialectBase {
|
|
11
|
-
protected readonly dialect = 'sqlite';
|
|
12
|
-
/**
|
|
13
|
-
* Creates a new SqliteDialect instance
|
|
14
|
-
*/
|
|
15
|
-
public constructor() {
|
|
16
|
-
super(new SqliteFunctionStrategy());
|
|
17
|
-
this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
18
|
-
const left = this.compileOperand(node.left, ctx);
|
|
19
|
-
const right = this.compileOperand(node.right, ctx);
|
|
20
|
-
if (node.operator === '^') {
|
|
21
|
-
return `(${left} | ${right}) & ~(${left} & ${right})`;
|
|
22
|
-
}
|
|
23
|
-
return `${left} ${node.operator} ${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
|
-
if (node.operator === '^') {
|
|
29
|
-
return `((${left} | ${right}) & ~(${left} & ${right}))`;
|
|
30
|
-
}
|
|
31
|
-
return `(${left} ${node.operator} ${right})`;
|
|
32
|
-
});
|
|
33
|
-
}
|
|
15
|
+
const quoteIdentifier = (id: string): string => `"${id}"`;
|
|
34
16
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
17
|
+
/** Creates the SQLite dialect entirely from composable compiler components. */
|
|
18
|
+
export const createSqliteDialect = (): Dialect =>
|
|
19
|
+
composeSqlDialect({
|
|
20
|
+
name: 'sqlite',
|
|
21
|
+
quoteIdentifier,
|
|
22
|
+
functionStrategy: new SqliteFunctionStrategy(),
|
|
23
|
+
returningStrategy: new SqliteReturningStrategy(),
|
|
24
|
+
upsertStrategy: new SqliteUpsertStrategy(),
|
|
25
|
+
supportsDmlReturning: true,
|
|
26
|
+
compileSetTarget: (column: ColumnNode, _table: TableNode) => {
|
|
27
|
+
void _table;
|
|
28
|
+
return quoteIdentifier(column.name);
|
|
29
|
+
},
|
|
30
|
+
compileJsonPath(node: JsonPathNode): string {
|
|
31
|
+
const column = `${quoteIdentifier(node.column.table)}.${quoteIdentifier(node.column.name)}`;
|
|
32
|
+
return `json_extract(${column}, '${node.path}')`;
|
|
33
|
+
},
|
|
34
|
+
configureExpressions(api) {
|
|
35
|
+
api.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
36
|
+
const left = api.compileOperand(node.left, ctx);
|
|
37
|
+
const right = api.compileOperand(node.right, ctx);
|
|
38
|
+
if (node.operator === '^') {
|
|
39
|
+
return `(${left} | ${right}) & ~(${left} & ${right})`;
|
|
40
|
+
}
|
|
41
|
+
return `${left} ${node.operator} ${right}`;
|
|
42
|
+
});
|
|
43
|
+
api.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
|
|
44
|
+
const left = api.compileOperand(node.left, ctx);
|
|
45
|
+
const right = api.compileOperand(node.right, ctx);
|
|
46
|
+
if (node.operator === '^') {
|
|
47
|
+
return `((${left} | ${right}) & ~(${left} & ${right}))`;
|
|
48
|
+
}
|
|
49
|
+
return `(${left} ${node.operator} ${right})`;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}).dialect;
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* @returns SQLite JSON path expression
|
|
48
|
-
*/
|
|
49
|
-
protected compileJsonPath(node: JsonPathNode): string {
|
|
50
|
-
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
51
|
-
// SQLite uses json_extract(col, '$.path')
|
|
52
|
-
return `json_extract(${col}, '${node.path}')`;
|
|
53
|
-
}
|
|
54
|
+
/** Ergonomic constructor facade over the composed SQLite dialect. */
|
|
55
|
+
export class SqliteDialect implements Dialect {
|
|
56
|
+
private readonly impl: Dialect = createSqliteDialect();
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return this.quoteIdentifier(column.name);
|
|
58
|
+
quoteIdentifier(id: string): string {
|
|
59
|
+
return this.impl.quoteIdentifier(id);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!returning || returning.length === 0) return '';
|
|
63
|
-
const columns = this.formatReturningColumns(returning);
|
|
64
|
-
return ` RETURNING ${columns}`;
|
|
62
|
+
supportsDmlReturningClause(): boolean {
|
|
63
|
+
return this.impl.supportsDmlReturningClause();
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
return
|
|
69
|
-
.map(column => {
|
|
70
|
-
const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : '';
|
|
71
|
-
return `${this.quoteIdentifier(column.name)}${alias}`;
|
|
72
|
-
})
|
|
73
|
-
.join(', ');
|
|
66
|
+
compileSelect(ast: SelectQueryNode): CompiledQuery {
|
|
67
|
+
return this.impl.compileSelect(ast);
|
|
74
68
|
}
|
|
75
69
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const clause = ast.onConflict;
|
|
80
|
-
if (clause.target.constraint) {
|
|
81
|
-
throw new Error('SQLite ON CONFLICT does not support named constraints.');
|
|
82
|
-
}
|
|
83
|
-
this.ensureConflictColumns(clause, 'SQLite ON CONFLICT requires conflict columns.');
|
|
84
|
-
|
|
85
|
-
const cols = clause.target.columns.map(col => this.quoteIdentifier(col.name)).join(', ');
|
|
86
|
-
const target = ` ON CONFLICT (${cols})`;
|
|
87
|
-
|
|
88
|
-
if (clause.action.type === 'DoNothing') {
|
|
89
|
-
return `${target} DO NOTHING`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (!clause.action.set.length) {
|
|
93
|
-
throw new Error('SQLite ON CONFLICT DO UPDATE requires at least one assignment.');
|
|
94
|
-
}
|
|
70
|
+
compileInsert(ast: InsertQueryNode): CompiledQuery {
|
|
71
|
+
return this.impl.compileInsert(ast);
|
|
72
|
+
}
|
|
95
73
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
? ` WHERE ${this.compileExpression(clause.action.where, ctx)}`
|
|
99
|
-
: '';
|
|
100
|
-
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
74
|
+
compileUpdate(ast: UpdateQueryNode): CompiledQuery {
|
|
75
|
+
return this.impl.compileUpdate(ast);
|
|
101
76
|
}
|
|
102
77
|
|
|
103
|
-
|
|
104
|
-
return
|
|
78
|
+
compileDelete(ast: DeleteQueryNode): CompiledQuery {
|
|
79
|
+
return this.impl.compileDelete(ast);
|
|
105
80
|
}
|
|
106
81
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ColumnNode } from '../../ast/expression.js';
|
|
2
|
+
import type { CompilerContext } from '../abstract.js';
|
|
3
|
+
import type {
|
|
4
|
+
QuoteIdentifier,
|
|
5
|
+
ReturningStrategy
|
|
6
|
+
} from '../base/returning-strategy.js';
|
|
7
|
+
|
|
8
|
+
export class SqliteReturningStrategy implements ReturningStrategy {
|
|
9
|
+
compileReturning(
|
|
10
|
+
returning: ColumnNode[] | undefined,
|
|
11
|
+
_ctx: CompilerContext,
|
|
12
|
+
quoteIdentifier: QuoteIdentifier
|
|
13
|
+
): string {
|
|
14
|
+
void _ctx;
|
|
15
|
+
if (!returning || returning.length === 0) return '';
|
|
16
|
+
return ` RETURNING ${this.formatReturningColumns(returning, quoteIdentifier)}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
formatReturningColumns(
|
|
20
|
+
returning: ColumnNode[],
|
|
21
|
+
quoteIdentifier: QuoteIdentifier
|
|
22
|
+
): string {
|
|
23
|
+
return returning
|
|
24
|
+
.map(column => {
|
|
25
|
+
const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : '';
|
|
26
|
+
return `${quoteIdentifier(column.name)}${alias}`;
|
|
27
|
+
})
|
|
28
|
+
.join(', ');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CompilerContext } from '../abstract.js';
|
|
2
|
+
import type { InsertQueryNode } from '../../ast/query.js';
|
|
3
|
+
import type {
|
|
4
|
+
UpsertCompilationServices,
|
|
5
|
+
UpsertStrategy
|
|
6
|
+
} from '../base/upsert-strategy.js';
|
|
7
|
+
|
|
8
|
+
export class SqliteUpsertStrategy implements UpsertStrategy {
|
|
9
|
+
compile(
|
|
10
|
+
ast: InsertQueryNode,
|
|
11
|
+
ctx: CompilerContext,
|
|
12
|
+
services: UpsertCompilationServices
|
|
13
|
+
): string {
|
|
14
|
+
if (!ast.onConflict) return '';
|
|
15
|
+
|
|
16
|
+
const clause = ast.onConflict;
|
|
17
|
+
if (clause.target.constraint) {
|
|
18
|
+
throw new Error('SQLite ON CONFLICT does not support named constraints.');
|
|
19
|
+
}
|
|
20
|
+
if (!clause.target.columns.length) {
|
|
21
|
+
throw new Error('SQLite ON CONFLICT requires conflict columns.');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const columns = clause.target.columns
|
|
25
|
+
.map(column => services.quoteIdentifier(column.name))
|
|
26
|
+
.join(', ');
|
|
27
|
+
const target = ` ON CONFLICT (${columns})`;
|
|
28
|
+
|
|
29
|
+
if (clause.action.type === 'DoNothing') {
|
|
30
|
+
return `${target} DO NOTHING`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!clause.action.set.length) {
|
|
34
|
+
throw new Error('SQLite ON CONFLICT DO UPDATE requires at least one assignment.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const assignments = services.compileUpdateAssignments(clause.action.set, ast.into, ctx);
|
|
38
|
+
const where = clause.action.where
|
|
39
|
+
? ` WHERE ${services.compileExpression(clause.action.where, ctx)}`
|
|
40
|
+
: '';
|
|
41
|
+
return `${target} DO UPDATE SET ${assignments}${where}`;
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -20,16 +20,37 @@ export * from './core/hydration/types.js';
|
|
|
20
20
|
export * from './core/dialect/abstract.js';
|
|
21
21
|
export * from './core/dialect/dialect-factory.js';
|
|
22
22
|
export * from './core/dialect/capabilities/procedure-compiler.js';
|
|
23
|
+
export * from './core/dialect/base/sql-dialect-composer.js';
|
|
24
|
+
export * from './core/dialect/base/sql-compiler-set.js';
|
|
25
|
+
export * from './core/dialect/base/upsert-strategy.js';
|
|
26
|
+
export * from './core/dialect/base/returning-strategy.js';
|
|
27
|
+
export * from './core/dialect/base/pagination-strategy.js';
|
|
23
28
|
export * from './core/dialect/base/standard-sql-services.js';
|
|
24
29
|
export * from './core/dialect/base/standard-sql-source-compiler.js';
|
|
25
30
|
export * from './core/dialect/base/standard-select-compiler.js';
|
|
26
31
|
export * from './core/dialect/base/standard-insert-compiler.js';
|
|
27
32
|
export * from './core/dialect/base/standard-update-compiler.js';
|
|
28
33
|
export * from './core/dialect/base/standard-delete-compiler.js';
|
|
34
|
+
export * from './core/functions/table-types.js';
|
|
35
|
+
export * from './core/functions/standard-table-strategy.js';
|
|
29
36
|
export * from './core/dialect/mysql/index.js';
|
|
37
|
+
export * from './core/dialect/mysql/upsert.js';
|
|
38
|
+
export * from './core/dialect/mysql/procedure-compiler.js';
|
|
30
39
|
export * from './core/dialect/mssql/index.js';
|
|
40
|
+
export * from './core/dialect/mssql/compiler-factory.js';
|
|
41
|
+
export * from './core/dialect/mssql/select-compiler.js';
|
|
42
|
+
export * from './core/dialect/mssql/insert-compiler.js';
|
|
43
|
+
export * from './core/dialect/mssql/update-compiler.js';
|
|
44
|
+
export * from './core/dialect/mssql/delete-compiler.js';
|
|
45
|
+
export * from './core/dialect/mssql/output.js';
|
|
46
|
+
export * from './core/dialect/mssql/procedure-compiler.js';
|
|
31
47
|
export * from './core/dialect/sqlite/index.js';
|
|
48
|
+
export * from './core/dialect/sqlite/upsert.js';
|
|
49
|
+
export * from './core/dialect/sqlite/returning.js';
|
|
32
50
|
export * from './core/dialect/postgres/index.js';
|
|
51
|
+
export * from './core/dialect/postgres/upsert.js';
|
|
52
|
+
export * from './core/dialect/postgres/returning.js';
|
|
53
|
+
export * from './core/dialect/postgres/procedure-compiler.js';
|
|
33
54
|
export * from './core/ddl/schema-generator.js';
|
|
34
55
|
export * from './core/ddl/schema-types.js';
|
|
35
56
|
export * from './core/ddl/schema-diff.js';
|
|
@@ -71,7 +92,7 @@ export * from './orm/jsonify.js';
|
|
|
71
92
|
export * from './orm/save-graph-types.js';
|
|
72
93
|
export * from './decorators/index.js';
|
|
73
94
|
|
|
74
|
-
//
|
|
95
|
+
// Execution abstraction + helpers
|
|
75
96
|
export * from './core/execution/db-executor.js';
|
|
76
97
|
export * from './core/execution/pooling/pool-types.js';
|
|
77
98
|
export * from './core/execution/pooling/pool.js';
|
|
@@ -81,17 +102,8 @@ export * from './core/execution/executors/sqlite-executor.js';
|
|
|
81
102
|
export * from './core/execution/executors/better-sqlite3-executor.js';
|
|
82
103
|
export * from './core/execution/executors/mssql-executor.js';
|
|
83
104
|
|
|
84
|
-
// NEW: first-class pooling integration
|
|
85
105
|
export * from './orm/pooled-executor-factory.js';
|
|
86
|
-
|
|
87
|
-
// DTO module for REST API integration
|
|
88
106
|
export * from './dto/index.js';
|
|
89
|
-
|
|
90
|
-
// Tree behavior (Nested Set / MPTT)
|
|
91
107
|
export * from './tree/index.js';
|
|
92
|
-
|
|
93
|
-
// Cache module
|
|
94
108
|
export * from './cache/index.js';
|
|
95
|
-
|
|
96
|
-
// Bulk operations module
|
|
97
109
|
export * from './bulk/index.js';
|