metal-orm 1.1.21 → 1.1.23
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 +379 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -173
- package/dist/index.d.ts +145 -173
- package/dist/index.js +374 -474
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ddl/introspect/catalogs/mssql.ts +0 -8
- package/src/core/ddl/introspect/catalogs/mysql.ts +0 -5
- package/src/core/ddl/introspect/catalogs/postgres.ts +0 -9
- package/src/core/ddl/introspect/catalogs/sqlite.ts +0 -3
- package/src/core/dialect/abstract.ts +94 -417
- package/src/core/dialect/base/expression-compiler-registry.ts +254 -0
- package/src/core/dialect/base/function-table-formatter.ts +40 -78
- package/src/core/dialect/base/select-ast-normalizer.ts +61 -0
- package/src/core/dialect/base/sql-dialect.ts +36 -59
- package/src/core/dialect/capabilities/procedure-compiler.ts +30 -0
- package/src/core/dialect/dialect-factory.ts +3 -4
- package/src/core/dialect/mssql/index.ts +3 -2
- package/src/core/dialect/mysql/index.ts +3 -2
- package/src/core/dialect/postgres/index.ts +3 -2
- package/src/core/dialect/sqlite/index.ts +1 -7
- package/src/decorators/entity.ts +2 -3
- package/src/index.ts +4 -0
- package/src/orm/entity-metadata.ts +6 -11
- package/src/orm/execute-procedure.ts +3 -2
- package/src/orm/lifecycle.ts +20 -0
- package/src/orm/orm-session.ts +37 -3
- package/src/orm/unit-of-work.ts +15 -9
- package/src/query-builder/procedure-call.ts +4 -18
- package/src/schema/table.ts +10 -25
- package/src/tree/tree-manager.ts +111 -43
package/dist/index.cjs
CHANGED
|
@@ -74,6 +74,8 @@ __export(index_exports, {
|
|
|
74
74
|
DefaultMorphToReference: () => DefaultMorphToReference,
|
|
75
75
|
DefaultTypeStrategy: () => DefaultTypeStrategy,
|
|
76
76
|
DeleteQueryBuilder: () => DeleteQueryBuilder,
|
|
77
|
+
DialectBase: () => DialectBase,
|
|
78
|
+
DialectFactory: () => DialectFactory,
|
|
77
79
|
DomainEventBus: () => DomainEventBus,
|
|
78
80
|
Email: () => Email,
|
|
79
81
|
Entity: () => Entity,
|
|
@@ -301,6 +303,7 @@ __export(index_exports, {
|
|
|
301
303
|
isNull: () => isNull,
|
|
302
304
|
isNullableColumn: () => isNullableColumn,
|
|
303
305
|
isOperandNode: () => isOperandNode,
|
|
306
|
+
isProcedureCompiler: () => isProcedureCompiler,
|
|
304
307
|
isSingleTargetRelation: () => isSingleTargetRelation,
|
|
305
308
|
isTableDef: () => isTableDef2,
|
|
306
309
|
isTreeConfig: () => isTreeConfig,
|
|
@@ -398,6 +401,8 @@ __export(index_exports, {
|
|
|
398
401
|
repeat: () => repeat,
|
|
399
402
|
replace: () => replace,
|
|
400
403
|
replaceWithRefs: () => replaceWithRefs,
|
|
404
|
+
requireProcedureCompiler: () => requireProcedureCompiler,
|
|
405
|
+
resolveDialectInput: () => resolveDialectInput,
|
|
401
406
|
resolveTreeConfig: () => resolveTreeConfig,
|
|
402
407
|
resolveValidator: () => resolveValidator,
|
|
403
408
|
responseToRef: () => responseToRef,
|
|
@@ -477,7 +482,7 @@ __export(index_exports, {
|
|
|
477
482
|
module.exports = __toCommonJS(index_exports);
|
|
478
483
|
|
|
479
484
|
// src/schema/table.ts
|
|
480
|
-
var defineTable = (name, columns, relations = {},
|
|
485
|
+
var defineTable = (name, columns, relations = {}, options = {}) => {
|
|
481
486
|
const colsWithNames = Object.entries(columns).reduce((acc, [key, def]) => {
|
|
482
487
|
const colDef = { ...def, name: key, table: name };
|
|
483
488
|
acc[key] = colDef;
|
|
@@ -488,7 +493,6 @@ var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
|
|
|
488
493
|
schema: options.schema,
|
|
489
494
|
columns: colsWithNames,
|
|
490
495
|
relations,
|
|
491
|
-
hooks,
|
|
492
496
|
primaryKey: options.primaryKey,
|
|
493
497
|
indexes: options.indexes,
|
|
494
498
|
checks: options.checks,
|
|
@@ -1756,268 +1760,40 @@ var StandardTableFunctionStrategy = class {
|
|
|
1756
1760
|
}
|
|
1757
1761
|
};
|
|
1758
1762
|
|
|
1759
|
-
// src/core/dialect/
|
|
1760
|
-
var
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
* @param ast - Query AST to compile
|
|
1764
|
-
* @returns Compiled query with SQL and parameters
|
|
1765
|
-
*/
|
|
1766
|
-
compileSelect(ast) {
|
|
1767
|
-
const ctx = this.createCompilerContext();
|
|
1768
|
-
const normalized = this.normalizeSelectAst(ast);
|
|
1769
|
-
const rawSql = this.compileSelectAst(normalized, ctx).trim();
|
|
1770
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1771
|
-
return {
|
|
1772
|
-
sql,
|
|
1773
|
-
params: [...ctx.params]
|
|
1774
|
-
};
|
|
1775
|
-
}
|
|
1776
|
-
compileInsert(ast) {
|
|
1777
|
-
const ctx = this.createCompilerContext();
|
|
1778
|
-
const rawSql = this.compileInsertAst(ast, ctx).trim();
|
|
1779
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1780
|
-
return {
|
|
1781
|
-
sql,
|
|
1782
|
-
params: [...ctx.params]
|
|
1783
|
-
};
|
|
1784
|
-
}
|
|
1785
|
-
compileUpdate(ast) {
|
|
1786
|
-
const ctx = this.createCompilerContext();
|
|
1787
|
-
const rawSql = this.compileUpdateAst(ast, ctx).trim();
|
|
1788
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1789
|
-
return {
|
|
1790
|
-
sql,
|
|
1791
|
-
params: [...ctx.params]
|
|
1792
|
-
};
|
|
1793
|
-
}
|
|
1794
|
-
compileDelete(ast) {
|
|
1795
|
-
const ctx = this.createCompilerContext();
|
|
1796
|
-
const rawSql = this.compileDeleteAst(ast, ctx).trim();
|
|
1797
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1798
|
-
return {
|
|
1799
|
-
sql,
|
|
1800
|
-
params: [...ctx.params]
|
|
1801
|
-
};
|
|
1802
|
-
}
|
|
1803
|
-
supportsDmlReturningClause() {
|
|
1804
|
-
return false;
|
|
1805
|
-
}
|
|
1806
|
-
/**
|
|
1807
|
-
* Compiles a WHERE clause
|
|
1808
|
-
* @param where - WHERE expression
|
|
1809
|
-
* @param ctx - Compiler context
|
|
1810
|
-
* @returns SQL WHERE clause or empty string
|
|
1811
|
-
*/
|
|
1812
|
-
compileWhere(where, ctx) {
|
|
1813
|
-
if (!where) return "";
|
|
1814
|
-
return ` WHERE ${this.compileExpression(where, ctx)}`;
|
|
1815
|
-
}
|
|
1816
|
-
compileReturning(returning, _ctx) {
|
|
1817
|
-
void _ctx;
|
|
1818
|
-
if (!returning || returning.length === 0) return "";
|
|
1819
|
-
throw new Error("RETURNING is not supported by this dialect.");
|
|
1820
|
-
}
|
|
1821
|
-
/**
|
|
1822
|
-
* Generates subquery for EXISTS expressions
|
|
1823
|
-
* Rule: Always forces SELECT 1, ignoring column list
|
|
1824
|
-
* Maintains FROM, JOINs, WHERE, GROUP BY, ORDER BY, LIMIT/OFFSET
|
|
1825
|
-
* Does not add ';' at the end
|
|
1826
|
-
* @param ast - Query AST
|
|
1827
|
-
* @param ctx - Compiler context
|
|
1828
|
-
* @returns SQL for EXISTS subquery
|
|
1829
|
-
*/
|
|
1830
|
-
compileSelectForExists(ast, ctx) {
|
|
1831
|
-
const normalized = this.normalizeSelectAst(ast);
|
|
1832
|
-
const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
|
|
1833
|
-
if (normalized.setOps && normalized.setOps.length > 0) {
|
|
1834
|
-
return `SELECT 1 FROM (${full}) AS _exists`;
|
|
1835
|
-
}
|
|
1836
|
-
const upper2 = full.toUpperCase();
|
|
1837
|
-
const fromIndex = upper2.indexOf(" FROM ");
|
|
1838
|
-
if (fromIndex === -1) {
|
|
1839
|
-
return full;
|
|
1840
|
-
}
|
|
1841
|
-
const tail = full.slice(fromIndex);
|
|
1842
|
-
return `SELECT 1${tail}`;
|
|
1843
|
-
}
|
|
1844
|
-
/**
|
|
1845
|
-
* Creates a new compiler context
|
|
1846
|
-
* @returns Compiler context with parameter management
|
|
1847
|
-
*/
|
|
1848
|
-
createCompilerContext() {
|
|
1849
|
-
const params = [];
|
|
1850
|
-
let counter = 0;
|
|
1851
|
-
return {
|
|
1852
|
-
params,
|
|
1853
|
-
addParameter: (value) => {
|
|
1854
|
-
counter += 1;
|
|
1855
|
-
params.push(value);
|
|
1856
|
-
return this.formatPlaceholder(counter);
|
|
1857
|
-
}
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
/**
|
|
1861
|
-
* Formats a parameter placeholder
|
|
1862
|
-
* @param index - Parameter index
|
|
1863
|
-
* @returns Formatted placeholder string
|
|
1864
|
-
*/
|
|
1865
|
-
formatPlaceholder(_index) {
|
|
1866
|
-
void _index;
|
|
1867
|
-
return "?";
|
|
1868
|
-
}
|
|
1869
|
-
/**
|
|
1870
|
-
* Whether the current dialect supports a given set operation.
|
|
1871
|
-
* Override in concrete dialects to restrict support.
|
|
1872
|
-
*/
|
|
1873
|
-
supportsSetOperation(_kind) {
|
|
1874
|
-
void _kind;
|
|
1875
|
-
return true;
|
|
1876
|
-
}
|
|
1877
|
-
/**
|
|
1878
|
-
* Validates set-operation semantics:
|
|
1879
|
-
* - Ensures the dialect supports requested operators.
|
|
1880
|
-
* - Enforces that only the outermost compound query may have ORDER/LIMIT/OFFSET.
|
|
1881
|
-
* @param ast - Query to validate
|
|
1882
|
-
* @param isOutermost - Whether this node is the outermost compound query
|
|
1883
|
-
*/
|
|
1884
|
-
validateSetOperations(ast, isOutermost = true) {
|
|
1885
|
-
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
1886
|
-
if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
|
|
1887
|
-
throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
|
|
1888
|
-
}
|
|
1889
|
-
if (hasSetOps) {
|
|
1890
|
-
for (const op of ast.setOps) {
|
|
1891
|
-
if (!this.supportsSetOperation(op.operator)) {
|
|
1892
|
-
throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
|
|
1893
|
-
}
|
|
1894
|
-
this.validateSetOperations(op.query, false);
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
/**
|
|
1899
|
-
* Hoists CTEs from set-operation operands to the outermost query so WITH appears once.
|
|
1900
|
-
* @param ast - Query AST
|
|
1901
|
-
* @returns Normalized AST without inner CTEs and a list of hoisted CTEs
|
|
1902
|
-
*/
|
|
1903
|
-
hoistCtes(ast) {
|
|
1904
|
-
let hoisted = [];
|
|
1905
|
-
const normalizedSetOps = ast.setOps?.map((op) => {
|
|
1906
|
-
const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
|
|
1907
|
-
const childCtes = child.ctes ?? [];
|
|
1908
|
-
if (childCtes.length) {
|
|
1909
|
-
hoisted = hoisted.concat(childCtes);
|
|
1910
|
-
}
|
|
1911
|
-
hoisted = hoisted.concat(childHoisted);
|
|
1912
|
-
const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
|
|
1913
|
-
return { ...op, query: queryWithoutCtes };
|
|
1914
|
-
});
|
|
1915
|
-
const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
|
|
1916
|
-
return { normalized, hoistedCtes: hoisted };
|
|
1917
|
-
}
|
|
1918
|
-
/**
|
|
1919
|
-
* Normalizes a SELECT AST before compilation (validation + CTE hoisting).
|
|
1920
|
-
* @param ast - Query AST
|
|
1921
|
-
* @returns Normalized query AST
|
|
1922
|
-
*/
|
|
1923
|
-
normalizeSelectAst(ast) {
|
|
1924
|
-
this.validateSetOperations(ast, true);
|
|
1925
|
-
const { normalized, hoistedCtes } = this.hoistCtes(ast);
|
|
1926
|
-
const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
|
|
1927
|
-
return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
|
|
1928
|
-
}
|
|
1929
|
-
expressionCompilers;
|
|
1930
|
-
operandCompilers;
|
|
1931
|
-
functionStrategy;
|
|
1932
|
-
tableFunctionStrategy;
|
|
1933
|
-
constructor(functionStrategy, tableFunctionStrategy) {
|
|
1934
|
-
this.expressionCompilers = /* @__PURE__ */ new Map();
|
|
1935
|
-
this.operandCompilers = /* @__PURE__ */ new Map();
|
|
1936
|
-
this.functionStrategy = functionStrategy || new StandardFunctionStrategy();
|
|
1937
|
-
this.tableFunctionStrategy = tableFunctionStrategy || new StandardTableFunctionStrategy();
|
|
1763
|
+
// src/core/dialect/base/expression-compiler-registry.ts
|
|
1764
|
+
var ExpressionCompilerRegistry = class {
|
|
1765
|
+
constructor(host) {
|
|
1766
|
+
this.host = host;
|
|
1938
1767
|
this.registerDefaultOperandCompilers();
|
|
1939
1768
|
this.registerDefaultExpressionCompilers();
|
|
1940
1769
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
* @param functionStrategy - Optional function strategy
|
|
1944
|
-
* @returns New Dialect instance
|
|
1945
|
-
*/
|
|
1946
|
-
static create(functionStrategy, tableFunctionStrategy) {
|
|
1947
|
-
class TestDialect extends _Dialect {
|
|
1948
|
-
dialect = "sqlite";
|
|
1949
|
-
quoteIdentifier(id) {
|
|
1950
|
-
return `"${id}"`;
|
|
1951
|
-
}
|
|
1952
|
-
compileSelectAst() {
|
|
1953
|
-
throw new Error("Not implemented");
|
|
1954
|
-
}
|
|
1955
|
-
compileInsertAst() {
|
|
1956
|
-
throw new Error("Not implemented");
|
|
1957
|
-
}
|
|
1958
|
-
compileUpdateAst() {
|
|
1959
|
-
throw new Error("Not implemented");
|
|
1960
|
-
}
|
|
1961
|
-
compileDeleteAst() {
|
|
1962
|
-
throw new Error("Not implemented");
|
|
1963
|
-
}
|
|
1964
|
-
compileProcedureCall() {
|
|
1965
|
-
throw new Error("Not implemented");
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
return new TestDialect(functionStrategy, tableFunctionStrategy);
|
|
1969
|
-
}
|
|
1970
|
-
/**
|
|
1971
|
-
* Registers an expression compiler for a specific node type
|
|
1972
|
-
* @param type - Expression node type
|
|
1973
|
-
* @param compiler - Compiler function
|
|
1974
|
-
*/
|
|
1770
|
+
expressionCompilers = /* @__PURE__ */ new Map();
|
|
1771
|
+
operandCompilers = /* @__PURE__ */ new Map();
|
|
1975
1772
|
registerExpressionCompiler(type, compiler) {
|
|
1976
1773
|
this.expressionCompilers.set(type, compiler);
|
|
1977
1774
|
}
|
|
1978
|
-
/**
|
|
1979
|
-
* Registers an operand compiler for a specific node type
|
|
1980
|
-
* @param type - Operand node type
|
|
1981
|
-
* @param compiler - Compiler function
|
|
1982
|
-
*/
|
|
1983
1775
|
registerOperandCompiler(type, compiler) {
|
|
1984
1776
|
this.operandCompilers.set(type, compiler);
|
|
1985
1777
|
}
|
|
1986
|
-
/**
|
|
1987
|
-
* Compiles an expression node
|
|
1988
|
-
* @param node - Expression node to compile
|
|
1989
|
-
* @param ctx - Compiler context
|
|
1990
|
-
* @returns Compiled SQL expression
|
|
1991
|
-
*/
|
|
1992
1778
|
compileExpression(node, ctx) {
|
|
1993
1779
|
const compiler = this.expressionCompilers.get(node.type);
|
|
1994
1780
|
if (!compiler) {
|
|
1995
|
-
throw new Error(`Unsupported expression node type "${node.type}" for ${this.
|
|
1781
|
+
throw new Error(`Unsupported expression node type "${node.type}" for ${this.host.describe()}`);
|
|
1996
1782
|
}
|
|
1997
1783
|
return compiler(node, ctx);
|
|
1998
1784
|
}
|
|
1999
|
-
/**
|
|
2000
|
-
* Compiles an operand node
|
|
2001
|
-
* @param node - Operand node to compile
|
|
2002
|
-
* @param ctx - Compiler context
|
|
2003
|
-
* @returns Compiled SQL operand
|
|
2004
|
-
*/
|
|
2005
1785
|
compileOperand(node, ctx) {
|
|
2006
1786
|
const compiler = this.operandCompilers.get(node.type);
|
|
2007
1787
|
if (!compiler) {
|
|
2008
|
-
throw new Error(`Unsupported operand node type "${node.type}" for ${this.
|
|
1788
|
+
throw new Error(`Unsupported operand node type "${node.type}" for ${this.host.describe()}`);
|
|
2009
1789
|
}
|
|
2010
1790
|
return compiler(node, ctx);
|
|
2011
1791
|
}
|
|
2012
|
-
/**
|
|
2013
|
-
* Compiles an ordering term (operand, expression, or alias reference).
|
|
2014
|
-
*/
|
|
2015
1792
|
compileOrderingTerm(term, ctx) {
|
|
2016
1793
|
if (isOperandNode(term)) {
|
|
2017
1794
|
return this.compileOperand(term, ctx);
|
|
2018
1795
|
}
|
|
2019
|
-
|
|
2020
|
-
return `(${expr})`;
|
|
1796
|
+
return `(${this.compileExpression(term, ctx)})`;
|
|
2021
1797
|
}
|
|
2022
1798
|
registerDefaultExpressionCompilers() {
|
|
2023
1799
|
this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
|
|
@@ -2052,11 +1828,11 @@ var Dialect = class _Dialect {
|
|
|
2052
1828
|
const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
|
|
2053
1829
|
return `${left2} ${inExpr.operator} (${values})`;
|
|
2054
1830
|
}
|
|
2055
|
-
const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
|
|
1831
|
+
const subquerySql = this.host.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
|
|
2056
1832
|
return `${left2} ${inExpr.operator} (${subquerySql})`;
|
|
2057
1833
|
});
|
|
2058
1834
|
this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
|
|
2059
|
-
const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
|
|
1835
|
+
const subquerySql = this.host.compileSelectForExists(existsExpr.subquery, ctx);
|
|
2060
1836
|
return `${existsExpr.operator} (${subquerySql})`;
|
|
2061
1837
|
});
|
|
2062
1838
|
this.registerExpressionCompiler("BetweenExpression", (betweenExpr, ctx) => {
|
|
@@ -2082,25 +1858,28 @@ var Dialect = class _Dialect {
|
|
|
2082
1858
|
});
|
|
2083
1859
|
}
|
|
2084
1860
|
registerDefaultOperandCompilers() {
|
|
2085
|
-
this.registerOperandCompiler(
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
1861
|
+
this.registerOperandCompiler(
|
|
1862
|
+
"Literal",
|
|
1863
|
+
(literal, ctx) => ctx.addParameter(literal.value)
|
|
1864
|
+
);
|
|
1865
|
+
this.registerOperandCompiler(
|
|
1866
|
+
"AliasRef",
|
|
1867
|
+
(alias) => this.host.quoteIdentifier(alias.name)
|
|
1868
|
+
);
|
|
1869
|
+
this.registerOperandCompiler(
|
|
1870
|
+
"Column",
|
|
1871
|
+
(column) => `${this.host.quoteIdentifier(column.table)}.${this.host.quoteIdentifier(column.name)}`
|
|
1872
|
+
);
|
|
2094
1873
|
this.registerOperandCompiler(
|
|
2095
1874
|
"Function",
|
|
2096
|
-
(fnNode, ctx) => this.compileFunctionOperand(fnNode, ctx)
|
|
1875
|
+
(fnNode, ctx) => this.host.compileFunctionOperand(fnNode, ctx)
|
|
1876
|
+
);
|
|
1877
|
+
this.registerOperandCompiler(
|
|
1878
|
+
"JsonPath",
|
|
1879
|
+
(path) => this.host.compileJsonPath(path)
|
|
2097
1880
|
);
|
|
2098
|
-
this.registerOperandCompiler("JsonPath", (path, _ctx) => {
|
|
2099
|
-
void _ctx;
|
|
2100
|
-
return this.compileJsonPath(path);
|
|
2101
|
-
});
|
|
2102
1881
|
this.registerOperandCompiler("ScalarSubquery", (node, ctx) => {
|
|
2103
|
-
const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
|
|
1882
|
+
const sql = this.host.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
|
|
2104
1883
|
return `(${sql})`;
|
|
2105
1884
|
});
|
|
2106
1885
|
this.registerOperandCompiler("CaseExpression", (node, ctx) => {
|
|
@@ -2127,7 +1906,7 @@ var Dialect = class _Dialect {
|
|
|
2127
1906
|
const parts = [];
|
|
2128
1907
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
2129
1908
|
const partitionClause = "PARTITION BY " + node.partitionBy.map(
|
|
2130
|
-
(col2) => `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`
|
|
1909
|
+
(col2) => `${this.host.quoteIdentifier(col2.table)}.${this.host.quoteIdentifier(col2.name)}`
|
|
2131
1910
|
).join(", ");
|
|
2132
1911
|
parts.push(partitionClause);
|
|
2133
1912
|
}
|
|
@@ -2159,14 +1938,164 @@ var Dialect = class _Dialect {
|
|
|
2159
1938
|
return `${expr} COLLATE ${node.collation}`;
|
|
2160
1939
|
});
|
|
2161
1940
|
}
|
|
2162
|
-
|
|
1941
|
+
};
|
|
1942
|
+
|
|
1943
|
+
// src/core/dialect/base/select-ast-normalizer.ts
|
|
1944
|
+
var SelectAstNormalizer = class {
|
|
1945
|
+
constructor(supportsSetOperation) {
|
|
1946
|
+
this.supportsSetOperation = supportsSetOperation;
|
|
1947
|
+
}
|
|
1948
|
+
normalize(ast) {
|
|
1949
|
+
this.validateSetOperations(ast, true);
|
|
1950
|
+
const { normalized, hoistedCtes } = this.hoistCtes(ast);
|
|
1951
|
+
const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
|
|
1952
|
+
return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
|
|
1953
|
+
}
|
|
1954
|
+
validateSetOperations(ast, isOutermost) {
|
|
1955
|
+
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
1956
|
+
if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
|
|
1957
|
+
throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
|
|
1958
|
+
}
|
|
1959
|
+
if (!hasSetOps) return;
|
|
1960
|
+
for (const op of ast.setOps) {
|
|
1961
|
+
if (!this.supportsSetOperation(op.operator)) {
|
|
1962
|
+
throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
|
|
1963
|
+
}
|
|
1964
|
+
this.validateSetOperations(op.query, false);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
hoistCtes(ast) {
|
|
1968
|
+
let hoisted = [];
|
|
1969
|
+
const normalizedSetOps = ast.setOps?.map((op) => {
|
|
1970
|
+
const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
|
|
1971
|
+
const childCtes = child.ctes ?? [];
|
|
1972
|
+
if (childCtes.length) hoisted = hoisted.concat(childCtes);
|
|
1973
|
+
hoisted = hoisted.concat(childHoisted);
|
|
1974
|
+
const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
|
|
1975
|
+
return { ...op, query: queryWithoutCtes };
|
|
1976
|
+
});
|
|
1977
|
+
const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
|
|
1978
|
+
return { normalized, hoistedCtes: hoisted };
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
|
|
1982
|
+
// src/core/dialect/abstract.ts
|
|
1983
|
+
var DialectBase = class _DialectBase {
|
|
1984
|
+
expressionCompilerRegistry;
|
|
1985
|
+
selectAstNormalizer;
|
|
1986
|
+
functionStrategy;
|
|
1987
|
+
tableFunctionStrategy;
|
|
1988
|
+
constructor(functionStrategy, tableFunctionStrategy) {
|
|
1989
|
+
this.functionStrategy = functionStrategy ?? new StandardFunctionStrategy();
|
|
1990
|
+
this.tableFunctionStrategy = tableFunctionStrategy ?? new StandardTableFunctionStrategy();
|
|
1991
|
+
this.selectAstNormalizer = new SelectAstNormalizer((kind) => this.supportsSetOperation(kind));
|
|
1992
|
+
this.expressionCompilerRegistry = new ExpressionCompilerRegistry({
|
|
1993
|
+
quoteIdentifier: (id) => this.quoteIdentifier(id),
|
|
1994
|
+
compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
|
|
1995
|
+
compileSelectForExists: (ast, ctx) => this.compileSelectForExists(ast, ctx),
|
|
1996
|
+
compileJsonPath: (node) => this.compileJsonPath(node),
|
|
1997
|
+
compileFunctionOperand: (node, ctx) => this.compileFunctionOperand(node, ctx),
|
|
1998
|
+
describe: () => this.constructor.name
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
compileSelect(ast) {
|
|
2002
|
+
const ctx = this.createCompilerContext();
|
|
2003
|
+
const normalized = this.normalizeSelectAst(ast);
|
|
2004
|
+
const rawSql = this.compileSelectAst(normalized, ctx).trim();
|
|
2005
|
+
return {
|
|
2006
|
+
sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
|
|
2007
|
+
params: [...ctx.params]
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
compileInsert(ast) {
|
|
2011
|
+
const ctx = this.createCompilerContext();
|
|
2012
|
+
const rawSql = this.compileInsertAst(ast, ctx).trim();
|
|
2013
|
+
return {
|
|
2014
|
+
sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
|
|
2015
|
+
params: [...ctx.params]
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
compileUpdate(ast) {
|
|
2019
|
+
const ctx = this.createCompilerContext();
|
|
2020
|
+
const rawSql = this.compileUpdateAst(ast, ctx).trim();
|
|
2021
|
+
return {
|
|
2022
|
+
sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
|
|
2023
|
+
params: [...ctx.params]
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
compileDelete(ast) {
|
|
2027
|
+
const ctx = this.createCompilerContext();
|
|
2028
|
+
const rawSql = this.compileDeleteAst(ast, ctx).trim();
|
|
2029
|
+
return {
|
|
2030
|
+
sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
|
|
2031
|
+
params: [...ctx.params]
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
supportsDmlReturningClause() {
|
|
2035
|
+
return false;
|
|
2036
|
+
}
|
|
2037
|
+
compileWhere(where, ctx) {
|
|
2038
|
+
if (!where) return "";
|
|
2039
|
+
return ` WHERE ${this.compileExpression(where, ctx)}`;
|
|
2040
|
+
}
|
|
2041
|
+
compileReturning(returning, _ctx) {
|
|
2042
|
+
void _ctx;
|
|
2043
|
+
if (!returning || returning.length === 0) return "";
|
|
2044
|
+
throw new Error("RETURNING is not supported by this dialect.");
|
|
2045
|
+
}
|
|
2046
|
+
compileSelectForExists(ast, ctx) {
|
|
2047
|
+
const normalized = this.normalizeSelectAst(ast);
|
|
2048
|
+
const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
|
|
2049
|
+
if (normalized.setOps && normalized.setOps.length > 0) {
|
|
2050
|
+
return `SELECT 1 FROM (${full}) AS _exists`;
|
|
2051
|
+
}
|
|
2052
|
+
const upper2 = full.toUpperCase();
|
|
2053
|
+
const fromIndex = upper2.indexOf(" FROM ");
|
|
2054
|
+
if (fromIndex === -1) return full;
|
|
2055
|
+
return `SELECT 1${full.slice(fromIndex)}`;
|
|
2056
|
+
}
|
|
2057
|
+
createCompilerContext() {
|
|
2058
|
+
const params = [];
|
|
2059
|
+
let counter = 0;
|
|
2060
|
+
return {
|
|
2061
|
+
params,
|
|
2062
|
+
addParameter: (value) => {
|
|
2063
|
+
counter += 1;
|
|
2064
|
+
params.push(value);
|
|
2065
|
+
return this.formatPlaceholder(counter);
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
2069
|
+
formatPlaceholder(_index) {
|
|
2070
|
+
void _index;
|
|
2071
|
+
return "?";
|
|
2072
|
+
}
|
|
2073
|
+
supportsSetOperation(_kind) {
|
|
2074
|
+
void _kind;
|
|
2075
|
+
return true;
|
|
2076
|
+
}
|
|
2077
|
+
normalizeSelectAst(ast) {
|
|
2078
|
+
return this.selectAstNormalizer.normalize(ast);
|
|
2079
|
+
}
|
|
2080
|
+
registerExpressionCompiler(type, compiler) {
|
|
2081
|
+
this.expressionCompilerRegistry.registerExpressionCompiler(type, compiler);
|
|
2082
|
+
}
|
|
2083
|
+
registerOperandCompiler(type, compiler) {
|
|
2084
|
+
this.expressionCompilerRegistry.registerOperandCompiler(type, compiler);
|
|
2085
|
+
}
|
|
2086
|
+
compileExpression(node, ctx) {
|
|
2087
|
+
return this.expressionCompilerRegistry.compileExpression(node, ctx);
|
|
2088
|
+
}
|
|
2089
|
+
compileOperand(node, ctx) {
|
|
2090
|
+
return this.expressionCompilerRegistry.compileOperand(node, ctx);
|
|
2091
|
+
}
|
|
2092
|
+
compileOrderingTerm(term, ctx) {
|
|
2093
|
+
return this.expressionCompilerRegistry.compileOrderingTerm(term, ctx);
|
|
2094
|
+
}
|
|
2163
2095
|
compileJsonPath(_node) {
|
|
2164
2096
|
void _node;
|
|
2165
2097
|
throw new Error("JSON Path not supported by this dialect");
|
|
2166
2098
|
}
|
|
2167
|
-
/**
|
|
2168
|
-
* Compiles a function operand, using the dialect's function strategy.
|
|
2169
|
-
*/
|
|
2170
2099
|
compileFunctionOperand(fnNode, ctx) {
|
|
2171
2100
|
const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
|
|
2172
2101
|
const renderer = this.functionStrategy.getRenderer(fnNode.name);
|
|
@@ -2179,98 +2108,62 @@ var Dialect = class _Dialect {
|
|
|
2179
2108
|
}
|
|
2180
2109
|
return `${fnNode.name}(${compiledArgs.join(", ")})`;
|
|
2181
2110
|
}
|
|
2111
|
+
/** Creates a minimal dialect implementation for isolated compiler tests. */
|
|
2112
|
+
static create(functionStrategy, tableFunctionStrategy) {
|
|
2113
|
+
class TestDialect extends _DialectBase {
|
|
2114
|
+
dialect = "sqlite";
|
|
2115
|
+
quoteIdentifier(id) {
|
|
2116
|
+
return `"${id}"`;
|
|
2117
|
+
}
|
|
2118
|
+
compileSelectAst() {
|
|
2119
|
+
throw new Error("Not implemented");
|
|
2120
|
+
}
|
|
2121
|
+
compileInsertAst() {
|
|
2122
|
+
throw new Error("Not implemented");
|
|
2123
|
+
}
|
|
2124
|
+
compileUpdateAst() {
|
|
2125
|
+
throw new Error("Not implemented");
|
|
2126
|
+
}
|
|
2127
|
+
compileDeleteAst() {
|
|
2128
|
+
throw new Error("Not implemented");
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
return new TestDialect(functionStrategy, tableFunctionStrategy);
|
|
2132
|
+
}
|
|
2182
2133
|
};
|
|
2183
2134
|
|
|
2184
2135
|
// src/core/dialect/base/function-table-formatter.ts
|
|
2185
2136
|
var FunctionTableFormatter = class {
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
* @param ctx - Optional compiler context for operand compilation.
|
|
2190
|
-
* @param dialect - The dialect instance for compiling operands.
|
|
2191
|
-
* @returns SQL function table expression (e.g., "LATERAL schema.func(args) WITH ORDINALITY AS alias(col1, col2)").
|
|
2192
|
-
*/
|
|
2193
|
-
static format(fn9, ctx, dialect) {
|
|
2194
|
-
const schemaPart = this.formatSchema(fn9, dialect);
|
|
2195
|
-
const args = this.formatArgs(fn9, ctx, dialect);
|
|
2137
|
+
static format(fn9, ctx, formatter) {
|
|
2138
|
+
const schemaPart = this.formatSchema(fn9, formatter);
|
|
2139
|
+
const args = this.formatArgs(fn9, ctx, formatter);
|
|
2196
2140
|
const base = this.formatBase(fn9, schemaPart, args);
|
|
2197
2141
|
const lateral = this.formatLateral(fn9);
|
|
2198
|
-
const alias = this.formatAlias(fn9,
|
|
2199
|
-
const colAliases = this.formatColumnAliases(fn9,
|
|
2142
|
+
const alias = this.formatAlias(fn9, formatter);
|
|
2143
|
+
const colAliases = this.formatColumnAliases(fn9, formatter);
|
|
2200
2144
|
return `${lateral}${base}${alias}${colAliases}`;
|
|
2201
2145
|
}
|
|
2202
|
-
|
|
2203
|
-
* Formats the schema prefix for the function name.
|
|
2204
|
-
* @param fn - The function table node.
|
|
2205
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
2206
|
-
* @returns Schema prefix (e.g., "schema.") or empty string.
|
|
2207
|
-
* @internal
|
|
2208
|
-
*/
|
|
2209
|
-
static formatSchema(fn9, dialect) {
|
|
2146
|
+
static formatSchema(fn9, formatter) {
|
|
2210
2147
|
if (!fn9.schema) return "";
|
|
2211
|
-
|
|
2212
|
-
return `${quoted}.`;
|
|
2148
|
+
return `${formatter.quoteIdentifier(fn9.schema)}.`;
|
|
2213
2149
|
}
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
* @param fn - The function table node containing arguments.
|
|
2217
|
-
* @param ctx - Optional compiler context for operand compilation.
|
|
2218
|
-
* @param dialect - The dialect instance for compiling operands.
|
|
2219
|
-
* @returns Comma-separated function arguments.
|
|
2220
|
-
* @internal
|
|
2221
|
-
*/
|
|
2222
|
-
static formatArgs(fn9, ctx, dialect) {
|
|
2223
|
-
return (fn9.args || []).map((a) => {
|
|
2224
|
-
if (ctx && dialect) {
|
|
2225
|
-
return dialect.compileOperand(a, ctx);
|
|
2226
|
-
}
|
|
2227
|
-
return String(a);
|
|
2228
|
-
}).join(", ");
|
|
2150
|
+
static formatArgs(fn9, ctx, formatter) {
|
|
2151
|
+
return (fn9.args || []).map((arg) => ctx ? formatter.compileOperand(arg, ctx) : String(arg)).join(", ");
|
|
2229
2152
|
}
|
|
2230
|
-
/**
|
|
2231
|
-
* Formats the base function call with WITH ORDINALITY if present.
|
|
2232
|
-
* @param fn - The function table node.
|
|
2233
|
-
* @param schemaPart - Formatted schema prefix.
|
|
2234
|
-
* @param args - Formatted function arguments.
|
|
2235
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
2236
|
-
* @returns Base function call expression (e.g., "schema.func(args) WITH ORDINALITY").
|
|
2237
|
-
* @internal
|
|
2238
|
-
*/
|
|
2239
2153
|
static formatBase(fn9, schemaPart, args) {
|
|
2240
2154
|
const ordinality = fn9.withOrdinality ? " WITH ORDINALITY" : "";
|
|
2241
2155
|
return `${schemaPart}${fn9.name}(${args})${ordinality}`;
|
|
2242
2156
|
}
|
|
2243
|
-
/**
|
|
2244
|
-
* Formats the LATERAL keyword if present.
|
|
2245
|
-
* @param fn - The function table node.
|
|
2246
|
-
* @returns "LATERAL " or empty string.
|
|
2247
|
-
* @internal
|
|
2248
|
-
*/
|
|
2249
2157
|
static formatLateral(fn9) {
|
|
2250
2158
|
return fn9.lateral ? "LATERAL " : "";
|
|
2251
2159
|
}
|
|
2252
|
-
|
|
2253
|
-
* Formats the table alias for the function table.
|
|
2254
|
-
* @param fn - The function table node.
|
|
2255
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
2256
|
-
* @returns " AS alias" or empty string.
|
|
2257
|
-
* @internal
|
|
2258
|
-
*/
|
|
2259
|
-
static formatAlias(fn9, dialect) {
|
|
2160
|
+
static formatAlias(fn9, formatter) {
|
|
2260
2161
|
if (!fn9.alias) return "";
|
|
2261
|
-
|
|
2262
|
-
return ` AS ${quoted}`;
|
|
2162
|
+
return ` AS ${formatter.quoteIdentifier(fn9.alias)}`;
|
|
2263
2163
|
}
|
|
2264
|
-
|
|
2265
|
-
* Formats column aliases for the function table result columns.
|
|
2266
|
-
* @param fn - The function table node containing column aliases.
|
|
2267
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
2268
|
-
* @returns "(col1, col2, ...)" or empty string.
|
|
2269
|
-
* @internal
|
|
2270
|
-
*/
|
|
2271
|
-
static formatColumnAliases(fn9, dialect) {
|
|
2164
|
+
static formatColumnAliases(fn9, formatter) {
|
|
2272
2165
|
if (!fn9.columnAliases || !fn9.columnAliases.length) return "";
|
|
2273
|
-
const aliases = fn9.columnAliases.map((col2) =>
|
|
2166
|
+
const aliases = fn9.columnAliases.map((col2) => formatter.quoteIdentifier(col2)).join(", ");
|
|
2274
2167
|
return `(${aliases})`;
|
|
2275
2168
|
}
|
|
2276
2169
|
};
|
|
@@ -2396,7 +2289,7 @@ var OrderByCompiler = class {
|
|
|
2396
2289
|
};
|
|
2397
2290
|
|
|
2398
2291
|
// src/core/dialect/base/sql-dialect.ts
|
|
2399
|
-
var SqlDialectBase = class extends
|
|
2292
|
+
var SqlDialectBase = class extends DialectBase {
|
|
2400
2293
|
paginationStrategy = new StandardLimitOffsetPagination();
|
|
2401
2294
|
returningStrategy = new NoReturningStrategy();
|
|
2402
2295
|
compileSelectAst(ast, ctx) {
|
|
@@ -2406,14 +2299,12 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2406
2299
|
ctx,
|
|
2407
2300
|
this.quoteIdentifier.bind(this),
|
|
2408
2301
|
this.compileSelectAst.bind(this),
|
|
2409
|
-
this.normalizeSelectAst
|
|
2302
|
+
this.normalizeSelectAst.bind(this),
|
|
2410
2303
|
this.stripTrailingSemicolon.bind(this)
|
|
2411
2304
|
);
|
|
2412
2305
|
const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
|
|
2413
2306
|
const baseSelect = this.compileSelectCore(baseAst, ctx);
|
|
2414
|
-
if (!hasSetOps) {
|
|
2415
|
-
return `${ctes}${baseSelect}`;
|
|
2416
|
-
}
|
|
2307
|
+
if (!hasSetOps) return `${ctes}${baseSelect}`;
|
|
2417
2308
|
return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
|
|
2418
2309
|
}
|
|
2419
2310
|
compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
|
|
@@ -2462,9 +2353,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2462
2353
|
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
2463
2354
|
}
|
|
2464
2355
|
ensureConflictColumns(clause, message) {
|
|
2465
|
-
if (!clause.target.columns.length)
|
|
2466
|
-
throw new Error(message);
|
|
2467
|
-
}
|
|
2356
|
+
if (!clause.target.columns.length) throw new Error(message);
|
|
2468
2357
|
}
|
|
2469
2358
|
compileSelectCore(ast, ctx) {
|
|
2470
2359
|
const columns = this.compileSelectColumns(ast, ctx);
|
|
@@ -2497,8 +2386,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2497
2386
|
}
|
|
2498
2387
|
compileUpdateAssignments(assignments, table, ctx) {
|
|
2499
2388
|
return assignments.map((assignment) => {
|
|
2500
|
-
const
|
|
2501
|
-
const target = this.compileSetTarget(col2, table);
|
|
2389
|
+
const target = this.compileSetTarget(assignment.column, table);
|
|
2502
2390
|
const value = this.compileOperand(assignment.value, ctx);
|
|
2503
2391
|
return `${target} = ${value}`;
|
|
2504
2392
|
}).join(", ");
|
|
@@ -2511,9 +2399,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2511
2399
|
const alias = table.alias;
|
|
2512
2400
|
const columnTable = column.table ?? alias ?? baseTableName;
|
|
2513
2401
|
const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
|
|
2514
|
-
if (!tableQualifier)
|
|
2515
|
-
return this.quoteIdentifier(column.name);
|
|
2516
|
-
}
|
|
2402
|
+
if (!tableQualifier) return this.quoteIdentifier(column.name);
|
|
2517
2403
|
return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
|
|
2518
2404
|
}
|
|
2519
2405
|
compileDeleteAst(ast, ctx) {
|
|
@@ -2530,27 +2416,20 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2530
2416
|
return ast.distinct ? "DISTINCT " : "";
|
|
2531
2417
|
}
|
|
2532
2418
|
compileSelectColumns(ast, ctx) {
|
|
2533
|
-
if (!ast.columns || ast.columns.length === 0)
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
if (c.alias.includes("(")) return c.alias;
|
|
2540
|
-
return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
|
|
2419
|
+
if (!ast.columns || ast.columns.length === 0) return "*";
|
|
2420
|
+
return ast.columns.map((column) => {
|
|
2421
|
+
const expr = this.compileOperand(column, ctx);
|
|
2422
|
+
if (column.alias) {
|
|
2423
|
+
if (column.alias.includes("(")) return column.alias;
|
|
2424
|
+
return `${expr} AS ${this.quoteIdentifier(column.alias)}`;
|
|
2541
2425
|
}
|
|
2542
2426
|
return expr;
|
|
2543
2427
|
}).join(", ");
|
|
2544
2428
|
}
|
|
2545
2429
|
compileFrom(ast, ctx) {
|
|
2546
|
-
|
|
2547
|
-
if (
|
|
2548
|
-
|
|
2549
|
-
}
|
|
2550
|
-
if (tableSource.type === "DerivedTable") {
|
|
2551
|
-
return this.compileDerivedTable(tableSource, ctx);
|
|
2552
|
-
}
|
|
2553
|
-
return this.compileTableSource(tableSource);
|
|
2430
|
+
if (ast.type === "FunctionTable") return this.compileFunctionTable(ast, ctx);
|
|
2431
|
+
if (ast.type === "DerivedTable") return this.compileDerivedTable(ast, ctx);
|
|
2432
|
+
return this.compileTableSource(ast);
|
|
2554
2433
|
}
|
|
2555
2434
|
compileFunctionTable(fn9, ctx) {
|
|
2556
2435
|
const key = fn9.key ?? fn9.name;
|
|
@@ -2569,23 +2448,20 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2569
2448
|
throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
|
|
2570
2449
|
}
|
|
2571
2450
|
}
|
|
2572
|
-
return FunctionTableFormatter.format(fn9, ctx,
|
|
2451
|
+
return FunctionTableFormatter.format(fn9, ctx, {
|
|
2452
|
+
quoteIdentifier: (id) => this.quoteIdentifier(id),
|
|
2453
|
+
compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext)
|
|
2454
|
+
});
|
|
2573
2455
|
}
|
|
2574
2456
|
compileDerivedTable(table, ctx) {
|
|
2575
|
-
if (!table.alias)
|
|
2576
|
-
throw new Error("Derived tables must have an alias.");
|
|
2577
|
-
}
|
|
2457
|
+
if (!table.alias) throw new Error("Derived tables must have an alias.");
|
|
2578
2458
|
const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2579
2459
|
const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2580
2460
|
return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
|
|
2581
2461
|
}
|
|
2582
2462
|
compileTableSource(table) {
|
|
2583
|
-
if (table.type === "FunctionTable")
|
|
2584
|
-
|
|
2585
|
-
}
|
|
2586
|
-
if (table.type === "DerivedTable") {
|
|
2587
|
-
return this.compileDerivedTable(table);
|
|
2588
|
-
}
|
|
2463
|
+
if (table.type === "FunctionTable") return this.compileFunctionTable(table);
|
|
2464
|
+
if (table.type === "DerivedTable") return this.compileDerivedTable(table);
|
|
2589
2465
|
const base = this.compileTableName(table);
|
|
2590
2466
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2591
2467
|
}
|
|
@@ -2601,9 +2477,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2601
2477
|
}
|
|
2602
2478
|
compileUpdateFromClause(ast, ctx) {
|
|
2603
2479
|
if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
|
|
2604
|
-
if (!ast.from)
|
|
2605
|
-
throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
|
|
2606
|
-
}
|
|
2480
|
+
if (!ast.from) throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
|
|
2607
2481
|
const from = this.compileFrom(ast.from, ctx);
|
|
2608
2482
|
const joins = JoinCompiler.compileJoins(
|
|
2609
2483
|
ast.joins,
|
|
@@ -2615,9 +2489,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2615
2489
|
}
|
|
2616
2490
|
compileDeleteUsingClause(ast, ctx) {
|
|
2617
2491
|
if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
|
|
2618
|
-
if (!ast.using)
|
|
2619
|
-
throw new Error("DELETE with JOINs requires a USING clause.");
|
|
2620
|
-
}
|
|
2492
|
+
if (!ast.using) throw new Error("DELETE with JOINs requires a USING clause.");
|
|
2621
2493
|
const usingTable = this.compileFrom(ast.using, ctx);
|
|
2622
2494
|
const joins = JoinCompiler.compileJoins(
|
|
2623
2495
|
ast.joins,
|
|
@@ -2635,8 +2507,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2635
2507
|
return sql.trim().replace(/;$/, "");
|
|
2636
2508
|
}
|
|
2637
2509
|
wrapSetOperand(sql) {
|
|
2638
|
-
|
|
2639
|
-
return `(${trimmed})`;
|
|
2510
|
+
return `(${this.stripTrailingSemicolon(sql)})`;
|
|
2640
2511
|
}
|
|
2641
2512
|
renderOrderByNulls(order) {
|
|
2642
2513
|
return order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
@@ -3345,10 +3216,6 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
3345
3216
|
supportsDmlReturningClause() {
|
|
3346
3217
|
return true;
|
|
3347
3218
|
}
|
|
3348
|
-
compileProcedureCall(_ast) {
|
|
3349
|
-
void _ast;
|
|
3350
|
-
throw new Error("Stored procedures are not supported by the SQLite dialect.");
|
|
3351
|
-
}
|
|
3352
3219
|
};
|
|
3353
3220
|
|
|
3354
3221
|
// src/core/dialect/mssql/functions.ts
|
|
@@ -3783,9 +3650,8 @@ var DialectFactory = class {
|
|
|
3783
3650
|
/**
|
|
3784
3651
|
* Register (or override) a dialect factory for a key.
|
|
3785
3652
|
*
|
|
3786
|
-
*
|
|
3787
|
-
*
|
|
3788
|
-
* DialectFactory.register('my-tenant-dialect', () => new CustomDialect());
|
|
3653
|
+
* Implementations are structural: extending DialectBase/SqlDialectBase is
|
|
3654
|
+
* optional. A composed object satisfying Dialect is a valid registration.
|
|
3789
3655
|
*/
|
|
3790
3656
|
static register(key, factory) {
|
|
3791
3657
|
this.registry.set(key, factory);
|
|
@@ -8404,14 +8270,11 @@ var addTransformerMetadata = (target, propertyKey, transformer) => {
|
|
|
8404
8270
|
const meta = ensureEntityMetadata(target);
|
|
8405
8271
|
meta.transformers[propertyKey] = transformer;
|
|
8406
8272
|
};
|
|
8407
|
-
var setEntityTableName = (target, tableName,
|
|
8273
|
+
var setEntityTableName = (target, tableName, type) => {
|
|
8408
8274
|
const meta = ensureEntityMetadata(target);
|
|
8409
8275
|
if (tableName && tableName.length > 0) {
|
|
8410
8276
|
meta.tableName = tableName;
|
|
8411
8277
|
}
|
|
8412
|
-
if (hooks) {
|
|
8413
|
-
meta.hooks = hooks;
|
|
8414
|
-
}
|
|
8415
8278
|
if (type) {
|
|
8416
8279
|
meta.type = type;
|
|
8417
8280
|
}
|
|
@@ -8428,7 +8291,7 @@ var buildTableDef = (meta) => {
|
|
|
8428
8291
|
table: meta.tableName
|
|
8429
8292
|
};
|
|
8430
8293
|
}
|
|
8431
|
-
const table = defineTable(meta.tableName, columns
|
|
8294
|
+
const table = defineTable(meta.tableName, columns);
|
|
8432
8295
|
meta.table = table;
|
|
8433
8296
|
return table;
|
|
8434
8297
|
};
|
|
@@ -11361,6 +11224,15 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
11361
11224
|
};
|
|
11362
11225
|
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
11363
11226
|
|
|
11227
|
+
// src/core/dialect/capabilities/procedure-compiler.ts
|
|
11228
|
+
var isProcedureCompiler = (value) => typeof value?.compileProcedureCall === "function";
|
|
11229
|
+
var requireProcedureCompiler = (value) => {
|
|
11230
|
+
if (!isProcedureCompiler(value)) {
|
|
11231
|
+
throw new Error("Stored procedures are not supported by this dialect.");
|
|
11232
|
+
}
|
|
11233
|
+
return value;
|
|
11234
|
+
};
|
|
11235
|
+
|
|
11364
11236
|
// src/orm/execute-procedure.ts
|
|
11365
11237
|
var resolveColumnIndex = (columns, expectedName) => {
|
|
11366
11238
|
const exact = columns.findIndex((column) => column === expectedName);
|
|
@@ -11399,7 +11271,7 @@ var extractOutValues = (compiled, resultSets) => {
|
|
|
11399
11271
|
};
|
|
11400
11272
|
var executeProcedureAst = async (session, ast) => {
|
|
11401
11273
|
const execCtx = session.getExecutionContext();
|
|
11402
|
-
const compiled = execCtx.dialect.compileProcedureCall(ast);
|
|
11274
|
+
const compiled = requireProcedureCompiler(execCtx.dialect).compileProcedureCall(ast);
|
|
11403
11275
|
const payload = await execCtx.interceptors.run(
|
|
11404
11276
|
{ sql: compiled.sql, params: compiled.params },
|
|
11405
11277
|
execCtx.executor
|
|
@@ -11472,8 +11344,7 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
|
|
|
11472
11344
|
}
|
|
11473
11345
|
compile(dialect) {
|
|
11474
11346
|
const resolved = resolveDialectInput(dialect);
|
|
11475
|
-
this.
|
|
11476
|
-
return resolved.compileProcedureCall(this.getAST());
|
|
11347
|
+
return requireProcedureCompiler(resolved).compileProcedureCall(this.getAST());
|
|
11477
11348
|
}
|
|
11478
11349
|
toSql(dialect) {
|
|
11479
11350
|
return this.compile(dialect).sql;
|
|
@@ -11486,21 +11357,8 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
|
|
|
11486
11357
|
};
|
|
11487
11358
|
}
|
|
11488
11359
|
async execute(session) {
|
|
11489
|
-
this.validateMssqlOutDbType(session.getExecutionContext().dialect);
|
|
11490
11360
|
return executeProcedureAst(session, this.getAST());
|
|
11491
11361
|
}
|
|
11492
|
-
validateMssqlOutDbType(dialect) {
|
|
11493
|
-
const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
|
|
11494
|
-
if (!isMssqlDialect) return;
|
|
11495
|
-
for (const param of this.ast.params) {
|
|
11496
|
-
const needsDbType = param.direction === "out" || param.direction === "inout";
|
|
11497
|
-
if (needsDbType && !param.dbType) {
|
|
11498
|
-
throw new Error(
|
|
11499
|
-
`MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
|
|
11500
|
-
);
|
|
11501
|
-
}
|
|
11502
|
-
}
|
|
11503
|
-
}
|
|
11504
11362
|
};
|
|
11505
11363
|
var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
|
|
11506
11364
|
|
|
@@ -11850,7 +11708,6 @@ var PgInformationSchemaColumns = defineTable(
|
|
|
11850
11708
|
ordinal_position: col.int()
|
|
11851
11709
|
},
|
|
11852
11710
|
{},
|
|
11853
|
-
void 0,
|
|
11854
11711
|
{ schema: "information_schema" }
|
|
11855
11712
|
);
|
|
11856
11713
|
var PgClass = defineTable(
|
|
@@ -11862,7 +11719,6 @@ var PgClass = defineTable(
|
|
|
11862
11719
|
relkind: col.varchar(1)
|
|
11863
11720
|
},
|
|
11864
11721
|
{},
|
|
11865
|
-
void 0,
|
|
11866
11722
|
{ schema: "pg_catalog" }
|
|
11867
11723
|
);
|
|
11868
11724
|
var PgNamespace = defineTable(
|
|
@@ -11872,7 +11728,6 @@ var PgNamespace = defineTable(
|
|
|
11872
11728
|
nspname: col.varchar(255)
|
|
11873
11729
|
},
|
|
11874
11730
|
{},
|
|
11875
|
-
void 0,
|
|
11876
11731
|
{ schema: "pg_catalog" }
|
|
11877
11732
|
);
|
|
11878
11733
|
var PgIndex = defineTable(
|
|
@@ -11885,7 +11740,6 @@ var PgIndex = defineTable(
|
|
|
11885
11740
|
indpred: col.varchar(1024)
|
|
11886
11741
|
},
|
|
11887
11742
|
{},
|
|
11888
|
-
void 0,
|
|
11889
11743
|
{ schema: "pg_catalog" }
|
|
11890
11744
|
);
|
|
11891
11745
|
var PgAttribute = defineTable(
|
|
@@ -11896,7 +11750,6 @@ var PgAttribute = defineTable(
|
|
|
11896
11750
|
attnum: col.int()
|
|
11897
11751
|
},
|
|
11898
11752
|
{},
|
|
11899
|
-
void 0,
|
|
11900
11753
|
{ schema: "pg_catalog" }
|
|
11901
11754
|
);
|
|
11902
11755
|
var PgTableConstraints = defineTable(
|
|
@@ -11911,7 +11764,6 @@ var PgTableConstraints = defineTable(
|
|
|
11911
11764
|
constraint_type: col.varchar(255)
|
|
11912
11765
|
},
|
|
11913
11766
|
{},
|
|
11914
|
-
void 0,
|
|
11915
11767
|
{ schema: "information_schema" }
|
|
11916
11768
|
);
|
|
11917
11769
|
var PgKeyColumnUsage = defineTable(
|
|
@@ -11927,7 +11779,6 @@ var PgKeyColumnUsage = defineTable(
|
|
|
11927
11779
|
ordinal_position: col.int()
|
|
11928
11780
|
},
|
|
11929
11781
|
{},
|
|
11930
|
-
void 0,
|
|
11931
11782
|
{ schema: "information_schema" }
|
|
11932
11783
|
);
|
|
11933
11784
|
var PgConstraintColumnUsage = defineTable(
|
|
@@ -11942,7 +11793,6 @@ var PgConstraintColumnUsage = defineTable(
|
|
|
11942
11793
|
column_name: col.varchar(255)
|
|
11943
11794
|
},
|
|
11944
11795
|
{},
|
|
11945
|
-
void 0,
|
|
11946
11796
|
{ schema: "information_schema" }
|
|
11947
11797
|
);
|
|
11948
11798
|
var PgReferentialConstraints = defineTable(
|
|
@@ -11959,7 +11809,6 @@ var PgReferentialConstraints = defineTable(
|
|
|
11959
11809
|
delete_rule: col.varchar(64)
|
|
11960
11810
|
},
|
|
11961
11811
|
{},
|
|
11962
|
-
void 0,
|
|
11963
11812
|
{ schema: "information_schema" }
|
|
11964
11813
|
);
|
|
11965
11814
|
|
|
@@ -12341,7 +12190,6 @@ var InformationSchemaTables = defineTable(
|
|
|
12341
12190
|
table_comment: col.varchar(1024)
|
|
12342
12191
|
},
|
|
12343
12192
|
{},
|
|
12344
|
-
void 0,
|
|
12345
12193
|
{ schema: INFORMATION_SCHEMA }
|
|
12346
12194
|
);
|
|
12347
12195
|
var InformationSchemaColumns = defineTable(
|
|
@@ -12359,7 +12207,6 @@ var InformationSchemaColumns = defineTable(
|
|
|
12359
12207
|
ordinal_position: col.int()
|
|
12360
12208
|
},
|
|
12361
12209
|
{},
|
|
12362
|
-
void 0,
|
|
12363
12210
|
{ schema: INFORMATION_SCHEMA }
|
|
12364
12211
|
);
|
|
12365
12212
|
var InformationSchemaKeyColumnUsage = defineTable(
|
|
@@ -12376,7 +12223,6 @@ var InformationSchemaKeyColumnUsage = defineTable(
|
|
|
12376
12223
|
referenced_column_name: col.varchar(255)
|
|
12377
12224
|
},
|
|
12378
12225
|
{},
|
|
12379
|
-
void 0,
|
|
12380
12226
|
{ schema: INFORMATION_SCHEMA }
|
|
12381
12227
|
);
|
|
12382
12228
|
var InformationSchemaReferentialConstraints = defineTable(
|
|
@@ -12388,7 +12234,6 @@ var InformationSchemaReferentialConstraints = defineTable(
|
|
|
12388
12234
|
update_rule: col.varchar(255)
|
|
12389
12235
|
},
|
|
12390
12236
|
{},
|
|
12391
|
-
void 0,
|
|
12392
12237
|
{ schema: INFORMATION_SCHEMA }
|
|
12393
12238
|
);
|
|
12394
12239
|
var InformationSchemaStatistics = defineTable(
|
|
@@ -12402,7 +12247,6 @@ var InformationSchemaStatistics = defineTable(
|
|
|
12402
12247
|
seq_in_index: col.int()
|
|
12403
12248
|
},
|
|
12404
12249
|
{},
|
|
12405
|
-
void 0,
|
|
12406
12250
|
{ schema: INFORMATION_SCHEMA }
|
|
12407
12251
|
);
|
|
12408
12252
|
|
|
@@ -13023,7 +12867,6 @@ var SysColumns = defineTable(
|
|
|
13023
12867
|
user_type_id: col.int()
|
|
13024
12868
|
},
|
|
13025
12869
|
{},
|
|
13026
|
-
void 0,
|
|
13027
12870
|
{ schema: "sys" }
|
|
13028
12871
|
);
|
|
13029
12872
|
var SysTables = defineTable(
|
|
@@ -13035,7 +12878,6 @@ var SysTables = defineTable(
|
|
|
13035
12878
|
is_ms_shipped: col.boolean()
|
|
13036
12879
|
},
|
|
13037
12880
|
{},
|
|
13038
|
-
void 0,
|
|
13039
12881
|
{ schema: "sys" }
|
|
13040
12882
|
);
|
|
13041
12883
|
var SysSchemas = defineTable(
|
|
@@ -13045,7 +12887,6 @@ var SysSchemas = defineTable(
|
|
|
13045
12887
|
name: col.varchar(255)
|
|
13046
12888
|
},
|
|
13047
12889
|
{},
|
|
13048
|
-
void 0,
|
|
13049
12890
|
{ schema: "sys" }
|
|
13050
12891
|
);
|
|
13051
12892
|
var SysTypes = defineTable(
|
|
@@ -13055,7 +12896,6 @@ var SysTypes = defineTable(
|
|
|
13055
12896
|
name: col.varchar(255)
|
|
13056
12897
|
},
|
|
13057
12898
|
{},
|
|
13058
|
-
void 0,
|
|
13059
12899
|
{ schema: "sys" }
|
|
13060
12900
|
);
|
|
13061
12901
|
var SysIndexes = defineTable(
|
|
@@ -13071,7 +12911,6 @@ var SysIndexes = defineTable(
|
|
|
13071
12911
|
is_hypothetical: col.boolean()
|
|
13072
12912
|
},
|
|
13073
12913
|
{},
|
|
13074
|
-
void 0,
|
|
13075
12914
|
{ schema: "sys" }
|
|
13076
12915
|
);
|
|
13077
12916
|
var SysIndexColumns = defineTable(
|
|
@@ -13083,7 +12922,6 @@ var SysIndexColumns = defineTable(
|
|
|
13083
12922
|
key_ordinal: col.int()
|
|
13084
12923
|
},
|
|
13085
12924
|
{},
|
|
13086
|
-
void 0,
|
|
13087
12925
|
{ schema: "sys" }
|
|
13088
12926
|
);
|
|
13089
12927
|
var SysForeignKeys = defineTable(
|
|
@@ -13095,7 +12933,6 @@ var SysForeignKeys = defineTable(
|
|
|
13095
12933
|
update_referential_action_desc: col.varchar(64)
|
|
13096
12934
|
},
|
|
13097
12935
|
{},
|
|
13098
|
-
void 0,
|
|
13099
12936
|
{ schema: "sys" }
|
|
13100
12937
|
);
|
|
13101
12938
|
var SysForeignKeyColumns = defineTable(
|
|
@@ -13109,7 +12946,6 @@ var SysForeignKeyColumns = defineTable(
|
|
|
13109
12946
|
constraint_column_id: col.int()
|
|
13110
12947
|
},
|
|
13111
12948
|
{},
|
|
13112
|
-
void 0,
|
|
13113
12949
|
{ schema: "sys" }
|
|
13114
12950
|
);
|
|
13115
12951
|
|
|
@@ -14534,12 +14370,14 @@ var UnitOfWork = class {
|
|
|
14534
14370
|
* @param executor - The database executor
|
|
14535
14371
|
* @param identityMap - The identity map
|
|
14536
14372
|
* @param hookContext - Function to get the hook context
|
|
14373
|
+
* @param resolveTableHooks - Session/runtime lifecycle hook resolver
|
|
14537
14374
|
*/
|
|
14538
|
-
constructor(dialect, executor, identityMap, hookContext) {
|
|
14375
|
+
constructor(dialect, executor, identityMap, hookContext, resolveTableHooks = () => void 0) {
|
|
14539
14376
|
this.dialect = dialect;
|
|
14540
14377
|
this.executor = executor;
|
|
14541
14378
|
this.identityMap = identityMap;
|
|
14542
14379
|
this.hookContext = hookContext;
|
|
14380
|
+
this.resolveTableHooks = resolveTableHooks;
|
|
14543
14381
|
}
|
|
14544
14382
|
trackedEntities = /* @__PURE__ */ new Map();
|
|
14545
14383
|
/**
|
|
@@ -14691,7 +14529,8 @@ var UnitOfWork = class {
|
|
|
14691
14529
|
* @param tracked - The tracked entity to insert
|
|
14692
14530
|
*/
|
|
14693
14531
|
async flushInsert(tracked) {
|
|
14694
|
-
|
|
14532
|
+
const hooks = this.resolveTableHooks(tracked.table);
|
|
14533
|
+
await this.runHook(hooks?.beforeInsert, tracked);
|
|
14695
14534
|
const payload = this.extractColumns(tracked.table, tracked.entity);
|
|
14696
14535
|
let builder = new InsertQueryBuilder(tracked.table).values(payload);
|
|
14697
14536
|
if (this.dialect.supportsDmlReturningClause()) {
|
|
@@ -14705,7 +14544,7 @@ var UnitOfWork = class {
|
|
|
14705
14544
|
tracked.original = this.createSnapshot(tracked.table, tracked.entity);
|
|
14706
14545
|
tracked.pk = this.getPrimaryKeyValue(tracked);
|
|
14707
14546
|
this.registerIdentity(tracked);
|
|
14708
|
-
await this.runHook(
|
|
14547
|
+
await this.runHook(hooks?.afterInsert, tracked);
|
|
14709
14548
|
}
|
|
14710
14549
|
/**
|
|
14711
14550
|
* Flushes an update operation for a modified entity.
|
|
@@ -14718,7 +14557,8 @@ var UnitOfWork = class {
|
|
|
14718
14557
|
tracked.status = "managed" /* Managed */;
|
|
14719
14558
|
return;
|
|
14720
14559
|
}
|
|
14721
|
-
|
|
14560
|
+
const hooks = this.resolveTableHooks(tracked.table);
|
|
14561
|
+
await this.runHook(hooks?.beforeUpdate, tracked);
|
|
14722
14562
|
const pkColumn = tracked.table.columns[findPrimaryKey(tracked.table)];
|
|
14723
14563
|
if (!pkColumn) return;
|
|
14724
14564
|
let builder = new UpdateQueryBuilder(tracked.table).set(changes).where(eq(pkColumn, tracked.pk));
|
|
@@ -14731,7 +14571,7 @@ var UnitOfWork = class {
|
|
|
14731
14571
|
tracked.status = "managed" /* Managed */;
|
|
14732
14572
|
tracked.original = this.createSnapshot(tracked.table, tracked.entity);
|
|
14733
14573
|
this.registerIdentity(tracked);
|
|
14734
|
-
await this.runHook(
|
|
14574
|
+
await this.runHook(hooks?.afterUpdate, tracked);
|
|
14735
14575
|
}
|
|
14736
14576
|
/**
|
|
14737
14577
|
* Flushes a delete operation for a removed entity.
|
|
@@ -14739,7 +14579,8 @@ var UnitOfWork = class {
|
|
|
14739
14579
|
*/
|
|
14740
14580
|
async flushDelete(tracked) {
|
|
14741
14581
|
if (tracked.pk == null) return;
|
|
14742
|
-
|
|
14582
|
+
const hooks = this.resolveTableHooks(tracked.table);
|
|
14583
|
+
await this.runHook(hooks?.beforeDelete, tracked);
|
|
14743
14584
|
const pkColumn = tracked.table.columns[findPrimaryKey(tracked.table)];
|
|
14744
14585
|
if (!pkColumn) return;
|
|
14745
14586
|
const builder = new DeleteQueryBuilder(tracked.table).where(eq(pkColumn, tracked.pk));
|
|
@@ -14748,10 +14589,10 @@ var UnitOfWork = class {
|
|
|
14748
14589
|
tracked.status = "detached" /* Detached */;
|
|
14749
14590
|
this.trackedEntities.delete(tracked.entity);
|
|
14750
14591
|
this.identityMap.remove(tracked);
|
|
14751
|
-
await this.runHook(
|
|
14592
|
+
await this.runHook(hooks?.afterDelete, tracked);
|
|
14752
14593
|
}
|
|
14753
14594
|
/**
|
|
14754
|
-
* Runs a
|
|
14595
|
+
* Runs a lifecycle hook if defined.
|
|
14755
14596
|
* @param hook - The hook function
|
|
14756
14597
|
* @param tracked - The tracked entity
|
|
14757
14598
|
*/
|
|
@@ -15656,6 +15497,7 @@ var OrmSession = class {
|
|
|
15656
15497
|
/** The tenant ID for multi-tenancy support */
|
|
15657
15498
|
tenantId;
|
|
15658
15499
|
interceptors;
|
|
15500
|
+
tableHooks = /* @__PURE__ */ new WeakMap();
|
|
15659
15501
|
saveGraphDefaults;
|
|
15660
15502
|
transactionDepth = 0;
|
|
15661
15503
|
savepointCounter = 0;
|
|
@@ -15669,7 +15511,13 @@ var OrmSession = class {
|
|
|
15669
15511
|
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
15670
15512
|
this.interceptors = [...opts.interceptors ?? []];
|
|
15671
15513
|
this.identityMap = new IdentityMap();
|
|
15672
|
-
this.unitOfWork = new UnitOfWork(
|
|
15514
|
+
this.unitOfWork = new UnitOfWork(
|
|
15515
|
+
this.orm.dialect,
|
|
15516
|
+
this.executor,
|
|
15517
|
+
this.identityMap,
|
|
15518
|
+
() => this,
|
|
15519
|
+
(table) => this.tableHooks.get(table)
|
|
15520
|
+
);
|
|
15673
15521
|
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
15674
15522
|
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
15675
15523
|
this.cacheManager = opts.cacheManager;
|
|
@@ -15777,6 +15625,18 @@ var OrmSession = class {
|
|
|
15777
15625
|
getEntitiesForTable(table) {
|
|
15778
15626
|
return this.unitOfWork.getEntitiesForTable(table);
|
|
15779
15627
|
}
|
|
15628
|
+
/**
|
|
15629
|
+
* Registers INSERT/UPDATE/DELETE lifecycle hooks for this Session only.
|
|
15630
|
+
* The target can be a TableDef or a decorated entity constructor.
|
|
15631
|
+
* Registering again for the same table replaces the previous hook set.
|
|
15632
|
+
*/
|
|
15633
|
+
registerTableHooks(target, hooks) {
|
|
15634
|
+
const table = typeof target === "function" ? getTableDefFromEntity(target) : target;
|
|
15635
|
+
if (!table) {
|
|
15636
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
15637
|
+
}
|
|
15638
|
+
this.tableHooks.set(table, hooks);
|
|
15639
|
+
}
|
|
15780
15640
|
/**
|
|
15781
15641
|
* Registers an interceptor for flush lifecycle hooks.
|
|
15782
15642
|
* @param interceptor - The interceptor to register
|
|
@@ -15787,7 +15647,7 @@ var OrmSession = class {
|
|
|
15787
15647
|
/**
|
|
15788
15648
|
* Registers a domain event handler.
|
|
15789
15649
|
* @param type - The event type
|
|
15790
|
-
* @param handler - The event handler
|
|
15650
|
+
* @param handler - The domain event handler
|
|
15791
15651
|
*/
|
|
15792
15652
|
registerDomainEventHandler(type, handler) {
|
|
15793
15653
|
this.domainEvents.on(type, handler);
|
|
@@ -15961,7 +15821,9 @@ var OrmSession = class {
|
|
|
15961
15821
|
this.markRemoved(entity);
|
|
15962
15822
|
}
|
|
15963
15823
|
/**
|
|
15964
|
-
* Flushes pending changes to the database without session
|
|
15824
|
+
* Flushes pending changes to the database without session interceptors,
|
|
15825
|
+
* relation processing, or domain events. Table lifecycle hooks still run
|
|
15826
|
+
* because they are part of the Unit of Work.
|
|
15965
15827
|
*/
|
|
15966
15828
|
async flush() {
|
|
15967
15829
|
await this.unitOfWork.flush();
|
|
@@ -16856,7 +16718,7 @@ function Entity(options = {}) {
|
|
|
16856
16718
|
return function(value, context) {
|
|
16857
16719
|
const ctor = value;
|
|
16858
16720
|
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
16859
|
-
setEntityTableName(ctor, tableName, options.
|
|
16721
|
+
setEntityTableName(ctor, tableName, options.type);
|
|
16860
16722
|
const bag = context ? readMetadataBag(context) : readMetadataBagFromConstructor(ctor);
|
|
16861
16723
|
if (bag) {
|
|
16862
16724
|
const meta = ensureEntityMetadata(ctor);
|
|
@@ -21076,7 +20938,7 @@ var TreeManager = class _TreeManager {
|
|
|
21076
20938
|
* Moves a node to be the last child of a new parent.
|
|
21077
20939
|
*/
|
|
21078
20940
|
async moveTo(node, newParentId) {
|
|
21079
|
-
NestedSetStrategy.subtreeWidth(node.lft, node.rght);
|
|
20941
|
+
const width = NestedSetStrategy.subtreeWidth(node.lft, node.rght);
|
|
21080
20942
|
let newPos;
|
|
21081
20943
|
if (newParentId === null) {
|
|
21082
20944
|
const maxRght = await this.getMaxRght();
|
|
@@ -21091,7 +20953,8 @@ var TreeManager = class _TreeManager {
|
|
|
21091
20953
|
newParent.depth ?? await this.getLevel(newParent)
|
|
21092
20954
|
);
|
|
21093
20955
|
}
|
|
21094
|
-
|
|
20956
|
+
const targetLft = newPos.lft > node.rght ? newPos.lft - width : newPos.lft;
|
|
20957
|
+
await this.moveSubtree(node, targetLft, newParentId, newPos.depth);
|
|
21095
20958
|
}
|
|
21096
20959
|
/**
|
|
21097
20960
|
* Inserts a new node as a child of a parent.
|
|
@@ -21130,7 +20993,10 @@ var TreeManager = class _TreeManager {
|
|
|
21130
20993
|
if (insertData[this.pkName] !== void 0) {
|
|
21131
20994
|
return insertData[this.pkName];
|
|
21132
20995
|
}
|
|
21133
|
-
const
|
|
20996
|
+
const scopeExpressions = this.getScopeExpressions();
|
|
20997
|
+
const lftCondition = eq(this.table.columns[this.config.leftKey], insertPos.lft);
|
|
20998
|
+
const findCondition = scopeExpressions.length > 0 ? and(lftCondition, ...scopeExpressions) : lftCondition;
|
|
20999
|
+
const findQuery = selectFrom(this.table).where(findCondition);
|
|
21134
21000
|
const { sql: findSql, params: findParams } = findQuery.compile(this.dialect);
|
|
21135
21001
|
const results = await this.executor.executeSql(findSql, findParams);
|
|
21136
21002
|
const rows = queryResultsToRows(results);
|
|
@@ -21140,23 +21006,37 @@ var TreeManager = class _TreeManager {
|
|
|
21140
21006
|
return void 0;
|
|
21141
21007
|
}
|
|
21142
21008
|
/**
|
|
21143
|
-
* Removes a node
|
|
21009
|
+
* Removes a node from its current tree position, promotes its direct children
|
|
21010
|
+
* to the removed node's parent, and retains the removed row as a standalone root.
|
|
21144
21011
|
*/
|
|
21145
21012
|
async removeFromTree(node) {
|
|
21146
21013
|
const nodeId = node.data[this.pkName];
|
|
21014
|
+
const originalMaxRght = await this.getMaxRght();
|
|
21147
21015
|
await this.executeUpdate(
|
|
21148
21016
|
eq(this.table.columns[this.config.parentKey], nodeId),
|
|
21149
21017
|
{ [this.config.parentKey]: node.parentId }
|
|
21150
21018
|
);
|
|
21151
|
-
|
|
21019
|
+
if (node.rght - node.lft > 1) {
|
|
21020
|
+
let sql = `UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} - 1, ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} - 1`;
|
|
21021
|
+
if (this.config.depthKey) {
|
|
21022
|
+
sql += `, ${this.quoteCol(this.config.depthKey)} = ${this.quoteCol(this.config.depthKey)} - 1`;
|
|
21023
|
+
}
|
|
21024
|
+
sql += ` WHERE ${this.quoteCol(this.config.leftKey)} > ? AND ${this.quoteCol(this.config.rightKey)} < ?`;
|
|
21025
|
+
await this.executeRawUpdate(sql, [node.lft, node.rght]);
|
|
21026
|
+
}
|
|
21152
21027
|
await this.shiftForDelete(node.rght, 2);
|
|
21153
|
-
|
|
21154
|
-
|
|
21155
|
-
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
|
|
21028
|
+
const detachedData = {
|
|
21029
|
+
[this.config.parentKey]: null,
|
|
21030
|
+
[this.config.leftKey]: originalMaxRght - 1,
|
|
21031
|
+
[this.config.rightKey]: originalMaxRght
|
|
21032
|
+
};
|
|
21033
|
+
if (this.config.depthKey) {
|
|
21034
|
+
detachedData[this.config.depthKey] = 0;
|
|
21159
21035
|
}
|
|
21036
|
+
await this.executeUpdate(
|
|
21037
|
+
eq(this.table.columns[this.pkName], nodeId),
|
|
21038
|
+
detachedData
|
|
21039
|
+
);
|
|
21160
21040
|
}
|
|
21161
21041
|
/**
|
|
21162
21042
|
* Deletes a node and all its descendants.
|
|
@@ -21281,22 +21161,32 @@ var TreeManager = class _TreeManager {
|
|
|
21281
21161
|
}
|
|
21282
21162
|
return "id";
|
|
21283
21163
|
}
|
|
21164
|
+
getScopeEntries() {
|
|
21165
|
+
return Object.entries(buildScopeConditions(this.config.scope, this.scopeValues));
|
|
21166
|
+
}
|
|
21167
|
+
getScopeExpressions() {
|
|
21168
|
+
return this.getScopeEntries().map(
|
|
21169
|
+
([key, value]) => eq(this.table.columns[key], value)
|
|
21170
|
+
);
|
|
21171
|
+
}
|
|
21284
21172
|
async getMaxRght() {
|
|
21285
21173
|
const query = selectFrom(this.table).selectRaw(`MAX(${this.config.rightKey}) as max_rght`);
|
|
21286
|
-
const
|
|
21174
|
+
const scopeExpressions = this.getScopeExpressions();
|
|
21175
|
+
const finalQuery = scopeExpressions.length > 0 ? query.where(and(...scopeExpressions)) : query;
|
|
21176
|
+
const { sql, params } = finalQuery.compile(this.dialect);
|
|
21287
21177
|
const queryResults = await this.executor.executeSql(sql, params);
|
|
21288
21178
|
const rows = queryResultsToRows(queryResults);
|
|
21289
21179
|
const maxRght = rows[0]?.max_rght;
|
|
21290
21180
|
return typeof maxRght === "number" ? maxRght : 0;
|
|
21291
21181
|
}
|
|
21292
|
-
async shiftForInsert(insertPoint) {
|
|
21182
|
+
async shiftForInsert(insertPoint, width = 2) {
|
|
21293
21183
|
await this.executeRawUpdate(
|
|
21294
|
-
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} +
|
|
21295
|
-
[insertPoint]
|
|
21184
|
+
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ? WHERE ${this.quoteCol(this.config.rightKey)} >= ?`,
|
|
21185
|
+
[width, insertPoint]
|
|
21296
21186
|
);
|
|
21297
21187
|
await this.executeRawUpdate(
|
|
21298
|
-
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} +
|
|
21299
|
-
[insertPoint]
|
|
21188
|
+
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} + ? WHERE ${this.quoteCol(this.config.leftKey)} > ?`,
|
|
21189
|
+
[width, insertPoint]
|
|
21300
21190
|
);
|
|
21301
21191
|
}
|
|
21302
21192
|
async shiftForDelete(deletedRght, width) {
|
|
@@ -21332,28 +21222,27 @@ var TreeManager = class _TreeManager {
|
|
|
21332
21222
|
}
|
|
21333
21223
|
async moveSubtree(node, newLft, newParentId, newDepth) {
|
|
21334
21224
|
const width = NestedSetStrategy.subtreeWidth(node.lft, node.rght);
|
|
21335
|
-
const
|
|
21336
|
-
const depthDelta = this.config.depthKey ? newDepth -
|
|
21225
|
+
const oldDepth = this.config.depthKey ? node.depth ?? await this.getLevel(node) : 0;
|
|
21226
|
+
const depthDelta = this.config.depthKey ? newDepth - oldDepth : 0;
|
|
21337
21227
|
const nodeId = node.data[this.pkName];
|
|
21338
|
-
const
|
|
21339
|
-
|
|
21340
|
-
|
|
21341
|
-
[tempOffset, node.lft, node.rght]
|
|
21342
|
-
);
|
|
21228
|
+
const isolateDelta = -1e7 - node.rght;
|
|
21229
|
+
const isolatedLft = node.lft + isolateDelta;
|
|
21230
|
+
const isolatedRght = node.rght + isolateDelta;
|
|
21343
21231
|
await this.executeRawUpdate(
|
|
21344
|
-
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ? WHERE ${this.quoteCol(this.config.leftKey)} >= ? AND ${this.quoteCol(this.config.rightKey)} <= ?`,
|
|
21345
|
-
[
|
|
21232
|
+
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} + ?, ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ? WHERE ${this.quoteCol(this.config.leftKey)} >= ? AND ${this.quoteCol(this.config.rightKey)} <= ?`,
|
|
21233
|
+
[isolateDelta, isolateDelta, node.lft, node.rght]
|
|
21346
21234
|
);
|
|
21347
21235
|
await this.shiftForDelete(node.rght, width);
|
|
21348
|
-
await this.shiftForInsert(newLft);
|
|
21349
|
-
|
|
21350
|
-
|
|
21236
|
+
await this.shiftForInsert(newLft, width);
|
|
21237
|
+
const restoreDelta = newLft - node.lft - isolateDelta;
|
|
21238
|
+
let updateSql = `UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} + ?, ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ?`;
|
|
21239
|
+
const updateParams = [restoreDelta, restoreDelta];
|
|
21351
21240
|
if (this.config.depthKey && depthDelta !== 0) {
|
|
21352
21241
|
updateSql += `, ${this.quoteCol(this.config.depthKey)} = ${this.quoteCol(this.config.depthKey)} + ?`;
|
|
21353
21242
|
updateParams.push(depthDelta);
|
|
21354
21243
|
}
|
|
21355
|
-
updateSql += ` WHERE ${this.quoteCol(this.config.leftKey)} >= ?`;
|
|
21356
|
-
updateParams.push(
|
|
21244
|
+
updateSql += ` WHERE ${this.quoteCol(this.config.leftKey)} >= ? AND ${this.quoteCol(this.config.rightKey)} <= ?`;
|
|
21245
|
+
updateParams.push(isolatedLft, isolatedRght);
|
|
21357
21246
|
await this.executeRawUpdate(updateSql, updateParams);
|
|
21358
21247
|
await this.executeUpdate(
|
|
21359
21248
|
eq(this.table.columns[this.pkName], nodeId),
|
|
@@ -21378,12 +21267,23 @@ var TreeManager = class _TreeManager {
|
|
|
21378
21267
|
}));
|
|
21379
21268
|
}
|
|
21380
21269
|
async executeUpdate(condition, data) {
|
|
21381
|
-
const
|
|
21270
|
+
const scopeExpressions = this.getScopeExpressions();
|
|
21271
|
+
const finalCondition = scopeExpressions.length > 0 ? and(condition, ...scopeExpressions) : condition;
|
|
21272
|
+
const query = update(this.table).set(data).where(finalCondition);
|
|
21382
21273
|
const { sql, params } = query.compile(this.dialect);
|
|
21383
21274
|
await this.executor.executeSql(sql, params);
|
|
21384
21275
|
}
|
|
21385
21276
|
async executeRawUpdate(sql, params) {
|
|
21386
|
-
|
|
21277
|
+
let scopedSql = sql;
|
|
21278
|
+
const scopedParams = [...params];
|
|
21279
|
+
let hasWhere = /\bWHERE\b/i.test(scopedSql);
|
|
21280
|
+
for (const [key, value] of this.getScopeEntries()) {
|
|
21281
|
+
scopedSql += hasWhere ? " AND " : " WHERE ";
|
|
21282
|
+
scopedSql += `${this.quoteCol(key)} = ?`;
|
|
21283
|
+
scopedParams.push(value);
|
|
21284
|
+
hasWhere = true;
|
|
21285
|
+
}
|
|
21286
|
+
await this.executor.executeSql(scopedSql, scopedParams);
|
|
21387
21287
|
}
|
|
21388
21288
|
quoteTable() {
|
|
21389
21289
|
const quote = this.getQuoteChar();
|
|
@@ -22187,6 +22087,8 @@ async function bulkUpsert(session, table, rows, options = {}) {
|
|
|
22187
22087
|
DefaultMorphToReference,
|
|
22188
22088
|
DefaultTypeStrategy,
|
|
22189
22089
|
DeleteQueryBuilder,
|
|
22090
|
+
DialectBase,
|
|
22091
|
+
DialectFactory,
|
|
22190
22092
|
DomainEventBus,
|
|
22191
22093
|
Email,
|
|
22192
22094
|
Entity,
|
|
@@ -22414,6 +22316,7 @@ async function bulkUpsert(session, table, rows, options = {}) {
|
|
|
22414
22316
|
isNull,
|
|
22415
22317
|
isNullableColumn,
|
|
22416
22318
|
isOperandNode,
|
|
22319
|
+
isProcedureCompiler,
|
|
22417
22320
|
isSingleTargetRelation,
|
|
22418
22321
|
isTableDef,
|
|
22419
22322
|
isTreeConfig,
|
|
@@ -22511,6 +22414,8 @@ async function bulkUpsert(session, table, rows, options = {}) {
|
|
|
22511
22414
|
repeat,
|
|
22512
22415
|
replace,
|
|
22513
22416
|
replaceWithRefs,
|
|
22417
|
+
requireProcedureCompiler,
|
|
22418
|
+
resolveDialectInput,
|
|
22514
22419
|
resolveTreeConfig,
|
|
22515
22420
|
resolveValidator,
|
|
22516
22421
|
responseToRef,
|