metal-orm 1.1.22 → 1.1.24

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 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,
@@ -107,6 +109,11 @@ __export(index_exports, {
107
109
  SelectQueryBuilder: () => SelectQueryBuilder,
108
110
  SqlServerDialect: () => SqlServerDialect,
109
111
  SqliteDialect: () => SqliteDialect,
112
+ StandardDeleteCompiler: () => StandardDeleteCompiler,
113
+ StandardInsertCompiler: () => StandardInsertCompiler,
114
+ StandardSelectCompiler: () => StandardSelectCompiler,
115
+ StandardSqlSourceCompiler: () => StandardSqlSourceCompiler,
116
+ StandardUpdateCompiler: () => StandardUpdateCompiler,
110
117
  StringTypeStrategy: () => StringTypeStrategy,
111
118
  TagIndex: () => TagIndex,
112
119
  Title: () => Title,
@@ -301,6 +308,7 @@ __export(index_exports, {
301
308
  isNull: () => isNull,
302
309
  isNullableColumn: () => isNullableColumn,
303
310
  isOperandNode: () => isOperandNode,
311
+ isProcedureCompiler: () => isProcedureCompiler,
304
312
  isSingleTargetRelation: () => isSingleTargetRelation,
305
313
  isTableDef: () => isTableDef2,
306
314
  isTreeConfig: () => isTreeConfig,
@@ -398,6 +406,8 @@ __export(index_exports, {
398
406
  repeat: () => repeat,
399
407
  replace: () => replace,
400
408
  replaceWithRefs: () => replaceWithRefs,
409
+ requireProcedureCompiler: () => requireProcedureCompiler,
410
+ resolveDialectInput: () => resolveDialectInput,
401
411
  resolveTreeConfig: () => resolveTreeConfig,
402
412
  resolveValidator: () => resolveValidator,
403
413
  responseToRef: () => responseToRef,
@@ -1755,268 +1765,40 @@ var StandardTableFunctionStrategy = class {
1755
1765
  }
1756
1766
  };
1757
1767
 
1758
- // src/core/dialect/abstract.ts
1759
- var Dialect = class _Dialect {
1760
- /**
1761
- * Compiles a SELECT query AST to SQL
1762
- * @param ast - Query AST to compile
1763
- * @returns Compiled query with SQL and parameters
1764
- */
1765
- compileSelect(ast) {
1766
- const ctx = this.createCompilerContext();
1767
- const normalized = this.normalizeSelectAst(ast);
1768
- const rawSql = this.compileSelectAst(normalized, ctx).trim();
1769
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1770
- return {
1771
- sql,
1772
- params: [...ctx.params]
1773
- };
1774
- }
1775
- compileInsert(ast) {
1776
- const ctx = this.createCompilerContext();
1777
- const rawSql = this.compileInsertAst(ast, ctx).trim();
1778
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1779
- return {
1780
- sql,
1781
- params: [...ctx.params]
1782
- };
1783
- }
1784
- compileUpdate(ast) {
1785
- const ctx = this.createCompilerContext();
1786
- const rawSql = this.compileUpdateAst(ast, ctx).trim();
1787
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1788
- return {
1789
- sql,
1790
- params: [...ctx.params]
1791
- };
1792
- }
1793
- compileDelete(ast) {
1794
- const ctx = this.createCompilerContext();
1795
- const rawSql = this.compileDeleteAst(ast, ctx).trim();
1796
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1797
- return {
1798
- sql,
1799
- params: [...ctx.params]
1800
- };
1801
- }
1802
- supportsDmlReturningClause() {
1803
- return false;
1804
- }
1805
- /**
1806
- * Compiles a WHERE clause
1807
- * @param where - WHERE expression
1808
- * @param ctx - Compiler context
1809
- * @returns SQL WHERE clause or empty string
1810
- */
1811
- compileWhere(where, ctx) {
1812
- if (!where) return "";
1813
- return ` WHERE ${this.compileExpression(where, ctx)}`;
1814
- }
1815
- compileReturning(returning, _ctx) {
1816
- void _ctx;
1817
- if (!returning || returning.length === 0) return "";
1818
- throw new Error("RETURNING is not supported by this dialect.");
1819
- }
1820
- /**
1821
- * Generates subquery for EXISTS expressions
1822
- * Rule: Always forces SELECT 1, ignoring column list
1823
- * Maintains FROM, JOINs, WHERE, GROUP BY, ORDER BY, LIMIT/OFFSET
1824
- * Does not add ';' at the end
1825
- * @param ast - Query AST
1826
- * @param ctx - Compiler context
1827
- * @returns SQL for EXISTS subquery
1828
- */
1829
- compileSelectForExists(ast, ctx) {
1830
- const normalized = this.normalizeSelectAst(ast);
1831
- const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1832
- if (normalized.setOps && normalized.setOps.length > 0) {
1833
- return `SELECT 1 FROM (${full}) AS _exists`;
1834
- }
1835
- const upper2 = full.toUpperCase();
1836
- const fromIndex = upper2.indexOf(" FROM ");
1837
- if (fromIndex === -1) {
1838
- return full;
1839
- }
1840
- const tail = full.slice(fromIndex);
1841
- return `SELECT 1${tail}`;
1842
- }
1843
- /**
1844
- * Creates a new compiler context
1845
- * @returns Compiler context with parameter management
1846
- */
1847
- createCompilerContext() {
1848
- const params = [];
1849
- let counter = 0;
1850
- return {
1851
- params,
1852
- addParameter: (value) => {
1853
- counter += 1;
1854
- params.push(value);
1855
- return this.formatPlaceholder(counter);
1856
- }
1857
- };
1858
- }
1859
- /**
1860
- * Formats a parameter placeholder
1861
- * @param index - Parameter index
1862
- * @returns Formatted placeholder string
1863
- */
1864
- formatPlaceholder(_index) {
1865
- void _index;
1866
- return "?";
1867
- }
1868
- /**
1869
- * Whether the current dialect supports a given set operation.
1870
- * Override in concrete dialects to restrict support.
1871
- */
1872
- supportsSetOperation(_kind) {
1873
- void _kind;
1874
- return true;
1875
- }
1876
- /**
1877
- * Validates set-operation semantics:
1878
- * - Ensures the dialect supports requested operators.
1879
- * - Enforces that only the outermost compound query may have ORDER/LIMIT/OFFSET.
1880
- * @param ast - Query to validate
1881
- * @param isOutermost - Whether this node is the outermost compound query
1882
- */
1883
- validateSetOperations(ast, isOutermost = true) {
1884
- const hasSetOps = !!(ast.setOps && ast.setOps.length);
1885
- if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
1886
- throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
1887
- }
1888
- if (hasSetOps) {
1889
- for (const op of ast.setOps) {
1890
- if (!this.supportsSetOperation(op.operator)) {
1891
- throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
1892
- }
1893
- this.validateSetOperations(op.query, false);
1894
- }
1895
- }
1896
- }
1897
- /**
1898
- * Hoists CTEs from set-operation operands to the outermost query so WITH appears once.
1899
- * @param ast - Query AST
1900
- * @returns Normalized AST without inner CTEs and a list of hoisted CTEs
1901
- */
1902
- hoistCtes(ast) {
1903
- let hoisted = [];
1904
- const normalizedSetOps = ast.setOps?.map((op) => {
1905
- const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
1906
- const childCtes = child.ctes ?? [];
1907
- if (childCtes.length) {
1908
- hoisted = hoisted.concat(childCtes);
1909
- }
1910
- hoisted = hoisted.concat(childHoisted);
1911
- const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
1912
- return { ...op, query: queryWithoutCtes };
1913
- });
1914
- const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
1915
- return { normalized, hoistedCtes: hoisted };
1916
- }
1917
- /**
1918
- * Normalizes a SELECT AST before compilation (validation + CTE hoisting).
1919
- * @param ast - Query AST
1920
- * @returns Normalized query AST
1921
- */
1922
- normalizeSelectAst(ast) {
1923
- this.validateSetOperations(ast, true);
1924
- const { normalized, hoistedCtes } = this.hoistCtes(ast);
1925
- const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
1926
- return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
1927
- }
1928
- expressionCompilers;
1929
- operandCompilers;
1930
- functionStrategy;
1931
- tableFunctionStrategy;
1932
- constructor(functionStrategy, tableFunctionStrategy) {
1933
- this.expressionCompilers = /* @__PURE__ */ new Map();
1934
- this.operandCompilers = /* @__PURE__ */ new Map();
1935
- this.functionStrategy = functionStrategy || new StandardFunctionStrategy();
1936
- this.tableFunctionStrategy = tableFunctionStrategy || new StandardTableFunctionStrategy();
1768
+ // src/core/dialect/base/expression-compiler-registry.ts
1769
+ var ExpressionCompilerRegistry = class {
1770
+ constructor(host) {
1771
+ this.host = host;
1937
1772
  this.registerDefaultOperandCompilers();
1938
1773
  this.registerDefaultExpressionCompilers();
1939
1774
  }
1940
- /**
1941
- * Creates a new Dialect instance (for testing purposes)
1942
- * @param functionStrategy - Optional function strategy
1943
- * @returns New Dialect instance
1944
- */
1945
- static create(functionStrategy, tableFunctionStrategy) {
1946
- class TestDialect extends _Dialect {
1947
- dialect = "sqlite";
1948
- quoteIdentifier(id) {
1949
- return `"${id}"`;
1950
- }
1951
- compileSelectAst() {
1952
- throw new Error("Not implemented");
1953
- }
1954
- compileInsertAst() {
1955
- throw new Error("Not implemented");
1956
- }
1957
- compileUpdateAst() {
1958
- throw new Error("Not implemented");
1959
- }
1960
- compileDeleteAst() {
1961
- throw new Error("Not implemented");
1962
- }
1963
- compileProcedureCall() {
1964
- throw new Error("Not implemented");
1965
- }
1966
- }
1967
- return new TestDialect(functionStrategy, tableFunctionStrategy);
1968
- }
1969
- /**
1970
- * Registers an expression compiler for a specific node type
1971
- * @param type - Expression node type
1972
- * @param compiler - Compiler function
1973
- */
1775
+ expressionCompilers = /* @__PURE__ */ new Map();
1776
+ operandCompilers = /* @__PURE__ */ new Map();
1974
1777
  registerExpressionCompiler(type, compiler) {
1975
1778
  this.expressionCompilers.set(type, compiler);
1976
1779
  }
1977
- /**
1978
- * Registers an operand compiler for a specific node type
1979
- * @param type - Operand node type
1980
- * @param compiler - Compiler function
1981
- */
1982
1780
  registerOperandCompiler(type, compiler) {
1983
1781
  this.operandCompilers.set(type, compiler);
1984
1782
  }
1985
- /**
1986
- * Compiles an expression node
1987
- * @param node - Expression node to compile
1988
- * @param ctx - Compiler context
1989
- * @returns Compiled SQL expression
1990
- */
1991
1783
  compileExpression(node, ctx) {
1992
1784
  const compiler = this.expressionCompilers.get(node.type);
1993
1785
  if (!compiler) {
1994
- throw new Error(`Unsupported expression node type "${node.type}" for ${this.constructor.name}`);
1786
+ throw new Error(`Unsupported expression node type "${node.type}" for ${this.host.describe()}`);
1995
1787
  }
1996
1788
  return compiler(node, ctx);
1997
1789
  }
1998
- /**
1999
- * Compiles an operand node
2000
- * @param node - Operand node to compile
2001
- * @param ctx - Compiler context
2002
- * @returns Compiled SQL operand
2003
- */
2004
1790
  compileOperand(node, ctx) {
2005
1791
  const compiler = this.operandCompilers.get(node.type);
2006
1792
  if (!compiler) {
2007
- throw new Error(`Unsupported operand node type "${node.type}" for ${this.constructor.name}`);
1793
+ throw new Error(`Unsupported operand node type "${node.type}" for ${this.host.describe()}`);
2008
1794
  }
2009
1795
  return compiler(node, ctx);
2010
1796
  }
2011
- /**
2012
- * Compiles an ordering term (operand, expression, or alias reference).
2013
- */
2014
1797
  compileOrderingTerm(term, ctx) {
2015
1798
  if (isOperandNode(term)) {
2016
1799
  return this.compileOperand(term, ctx);
2017
1800
  }
2018
- const expr = this.compileExpression(term, ctx);
2019
- return `(${expr})`;
1801
+ return `(${this.compileExpression(term, ctx)})`;
2020
1802
  }
2021
1803
  registerDefaultExpressionCompilers() {
2022
1804
  this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
@@ -2051,11 +1833,11 @@ var Dialect = class _Dialect {
2051
1833
  const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
2052
1834
  return `${left2} ${inExpr.operator} (${values})`;
2053
1835
  }
2054
- const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1836
+ const subquerySql = this.host.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
2055
1837
  return `${left2} ${inExpr.operator} (${subquerySql})`;
2056
1838
  });
2057
1839
  this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
2058
- const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
1840
+ const subquerySql = this.host.compileSelectForExists(existsExpr.subquery, ctx);
2059
1841
  return `${existsExpr.operator} (${subquerySql})`;
2060
1842
  });
2061
1843
  this.registerExpressionCompiler("BetweenExpression", (betweenExpr, ctx) => {
@@ -2081,25 +1863,28 @@ var Dialect = class _Dialect {
2081
1863
  });
2082
1864
  }
2083
1865
  registerDefaultOperandCompilers() {
2084
- this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
2085
- this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
2086
- void _ctx;
2087
- return this.quoteIdentifier(alias.name);
2088
- });
2089
- this.registerOperandCompiler("Column", (column, _ctx) => {
2090
- void _ctx;
2091
- return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
2092
- });
1866
+ this.registerOperandCompiler(
1867
+ "Literal",
1868
+ (literal, ctx) => ctx.addParameter(literal.value)
1869
+ );
1870
+ this.registerOperandCompiler(
1871
+ "AliasRef",
1872
+ (alias) => this.host.quoteIdentifier(alias.name)
1873
+ );
1874
+ this.registerOperandCompiler(
1875
+ "Column",
1876
+ (column) => `${this.host.quoteIdentifier(column.table)}.${this.host.quoteIdentifier(column.name)}`
1877
+ );
2093
1878
  this.registerOperandCompiler(
2094
1879
  "Function",
2095
- (fnNode, ctx) => this.compileFunctionOperand(fnNode, ctx)
1880
+ (fnNode, ctx) => this.host.compileFunctionOperand(fnNode, ctx)
1881
+ );
1882
+ this.registerOperandCompiler(
1883
+ "JsonPath",
1884
+ (path) => this.host.compileJsonPath(path)
2096
1885
  );
2097
- this.registerOperandCompiler("JsonPath", (path, _ctx) => {
2098
- void _ctx;
2099
- return this.compileJsonPath(path);
2100
- });
2101
1886
  this.registerOperandCompiler("ScalarSubquery", (node, ctx) => {
2102
- const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
1887
+ const sql = this.host.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
2103
1888
  return `(${sql})`;
2104
1889
  });
2105
1890
  this.registerOperandCompiler("CaseExpression", (node, ctx) => {
@@ -2126,7 +1911,7 @@ var Dialect = class _Dialect {
2126
1911
  const parts = [];
2127
1912
  if (node.partitionBy && node.partitionBy.length > 0) {
2128
1913
  const partitionClause = "PARTITION BY " + node.partitionBy.map(
2129
- (col2) => `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`
1914
+ (col2) => `${this.host.quoteIdentifier(col2.table)}.${this.host.quoteIdentifier(col2.name)}`
2130
1915
  ).join(", ");
2131
1916
  parts.push(partitionClause);
2132
1917
  }
@@ -2158,14 +1943,164 @@ var Dialect = class _Dialect {
2158
1943
  return `${expr} COLLATE ${node.collation}`;
2159
1944
  });
2160
1945
  }
2161
- // Default fallback, should be overridden by dialects if supported
1946
+ };
1947
+
1948
+ // src/core/dialect/base/select-ast-normalizer.ts
1949
+ var SelectAstNormalizer = class {
1950
+ constructor(supportsSetOperation) {
1951
+ this.supportsSetOperation = supportsSetOperation;
1952
+ }
1953
+ normalize(ast) {
1954
+ this.validateSetOperations(ast, true);
1955
+ const { normalized, hoistedCtes } = this.hoistCtes(ast);
1956
+ const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
1957
+ return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
1958
+ }
1959
+ validateSetOperations(ast, isOutermost) {
1960
+ const hasSetOps = !!(ast.setOps && ast.setOps.length);
1961
+ if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
1962
+ throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
1963
+ }
1964
+ if (!hasSetOps) return;
1965
+ for (const op of ast.setOps) {
1966
+ if (!this.supportsSetOperation(op.operator)) {
1967
+ throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
1968
+ }
1969
+ this.validateSetOperations(op.query, false);
1970
+ }
1971
+ }
1972
+ hoistCtes(ast) {
1973
+ let hoisted = [];
1974
+ const normalizedSetOps = ast.setOps?.map((op) => {
1975
+ const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
1976
+ const childCtes = child.ctes ?? [];
1977
+ if (childCtes.length) hoisted = hoisted.concat(childCtes);
1978
+ hoisted = hoisted.concat(childHoisted);
1979
+ const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
1980
+ return { ...op, query: queryWithoutCtes };
1981
+ });
1982
+ const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
1983
+ return { normalized, hoistedCtes: hoisted };
1984
+ }
1985
+ };
1986
+
1987
+ // src/core/dialect/abstract.ts
1988
+ var DialectBase = class _DialectBase {
1989
+ expressionCompilerRegistry;
1990
+ selectAstNormalizer;
1991
+ functionStrategy;
1992
+ tableFunctionStrategy;
1993
+ constructor(functionStrategy, tableFunctionStrategy) {
1994
+ this.functionStrategy = functionStrategy ?? new StandardFunctionStrategy();
1995
+ this.tableFunctionStrategy = tableFunctionStrategy ?? new StandardTableFunctionStrategy();
1996
+ this.selectAstNormalizer = new SelectAstNormalizer((kind) => this.supportsSetOperation(kind));
1997
+ this.expressionCompilerRegistry = new ExpressionCompilerRegistry({
1998
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
1999
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
2000
+ compileSelectForExists: (ast, ctx) => this.compileSelectForExists(ast, ctx),
2001
+ compileJsonPath: (node) => this.compileJsonPath(node),
2002
+ compileFunctionOperand: (node, ctx) => this.compileFunctionOperand(node, ctx),
2003
+ describe: () => this.constructor.name
2004
+ });
2005
+ }
2006
+ compileSelect(ast) {
2007
+ const ctx = this.createCompilerContext();
2008
+ const normalized = this.normalizeSelectAst(ast);
2009
+ const rawSql = this.compileSelectAst(normalized, ctx).trim();
2010
+ return {
2011
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
2012
+ params: [...ctx.params]
2013
+ };
2014
+ }
2015
+ compileInsert(ast) {
2016
+ const ctx = this.createCompilerContext();
2017
+ const rawSql = this.compileInsertAst(ast, ctx).trim();
2018
+ return {
2019
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
2020
+ params: [...ctx.params]
2021
+ };
2022
+ }
2023
+ compileUpdate(ast) {
2024
+ const ctx = this.createCompilerContext();
2025
+ const rawSql = this.compileUpdateAst(ast, ctx).trim();
2026
+ return {
2027
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
2028
+ params: [...ctx.params]
2029
+ };
2030
+ }
2031
+ compileDelete(ast) {
2032
+ const ctx = this.createCompilerContext();
2033
+ const rawSql = this.compileDeleteAst(ast, ctx).trim();
2034
+ return {
2035
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
2036
+ params: [...ctx.params]
2037
+ };
2038
+ }
2039
+ supportsDmlReturningClause() {
2040
+ return false;
2041
+ }
2042
+ compileWhere(where, ctx) {
2043
+ if (!where) return "";
2044
+ return ` WHERE ${this.compileExpression(where, ctx)}`;
2045
+ }
2046
+ compileReturning(returning, _ctx) {
2047
+ void _ctx;
2048
+ if (!returning || returning.length === 0) return "";
2049
+ throw new Error("RETURNING is not supported by this dialect.");
2050
+ }
2051
+ compileSelectForExists(ast, ctx) {
2052
+ const normalized = this.normalizeSelectAst(ast);
2053
+ const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
2054
+ if (normalized.setOps && normalized.setOps.length > 0) {
2055
+ return `SELECT 1 FROM (${full}) AS _exists`;
2056
+ }
2057
+ const upper2 = full.toUpperCase();
2058
+ const fromIndex = upper2.indexOf(" FROM ");
2059
+ if (fromIndex === -1) return full;
2060
+ return `SELECT 1${full.slice(fromIndex)}`;
2061
+ }
2062
+ createCompilerContext() {
2063
+ const params = [];
2064
+ let counter = 0;
2065
+ return {
2066
+ params,
2067
+ addParameter: (value) => {
2068
+ counter += 1;
2069
+ params.push(value);
2070
+ return this.formatPlaceholder(counter);
2071
+ }
2072
+ };
2073
+ }
2074
+ formatPlaceholder(_index) {
2075
+ void _index;
2076
+ return "?";
2077
+ }
2078
+ supportsSetOperation(_kind) {
2079
+ void _kind;
2080
+ return true;
2081
+ }
2082
+ normalizeSelectAst(ast) {
2083
+ return this.selectAstNormalizer.normalize(ast);
2084
+ }
2085
+ registerExpressionCompiler(type, compiler) {
2086
+ this.expressionCompilerRegistry.registerExpressionCompiler(type, compiler);
2087
+ }
2088
+ registerOperandCompiler(type, compiler) {
2089
+ this.expressionCompilerRegistry.registerOperandCompiler(type, compiler);
2090
+ }
2091
+ compileExpression(node, ctx) {
2092
+ return this.expressionCompilerRegistry.compileExpression(node, ctx);
2093
+ }
2094
+ compileOperand(node, ctx) {
2095
+ return this.expressionCompilerRegistry.compileOperand(node, ctx);
2096
+ }
2097
+ compileOrderingTerm(term, ctx) {
2098
+ return this.expressionCompilerRegistry.compileOrderingTerm(term, ctx);
2099
+ }
2162
2100
  compileJsonPath(_node) {
2163
2101
  void _node;
2164
2102
  throw new Error("JSON Path not supported by this dialect");
2165
2103
  }
2166
- /**
2167
- * Compiles a function operand, using the dialect's function strategy.
2168
- */
2169
2104
  compileFunctionOperand(fnNode, ctx) {
2170
2105
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
2171
2106
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
@@ -2178,115 +2113,175 @@ var Dialect = class _Dialect {
2178
2113
  }
2179
2114
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
2180
2115
  }
2116
+ /** Creates a minimal dialect implementation for isolated compiler tests. */
2117
+ static create(functionStrategy, tableFunctionStrategy) {
2118
+ class TestDialect extends _DialectBase {
2119
+ dialect = "sqlite";
2120
+ quoteIdentifier(id) {
2121
+ return `"${id}"`;
2122
+ }
2123
+ compileSelectAst() {
2124
+ throw new Error("Not implemented");
2125
+ }
2126
+ compileInsertAst() {
2127
+ throw new Error("Not implemented");
2128
+ }
2129
+ compileUpdateAst() {
2130
+ throw new Error("Not implemented");
2131
+ }
2132
+ compileDeleteAst() {
2133
+ throw new Error("Not implemented");
2134
+ }
2135
+ }
2136
+ return new TestDialect(functionStrategy, tableFunctionStrategy);
2137
+ }
2181
2138
  };
2182
2139
 
2183
- // src/core/dialect/base/function-table-formatter.ts
2184
- var FunctionTableFormatter = class {
2140
+ // src/core/dialect/base/pagination-strategy.ts
2141
+ var StandardLimitOffsetPagination = class {
2185
2142
  /**
2186
- * Formats a function table node into SQL syntax.
2187
- * @param fn - The function table node containing schema, name, args, and aliases.
2188
- * @param ctx - Optional compiler context for operand compilation.
2189
- * @param dialect - The dialect instance for compiling operands.
2190
- * @returns SQL function table expression (e.g., "LATERAL schema.func(args) WITH ORDINALITY AS alias(col1, col2)").
2143
+ * Compiles LIMIT/OFFSET pagination clause.
2144
+ * @param limit - The maximum number of rows to return.
2145
+ * @param offset - The number of rows to skip.
2146
+ * @returns SQL pagination clause with LIMIT and/or OFFSET.
2191
2147
  */
2192
- static format(fn9, ctx, dialect) {
2193
- const schemaPart = this.formatSchema(fn9, dialect);
2194
- const args = this.formatArgs(fn9, ctx, dialect);
2195
- const base = this.formatBase(fn9, schemaPart, args);
2196
- const lateral = this.formatLateral(fn9);
2197
- const alias = this.formatAlias(fn9, dialect);
2198
- const colAliases = this.formatColumnAliases(fn9, dialect);
2199
- return `${lateral}${base}${alias}${colAliases}`;
2148
+ compilePagination(limit, offset) {
2149
+ const parts = [];
2150
+ if (limit !== void 0) parts.push(`LIMIT ${limit}`);
2151
+ if (offset !== void 0) parts.push(`OFFSET ${offset}`);
2152
+ return parts.length ? ` ${parts.join(" ")}` : "";
2200
2153
  }
2154
+ };
2155
+
2156
+ // src/core/dialect/base/returning-strategy.ts
2157
+ var NoReturningStrategy = class {
2201
2158
  /**
2202
- * Formats the schema prefix for the function name.
2203
- * @param fn - The function table node.
2204
- * @param dialect - The dialect instance for quoting identifiers.
2205
- * @returns Schema prefix (e.g., "schema.") or empty string.
2206
- * @internal
2159
+ * Throws an error as RETURNING is not supported.
2160
+ * @param returning - Columns to return (causes error if non-empty).
2161
+ * @param _ctx - Compiler context (unused).
2162
+ * @throws Error indicating RETURNING is not supported.
2207
2163
  */
2208
- static formatSchema(fn9, dialect) {
2209
- if (!fn9.schema) return "";
2210
- const quoted = dialect ? dialect.quoteIdentifier(fn9.schema) : fn9.schema;
2211
- return `${quoted}.`;
2164
+ compileReturning(returning, _ctx) {
2165
+ void _ctx;
2166
+ if (!returning || returning.length === 0) return "";
2167
+ throw new Error("RETURNING is not supported by this dialect.");
2212
2168
  }
2213
2169
  /**
2214
- * Formats function arguments into SQL syntax.
2215
- * @param fn - The function table node containing arguments.
2216
- * @param ctx - Optional compiler context for operand compilation.
2217
- * @param dialect - The dialect instance for compiling operands.
2218
- * @returns Comma-separated function arguments.
2219
- * @internal
2170
+ * Formats column names for RETURNING clause.
2171
+ * @param returning - Columns to format.
2172
+ * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
2173
+ * @returns Simple comma-separated column names.
2220
2174
  */
2221
- static formatArgs(fn9, ctx, dialect) {
2222
- return (fn9.args || []).map((a) => {
2223
- if (ctx && dialect) {
2224
- return dialect.compileOperand(a, ctx);
2225
- }
2226
- return String(a);
2175
+ formatReturningColumns(returning, quoteIdentifier) {
2176
+ return returning.map((column) => {
2177
+ const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
2178
+ const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
2179
+ return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
2227
2180
  }).join(", ");
2228
2181
  }
2229
- /**
2230
- * Formats the base function call with WITH ORDINALITY if present.
2231
- * @param fn - The function table node.
2232
- * @param schemaPart - Formatted schema prefix.
2233
- * @param args - Formatted function arguments.
2234
- * @param dialect - The dialect instance for quoting identifiers.
2235
- * @returns Base function call expression (e.g., "schema.func(args) WITH ORDINALITY").
2236
- * @internal
2237
- */
2182
+ };
2183
+
2184
+ // src/core/dialect/base/function-table-formatter.ts
2185
+ var FunctionTableFormatter = class {
2186
+ static format(fn9, ctx, formatter) {
2187
+ const schemaPart = this.formatSchema(fn9, formatter);
2188
+ const args = this.formatArgs(fn9, ctx, formatter);
2189
+ const base = this.formatBase(fn9, schemaPart, args);
2190
+ const lateral = this.formatLateral(fn9);
2191
+ const alias = this.formatAlias(fn9, formatter);
2192
+ const colAliases = this.formatColumnAliases(fn9, formatter);
2193
+ return `${lateral}${base}${alias}${colAliases}`;
2194
+ }
2195
+ static formatSchema(fn9, formatter) {
2196
+ if (!fn9.schema) return "";
2197
+ return `${formatter.quoteIdentifier(fn9.schema)}.`;
2198
+ }
2199
+ static formatArgs(fn9, ctx, formatter) {
2200
+ return (fn9.args || []).map((arg) => ctx ? formatter.compileOperand(arg, ctx) : String(arg)).join(", ");
2201
+ }
2238
2202
  static formatBase(fn9, schemaPart, args) {
2239
2203
  const ordinality = fn9.withOrdinality ? " WITH ORDINALITY" : "";
2240
2204
  return `${schemaPart}${fn9.name}(${args})${ordinality}`;
2241
2205
  }
2242
- /**
2243
- * Formats the LATERAL keyword if present.
2244
- * @param fn - The function table node.
2245
- * @returns "LATERAL " or empty string.
2246
- * @internal
2247
- */
2248
2206
  static formatLateral(fn9) {
2249
2207
  return fn9.lateral ? "LATERAL " : "";
2250
2208
  }
2251
- /**
2252
- * Formats the table alias for the function table.
2253
- * @param fn - The function table node.
2254
- * @param dialect - The dialect instance for quoting identifiers.
2255
- * @returns " AS alias" or empty string.
2256
- * @internal
2257
- */
2258
- static formatAlias(fn9, dialect) {
2209
+ static formatAlias(fn9, formatter) {
2259
2210
  if (!fn9.alias) return "";
2260
- const quoted = dialect ? dialect.quoteIdentifier(fn9.alias) : fn9.alias;
2261
- return ` AS ${quoted}`;
2262
- }
2263
- /**
2264
- * Formats column aliases for the function table result columns.
2265
- * @param fn - The function table node containing column aliases.
2266
- * @param dialect - The dialect instance for quoting identifiers.
2267
- * @returns "(col1, col2, ...)" or empty string.
2268
- * @internal
2269
- */
2270
- static formatColumnAliases(fn9, dialect) {
2211
+ return ` AS ${formatter.quoteIdentifier(fn9.alias)}`;
2212
+ }
2213
+ static formatColumnAliases(fn9, formatter) {
2271
2214
  if (!fn9.columnAliases || !fn9.columnAliases.length) return "";
2272
- const aliases = fn9.columnAliases.map((col2) => dialect ? dialect.quoteIdentifier(col2) : col2).join(", ");
2215
+ const aliases = fn9.columnAliases.map((col2) => formatter.quoteIdentifier(col2)).join(", ");
2273
2216
  return `(${aliases})`;
2274
2217
  }
2275
2218
  };
2276
2219
 
2277
- // src/core/dialect/base/pagination-strategy.ts
2278
- var StandardLimitOffsetPagination = class {
2279
- /**
2280
- * Compiles LIMIT/OFFSET pagination clause.
2281
- * @param limit - The maximum number of rows to return.
2282
- * @param offset - The number of rows to skip.
2283
- * @returns SQL pagination clause with LIMIT and/or OFFSET.
2284
- */
2285
- compilePagination(limit, offset) {
2286
- const parts = [];
2287
- if (limit !== void 0) parts.push(`LIMIT ${limit}`);
2288
- if (offset !== void 0) parts.push(`OFFSET ${offset}`);
2289
- return parts.length ? ` ${parts.join(" ")}` : "";
2220
+ // src/core/dialect/base/standard-sql-source-compiler.ts
2221
+ var StandardSqlSourceCompiler = class {
2222
+ constructor(services) {
2223
+ this.services = services;
2224
+ }
2225
+ compileFrom(source, ctx) {
2226
+ if (source.type === "FunctionTable") return this.compileFunctionTable(source, ctx);
2227
+ if (source.type === "DerivedTable") return this.compileDerivedTable(source, ctx);
2228
+ return this.compileTableSource(source);
2229
+ }
2230
+ compileFunctionTable(fn9, ctx) {
2231
+ const key = fn9.key ?? fn9.name;
2232
+ if (ctx) {
2233
+ const renderer = this.services.getTableFunctionStrategy().getRenderer(key);
2234
+ if (renderer) {
2235
+ const compiledArgs = (fn9.args ?? []).map((arg) => this.services.compileOperand(arg, ctx));
2236
+ return renderer({
2237
+ node: fn9,
2238
+ compiledArgs,
2239
+ compileOperand: (operand) => this.services.compileOperand(operand, ctx),
2240
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id)
2241
+ });
2242
+ }
2243
+ if (fn9.key) {
2244
+ throw new Error(
2245
+ `Table function "${key}" is not supported by dialect "${this.services.getDialectName()}".`
2246
+ );
2247
+ }
2248
+ }
2249
+ return FunctionTableFormatter.format(fn9, ctx, {
2250
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id),
2251
+ compileOperand: (node, compilerContext) => this.services.compileOperand(node, compilerContext)
2252
+ });
2253
+ }
2254
+ compileDerivedTable(table, ctx) {
2255
+ if (!table.alias) throw new Error("Derived tables must have an alias.");
2256
+ if (!ctx) throw new Error("Derived table compilation requires a compiler context.");
2257
+ const normalized = this.services.normalizeSelectAst(table.query);
2258
+ const subquery = this.services.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
2259
+ const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((column) => this.services.quoteIdentifier(column)).join(", ")})` : "";
2260
+ return `(${subquery}) AS ${this.services.quoteIdentifier(table.alias)}${columns}`;
2261
+ }
2262
+ compileTableSource(table) {
2263
+ if (table.type === "FunctionTable") return this.compileFunctionTable(table);
2264
+ if (table.type === "DerivedTable") {
2265
+ throw new Error("Derived table compilation requires a compiler context.");
2266
+ }
2267
+ const base = this.compileTableName(table);
2268
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
2269
+ }
2270
+ compileTableName(table) {
2271
+ if (table.schema) {
2272
+ return `${this.services.quoteIdentifier(table.schema)}.${this.services.quoteIdentifier(table.name)}`;
2273
+ }
2274
+ return this.services.quoteIdentifier(table.name);
2275
+ }
2276
+ compileTableReference(table) {
2277
+ const base = this.compileTableName(table);
2278
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
2279
+ }
2280
+ stripTrailingSemicolon(sql) {
2281
+ return sql.trim().replace(/;$/, "");
2282
+ }
2283
+ wrapSetOperand(sql) {
2284
+ return `(${this.stripTrailingSemicolon(sql)})`;
2290
2285
  }
2291
2286
  };
2292
2287
 
@@ -2316,34 +2311,6 @@ var CteCompiler = class {
2316
2311
  }
2317
2312
  };
2318
2313
 
2319
- // src/core/dialect/base/returning-strategy.ts
2320
- var NoReturningStrategy = class {
2321
- /**
2322
- * Throws an error as RETURNING is not supported.
2323
- * @param returning - Columns to return (causes error if non-empty).
2324
- * @param _ctx - Compiler context (unused).
2325
- * @throws Error indicating RETURNING is not supported.
2326
- */
2327
- compileReturning(returning, _ctx) {
2328
- void _ctx;
2329
- if (!returning || returning.length === 0) return "";
2330
- throw new Error("RETURNING is not supported by this dialect.");
2331
- }
2332
- /**
2333
- * Formats column names for RETURNING clause.
2334
- * @param returning - Columns to format.
2335
- * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
2336
- * @returns Simple comma-separated column names.
2337
- */
2338
- formatReturningColumns(returning, quoteIdentifier) {
2339
- return returning.map((column) => {
2340
- const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
2341
- const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
2342
- return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
2343
- }).join(", ");
2344
- }
2345
- };
2346
-
2347
2314
  // src/core/dialect/base/join-compiler.ts
2348
2315
  var JoinCompiler = class {
2349
2316
  static compileJoins(joins, ctx, compileFrom, compileExpression) {
@@ -2394,113 +2361,229 @@ var OrderByCompiler = class {
2394
2361
  }
2395
2362
  };
2396
2363
 
2397
- // src/core/dialect/base/sql-dialect.ts
2398
- var SqlDialectBase = class extends Dialect {
2399
- paginationStrategy = new StandardLimitOffsetPagination();
2400
- returningStrategy = new NoReturningStrategy();
2401
- compileSelectAst(ast, ctx) {
2364
+ // src/core/dialect/base/standard-select-compiler.ts
2365
+ var StandardSelectCompiler = class {
2366
+ constructor(services, sources) {
2367
+ this.services = services;
2368
+ this.sources = sources;
2369
+ }
2370
+ compile(ast, ctx) {
2402
2371
  const hasSetOps = !!(ast.setOps && ast.setOps.length);
2403
2372
  const ctes = CteCompiler.compileCtes(
2404
2373
  ast,
2405
2374
  ctx,
2406
- this.quoteIdentifier.bind(this),
2407
- this.compileSelectAst.bind(this),
2408
- this.normalizeSelectAst?.bind(this) ?? ((a) => a),
2409
- this.stripTrailingSemicolon.bind(this)
2375
+ (id) => this.services.quoteIdentifier(id),
2376
+ (query, compilerContext) => this.services.compileSelectAst(query, compilerContext),
2377
+ (query) => this.services.normalizeSelectAst(query),
2378
+ (sql) => this.sources.stripTrailingSemicolon(sql)
2410
2379
  );
2411
2380
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
2412
- const baseSelect = this.compileSelectCore(baseAst, ctx);
2413
- if (!hasSetOps) {
2414
- return `${ctes}${baseSelect}`;
2415
- }
2416
- return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
2381
+ const baseSelect = this.compileCore(baseAst, ctx);
2382
+ if (!hasSetOps) return `${ctes}${baseSelect}`;
2383
+ const compound = ast.setOps.map((op) => `${op.operator} ${this.sources.wrapSetOperand(this.services.compileSelectAst(op.query, ctx))}`).join(" ");
2384
+ const orderBy = this.compileOrderBy(ast, ctx);
2385
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
2386
+ const combined = `${this.sources.wrapSetOperand(baseSelect)} ${compound}`;
2387
+ return `${ctes}${combined}${orderBy}${pagination}`;
2417
2388
  }
2418
- compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
2419
- const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
2420
- const orderBy = OrderByCompiler.compileOrderBy(
2389
+ compileCore(ast, ctx) {
2390
+ const columns = this.compileColumns(ast, ctx);
2391
+ const from = this.sources.compileFrom(ast.from, ctx);
2392
+ const joins = JoinCompiler.compileJoins(
2393
+ ast.joins,
2394
+ ctx,
2395
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2396
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2397
+ );
2398
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2399
+ const groupBy = GroupByCompiler.compileGroupBy(
2421
2400
  ast,
2422
- (term) => this.compileOrderingTerm(term, ctx),
2423
- this.renderOrderByNulls.bind(this),
2424
- this.renderOrderByCollation.bind(this)
2401
+ (term) => this.services.compileOrderingTerm(term, ctx)
2425
2402
  );
2426
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
2427
- const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
2428
- return `${ctes}${combined}${orderBy}${pagination}`;
2403
+ const having = ast.having ? ` HAVING ${this.services.compileExpression(ast.having, ctx)}` : "";
2404
+ const orderBy = this.compileOrderBy(ast, ctx);
2405
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
2406
+ return `SELECT ${ast.distinct ? "DISTINCT " : ""}${columns} FROM ${from}${joins}${where}${groupBy}${having}${orderBy}${pagination}`;
2407
+ }
2408
+ compileColumns(ast, ctx) {
2409
+ if (!ast.columns || ast.columns.length === 0) return "*";
2410
+ return ast.columns.map((column) => {
2411
+ const expr = this.services.compileOperand(column, ctx);
2412
+ if (!column.alias) return expr;
2413
+ if (column.alias.includes("(")) return column.alias;
2414
+ return `${expr} AS ${this.services.quoteIdentifier(column.alias)}`;
2415
+ }).join(", ");
2429
2416
  }
2430
- compileInsertAst(ast, ctx) {
2417
+ compileOrderBy(ast, ctx) {
2418
+ return OrderByCompiler.compileOrderBy(
2419
+ ast,
2420
+ (term) => this.services.compileOrderingTerm(term, ctx),
2421
+ (order) => this.services.renderOrderByNulls(order),
2422
+ (order) => this.services.renderOrderByCollation(order)
2423
+ );
2424
+ }
2425
+ };
2426
+
2427
+ // src/core/dialect/base/standard-insert-compiler.ts
2428
+ var StandardInsertCompiler = class {
2429
+ constructor(services, sources) {
2430
+ this.services = services;
2431
+ this.sources = sources;
2432
+ }
2433
+ compile(ast, ctx) {
2431
2434
  if (!ast.columns.length) {
2432
2435
  throw new Error("INSERT queries must specify columns.");
2433
2436
  }
2434
- const table = this.compileTableName(ast.into);
2435
- const columnList = this.compileInsertColumnList(ast.columns);
2436
- const source = this.compileInsertSource(ast.source, ctx);
2437
- const upsert = this.compileUpsertClause(ast, ctx);
2438
- const returning = this.compileReturning(ast.returning, ctx);
2437
+ const table = this.sources.compileTableName(ast.into);
2438
+ const columnList = this.compileColumnList(ast.columns);
2439
+ const source = this.compileSource(ast.source, ctx);
2440
+ const upsert = this.services.compileUpsertClause(ast, ctx);
2441
+ const returning = this.services.compileReturning(ast.returning, ctx);
2439
2442
  return `INSERT INTO ${table} (${columnList}) ${source}${upsert}${returning}`;
2440
2443
  }
2441
- compileUpsertClause(ast, _ctx) {
2442
- void _ctx;
2443
- if (!ast.onConflict) return "";
2444
- throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
2445
- }
2446
- compileReturning(returning, ctx) {
2447
- return this.returningStrategy.compileReturning(returning, ctx);
2448
- }
2449
- compileInsertSource(source, ctx) {
2444
+ compileSource(source, ctx) {
2450
2445
  if (source.type === "InsertValues") {
2451
2446
  if (!source.rows.length) {
2452
2447
  throw new Error("INSERT ... VALUES requires at least one row.");
2453
2448
  }
2454
- const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
2449
+ const values = source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
2455
2450
  return `VALUES ${values}`;
2456
2451
  }
2457
- const normalized = this.normalizeSelectAst(source.query);
2458
- return this.compileSelectAst(normalized, ctx).trim();
2452
+ const normalized = this.services.normalizeSelectAst(source.query);
2453
+ return this.services.compileSelectAst(normalized, ctx).trim();
2459
2454
  }
2460
- compileInsertColumnList(columns) {
2461
- return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
2455
+ compileColumnList(columns) {
2456
+ return columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
2462
2457
  }
2463
2458
  ensureConflictColumns(clause, message) {
2464
- if (!clause.target.columns.length) {
2465
- throw new Error(message);
2466
- }
2459
+ if (!clause.target.columns.length) throw new Error(message);
2467
2460
  }
2468
- compileSelectCore(ast, ctx) {
2469
- const columns = this.compileSelectColumns(ast, ctx);
2470
- const from = this.compileFrom(ast.from, ctx);
2461
+ };
2462
+
2463
+ // src/core/dialect/base/standard-update-compiler.ts
2464
+ var StandardUpdateCompiler = class {
2465
+ constructor(services, sources) {
2466
+ this.services = services;
2467
+ this.sources = sources;
2468
+ }
2469
+ compile(ast, ctx) {
2470
+ const target = this.sources.compileTableReference(ast.table);
2471
+ const assignments = this.compileAssignments(ast.set, ast.table, ctx);
2472
+ const from = this.compileFromClause(ast, ctx);
2473
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2474
+ const returning = this.services.compileReturning(ast.returning, ctx);
2475
+ return `UPDATE ${target} SET ${assignments}${from}${where}${returning}`;
2476
+ }
2477
+ compileAssignments(assignments, table, ctx) {
2478
+ return assignments.map((assignment) => {
2479
+ const target = this.services.compileSetTarget(assignment.column, table);
2480
+ const value = this.services.compileOperand(assignment.value, ctx);
2481
+ return `${target} = ${value}`;
2482
+ }).join(", ");
2483
+ }
2484
+ compileFromClause(ast, ctx) {
2485
+ if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2486
+ if (!ast.from) {
2487
+ throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2488
+ }
2489
+ const from = this.sources.compileFrom(ast.from, ctx);
2471
2490
  const joins = JoinCompiler.compileJoins(
2472
2491
  ast.joins,
2473
2492
  ctx,
2474
- this.compileFrom.bind(this),
2475
- this.compileExpression.bind(this)
2493
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2494
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2476
2495
  );
2477
- const whereClause = this.compileWhere(ast.where, ctx);
2478
- const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
2479
- const having = this.compileHaving(ast, ctx);
2480
- const orderBy = OrderByCompiler.compileOrderBy(
2481
- ast,
2482
- (term) => this.compileOrderingTerm(term, ctx),
2483
- this.renderOrderByNulls.bind(this),
2484
- this.renderOrderByCollation.bind(this)
2496
+ return ` FROM ${from}${joins}`;
2497
+ }
2498
+ };
2499
+
2500
+ // src/core/dialect/base/standard-delete-compiler.ts
2501
+ var StandardDeleteCompiler = class {
2502
+ constructor(services, sources) {
2503
+ this.services = services;
2504
+ this.sources = sources;
2505
+ }
2506
+ compile(ast, ctx) {
2507
+ const target = this.sources.compileTableReference(ast.from);
2508
+ const using = this.compileUsingClause(ast, ctx);
2509
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2510
+ const returning = this.services.compileReturning(ast.returning, ctx);
2511
+ return `DELETE FROM ${target}${using}${where}${returning}`;
2512
+ }
2513
+ compileUsingClause(ast, ctx) {
2514
+ if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2515
+ if (!ast.using) {
2516
+ throw new Error("DELETE with JOINs requires a USING clause.");
2517
+ }
2518
+ const usingTable = this.sources.compileFrom(ast.using, ctx);
2519
+ const joins = JoinCompiler.compileJoins(
2520
+ ast.joins,
2521
+ ctx,
2522
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2523
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2485
2524
  );
2486
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
2487
- return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
2525
+ return ` USING ${usingTable}${joins}`;
2526
+ }
2527
+ };
2528
+
2529
+ // src/core/dialect/base/sql-dialect.ts
2530
+ var SqlDialectBase = class extends DialectBase {
2531
+ paginationStrategy = new StandardLimitOffsetPagination();
2532
+ returningStrategy = new NoReturningStrategy();
2533
+ sourceCompiler;
2534
+ selectCompiler;
2535
+ insertCompiler;
2536
+ updateCompiler;
2537
+ deleteCompiler;
2538
+ constructor(functionStrategy, tableFunctionStrategy) {
2539
+ super(functionStrategy, tableFunctionStrategy);
2540
+ const services = {
2541
+ getDialectName: () => this.dialect,
2542
+ getPaginationStrategy: () => this.paginationStrategy,
2543
+ getTableFunctionStrategy: () => this.tableFunctionStrategy,
2544
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2545
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx),
2546
+ compileExpression: (node, ctx) => this.compileExpression(node, ctx),
2547
+ compileOrderingTerm: (term, ctx) => this.compileOrderingTerm(term, ctx),
2548
+ normalizeSelectAst: (ast) => this.normalizeSelectAst(ast),
2549
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
2550
+ compileReturning: (returning, ctx) => this.compileReturning(returning, ctx),
2551
+ compileUpsertClause: (ast, ctx) => this.compileUpsertClause(ast, ctx),
2552
+ compileSetTarget: (column, table) => this.compileSetTarget(column, table),
2553
+ renderOrderByNulls: (order) => this.renderOrderByNulls(order),
2554
+ renderOrderByCollation: (order) => this.renderOrderByCollation(order)
2555
+ };
2556
+ this.sourceCompiler = new StandardSqlSourceCompiler(services);
2557
+ this.selectCompiler = new StandardSelectCompiler(services, this.sourceCompiler);
2558
+ this.insertCompiler = new StandardInsertCompiler(services, this.sourceCompiler);
2559
+ this.updateCompiler = new StandardUpdateCompiler(services, this.sourceCompiler);
2560
+ this.deleteCompiler = new StandardDeleteCompiler(services, this.sourceCompiler);
2561
+ }
2562
+ compileSelectAst(ast, ctx) {
2563
+ return this.selectCompiler.compile(ast, ctx);
2564
+ }
2565
+ compileInsertAst(ast, ctx) {
2566
+ return this.insertCompiler.compile(ast, ctx);
2488
2567
  }
2489
2568
  compileUpdateAst(ast, ctx) {
2490
- const target = this.compileTableReference(ast.table);
2491
- const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
2492
- const fromClause = this.compileUpdateFromClause(ast, ctx);
2493
- const whereClause = this.compileWhere(ast.where, ctx);
2494
- const returning = this.compileReturning(ast.returning, ctx);
2495
- return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
2569
+ return this.updateCompiler.compile(ast, ctx);
2570
+ }
2571
+ compileDeleteAst(ast, ctx) {
2572
+ return this.deleteCompiler.compile(ast, ctx);
2573
+ }
2574
+ compileUpsertClause(ast, _ctx) {
2575
+ void _ctx;
2576
+ if (!ast.onConflict) return "";
2577
+ throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
2578
+ }
2579
+ compileReturning(returning, ctx) {
2580
+ return this.returningStrategy.compileReturning(returning, ctx);
2581
+ }
2582
+ ensureConflictColumns(clause, message) {
2583
+ this.insertCompiler.ensureConflictColumns(clause, message);
2496
2584
  }
2497
2585
  compileUpdateAssignments(assignments, table, ctx) {
2498
- return assignments.map((assignment) => {
2499
- const col2 = assignment.column;
2500
- const target = this.compileSetTarget(col2, table);
2501
- const value = this.compileOperand(assignment.value, ctx);
2502
- return `${target} = ${value}`;
2503
- }).join(", ");
2586
+ return this.updateCompiler.compileAssignments(assignments, table, ctx);
2504
2587
  }
2505
2588
  compileSetTarget(column, table) {
2506
2589
  return this.compileQualifiedColumn(column, table);
@@ -2510,132 +2593,38 @@ var SqlDialectBase = class extends Dialect {
2510
2593
  const alias = table.alias;
2511
2594
  const columnTable = column.table ?? alias ?? baseTableName;
2512
2595
  const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
2513
- if (!tableQualifier) {
2514
- return this.quoteIdentifier(column.name);
2515
- }
2596
+ if (!tableQualifier) return this.quoteIdentifier(column.name);
2516
2597
  return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
2517
2598
  }
2518
- compileDeleteAst(ast, ctx) {
2519
- const target = this.compileTableReference(ast.from);
2520
- const usingClause = this.compileDeleteUsingClause(ast, ctx);
2521
- const whereClause = this.compileWhere(ast.where, ctx);
2522
- const returning = this.compileReturning(ast.returning, ctx);
2523
- return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
2524
- }
2525
2599
  formatReturningColumns(returning) {
2526
- return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
2527
- }
2528
- compileDistinct(ast) {
2529
- return ast.distinct ? "DISTINCT " : "";
2530
- }
2531
- compileSelectColumns(ast, ctx) {
2532
- if (!ast.columns || ast.columns.length === 0) {
2533
- return "*";
2534
- }
2535
- return ast.columns.map((c) => {
2536
- const expr = this.compileOperand(c, ctx);
2537
- if (c.alias) {
2538
- if (c.alias.includes("(")) return c.alias;
2539
- return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
2540
- }
2541
- return expr;
2542
- }).join(", ");
2600
+ return this.returningStrategy.formatReturningColumns(
2601
+ returning,
2602
+ (id) => this.quoteIdentifier(id)
2603
+ );
2543
2604
  }
2544
- compileFrom(ast, ctx) {
2545
- const tableSource = ast;
2546
- if (tableSource.type === "FunctionTable") {
2547
- return this.compileFunctionTable(tableSource, ctx);
2548
- }
2549
- if (tableSource.type === "DerivedTable") {
2550
- return this.compileDerivedTable(tableSource, ctx);
2551
- }
2552
- return this.compileTableSource(tableSource);
2605
+ compileFrom(source, ctx) {
2606
+ return this.sourceCompiler.compileFrom(source, ctx);
2553
2607
  }
2554
2608
  compileFunctionTable(fn9, ctx) {
2555
- const key = fn9.key ?? fn9.name;
2556
- if (ctx) {
2557
- const renderer = this.tableFunctionStrategy.getRenderer(key);
2558
- if (renderer) {
2559
- const compiledArgs = (fn9.args ?? []).map((arg) => this.compileOperand(arg, ctx));
2560
- return renderer({
2561
- node: fn9,
2562
- compiledArgs,
2563
- compileOperand: (operand) => this.compileOperand(operand, ctx),
2564
- quoteIdentifier: this.quoteIdentifier.bind(this)
2565
- });
2566
- }
2567
- if (fn9.key) {
2568
- throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
2569
- }
2570
- }
2571
- return FunctionTableFormatter.format(fn9, ctx, this);
2609
+ return this.sourceCompiler.compileFunctionTable(fn9, ctx);
2572
2610
  }
2573
2611
  compileDerivedTable(table, ctx) {
2574
- if (!table.alias) {
2575
- throw new Error("Derived tables must have an alias.");
2576
- }
2577
- const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2578
- const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2579
- return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
2612
+ return this.sourceCompiler.compileDerivedTable(table, ctx);
2580
2613
  }
2581
2614
  compileTableSource(table) {
2582
- if (table.type === "FunctionTable") {
2583
- return this.compileFunctionTable(table);
2584
- }
2585
- if (table.type === "DerivedTable") {
2586
- return this.compileDerivedTable(table);
2587
- }
2588
- const base = this.compileTableName(table);
2589
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2615
+ return this.sourceCompiler.compileTableSource(table);
2590
2616
  }
2591
2617
  compileTableName(table) {
2592
- if (table.schema) {
2593
- return `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`;
2594
- }
2595
- return this.quoteIdentifier(table.name);
2618
+ return this.sourceCompiler.compileTableName(table);
2596
2619
  }
2597
2620
  compileTableReference(table) {
2598
- const base = this.compileTableName(table);
2599
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2600
- }
2601
- compileUpdateFromClause(ast, ctx) {
2602
- if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2603
- if (!ast.from) {
2604
- throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2605
- }
2606
- const from = this.compileFrom(ast.from, ctx);
2607
- const joins = JoinCompiler.compileJoins(
2608
- ast.joins,
2609
- ctx,
2610
- this.compileFrom.bind(this),
2611
- this.compileExpression.bind(this)
2612
- );
2613
- return ` FROM ${from}${joins}`;
2614
- }
2615
- compileDeleteUsingClause(ast, ctx) {
2616
- if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2617
- if (!ast.using) {
2618
- throw new Error("DELETE with JOINs requires a USING clause.");
2619
- }
2620
- const usingTable = this.compileFrom(ast.using, ctx);
2621
- const joins = JoinCompiler.compileJoins(
2622
- ast.joins,
2623
- ctx,
2624
- this.compileFrom.bind(this),
2625
- this.compileExpression.bind(this)
2626
- );
2627
- return ` USING ${usingTable}${joins}`;
2628
- }
2629
- compileHaving(ast, ctx) {
2630
- if (!ast.having) return "";
2631
- return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
2621
+ return this.sourceCompiler.compileTableReference(table);
2632
2622
  }
2633
2623
  stripTrailingSemicolon(sql) {
2634
- return sql.trim().replace(/;$/, "");
2624
+ return this.sourceCompiler.stripTrailingSemicolon(sql);
2635
2625
  }
2636
2626
  wrapSetOperand(sql) {
2637
- const trimmed = this.stripTrailingSemicolon(sql);
2638
- return `(${trimmed})`;
2627
+ return this.sourceCompiler.wrapSetOperand(sql);
2639
2628
  }
2640
2629
  renderOrderByNulls(order) {
2641
2630
  return order.nulls ? ` NULLS ${order.nulls}` : "";
@@ -3344,10 +3333,6 @@ var SqliteDialect = class extends SqlDialectBase {
3344
3333
  supportsDmlReturningClause() {
3345
3334
  return true;
3346
3335
  }
3347
- compileProcedureCall(_ast) {
3348
- void _ast;
3349
- throw new Error("Stored procedures are not supported by the SQLite dialect.");
3350
- }
3351
3336
  };
3352
3337
 
3353
3338
  // src/core/dialect/mssql/functions.ts
@@ -3782,9 +3767,8 @@ var DialectFactory = class {
3782
3767
  /**
3783
3768
  * Register (or override) a dialect factory for a key.
3784
3769
  *
3785
- * Examples:
3786
- * DialectFactory.register('sqlite', () => new SqliteDialect());
3787
- * DialectFactory.register('my-tenant-dialect', () => new CustomDialect());
3770
+ * Implementations are structural: extending DialectBase/SqlDialectBase is
3771
+ * optional. A composed object satisfying Dialect is a valid registration.
3788
3772
  */
3789
3773
  static register(key, factory) {
3790
3774
  this.registry.set(key, factory);
@@ -11357,6 +11341,15 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
11357
11341
  };
11358
11342
  var isTableSourceNode2 = (source) => typeof source.type === "string";
11359
11343
 
11344
+ // src/core/dialect/capabilities/procedure-compiler.ts
11345
+ var isProcedureCompiler = (value) => typeof value?.compileProcedureCall === "function";
11346
+ var requireProcedureCompiler = (value) => {
11347
+ if (!isProcedureCompiler(value)) {
11348
+ throw new Error("Stored procedures are not supported by this dialect.");
11349
+ }
11350
+ return value;
11351
+ };
11352
+
11360
11353
  // src/orm/execute-procedure.ts
11361
11354
  var resolveColumnIndex = (columns, expectedName) => {
11362
11355
  const exact = columns.findIndex((column) => column === expectedName);
@@ -11395,7 +11388,7 @@ var extractOutValues = (compiled, resultSets) => {
11395
11388
  };
11396
11389
  var executeProcedureAst = async (session, ast) => {
11397
11390
  const execCtx = session.getExecutionContext();
11398
- const compiled = execCtx.dialect.compileProcedureCall(ast);
11391
+ const compiled = requireProcedureCompiler(execCtx.dialect).compileProcedureCall(ast);
11399
11392
  const payload = await execCtx.interceptors.run(
11400
11393
  { sql: compiled.sql, params: compiled.params },
11401
11394
  execCtx.executor
@@ -11468,8 +11461,7 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
11468
11461
  }
11469
11462
  compile(dialect) {
11470
11463
  const resolved = resolveDialectInput(dialect);
11471
- this.validateMssqlOutDbType(resolved);
11472
- return resolved.compileProcedureCall(this.getAST());
11464
+ return requireProcedureCompiler(resolved).compileProcedureCall(this.getAST());
11473
11465
  }
11474
11466
  toSql(dialect) {
11475
11467
  return this.compile(dialect).sql;
@@ -11482,21 +11474,8 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
11482
11474
  };
11483
11475
  }
11484
11476
  async execute(session) {
11485
- this.validateMssqlOutDbType(session.getExecutionContext().dialect);
11486
11477
  return executeProcedureAst(session, this.getAST());
11487
11478
  }
11488
- validateMssqlOutDbType(dialect) {
11489
- const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
11490
- if (!isMssqlDialect) return;
11491
- for (const param of this.ast.params) {
11492
- const needsDbType = param.direction === "out" || param.direction === "inout";
11493
- if (needsDbType && !param.dbType) {
11494
- throw new Error(
11495
- `MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
11496
- );
11497
- }
11498
- }
11499
- }
11500
11479
  };
11501
11480
  var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
11502
11481
 
@@ -22225,6 +22204,8 @@ async function bulkUpsert(session, table, rows, options = {}) {
22225
22204
  DefaultMorphToReference,
22226
22205
  DefaultTypeStrategy,
22227
22206
  DeleteQueryBuilder,
22207
+ DialectBase,
22208
+ DialectFactory,
22228
22209
  DomainEventBus,
22229
22210
  Email,
22230
22211
  Entity,
@@ -22258,6 +22239,11 @@ async function bulkUpsert(session, table, rows, options = {}) {
22258
22239
  SelectQueryBuilder,
22259
22240
  SqlServerDialect,
22260
22241
  SqliteDialect,
22242
+ StandardDeleteCompiler,
22243
+ StandardInsertCompiler,
22244
+ StandardSelectCompiler,
22245
+ StandardSqlSourceCompiler,
22246
+ StandardUpdateCompiler,
22261
22247
  StringTypeStrategy,
22262
22248
  TagIndex,
22263
22249
  Title,
@@ -22452,6 +22438,7 @@ async function bulkUpsert(session, table, rows, options = {}) {
22452
22438
  isNull,
22453
22439
  isNullableColumn,
22454
22440
  isOperandNode,
22441
+ isProcedureCompiler,
22455
22442
  isSingleTargetRelation,
22456
22443
  isTableDef,
22457
22444
  isTreeConfig,
@@ -22549,6 +22536,8 @@ async function bulkUpsert(session, table, rows, options = {}) {
22549
22536
  repeat,
22550
22537
  replace,
22551
22538
  replaceWithRefs,
22539
+ requireProcedureCompiler,
22540
+ resolveDialectInput,
22552
22541
  resolveTreeConfig,
22553
22542
  resolveValidator,
22554
22543
  responseToRef,