metal-orm 1.1.23 → 1.1.25

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.
Files changed (37) hide show
  1. package/dist/index.cjs +832 -583
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +281 -144
  4. package/dist/index.d.ts +281 -144
  5. package/dist/index.js +807 -583
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/core/dialect/base/returning-strategy.ts +40 -39
  9. package/src/core/dialect/base/sql-compiler-set.ts +33 -0
  10. package/src/core/dialect/base/sql-dialect.ts +125 -222
  11. package/src/core/dialect/base/standard-delete-compiler.ts +37 -0
  12. package/src/core/dialect/base/standard-insert-compiler.ts +49 -0
  13. package/src/core/dialect/base/standard-select-compiler.ts +82 -0
  14. package/src/core/dialect/base/standard-sql-services.ts +44 -0
  15. package/src/core/dialect/base/standard-sql-source-compiler.ts +88 -0
  16. package/src/core/dialect/base/standard-update-compiler.ts +53 -0
  17. package/src/core/dialect/base/upsert-strategy.ts +45 -0
  18. package/src/core/dialect/capabilities/procedure-compiler.ts +10 -8
  19. package/src/core/dialect/mssql/compiler-factory.ts +12 -0
  20. package/src/core/dialect/mssql/delete-compiler.ts +40 -0
  21. package/src/core/dialect/mssql/index.ts +24 -371
  22. package/src/core/dialect/mssql/insert-compiler.ts +112 -0
  23. package/src/core/dialect/mssql/output.ts +46 -0
  24. package/src/core/dialect/mssql/procedure-compiler.ts +81 -0
  25. package/src/core/dialect/mssql/select-compiler.ts +116 -0
  26. package/src/core/dialect/mssql/update-compiler.ts +37 -0
  27. package/src/core/dialect/mysql/index.ts +24 -117
  28. package/src/core/dialect/mysql/procedure-compiler.ts +67 -0
  29. package/src/core/dialect/mysql/upsert.ts +42 -0
  30. package/src/core/dialect/postgres/index.ts +34 -101
  31. package/src/core/dialect/postgres/procedure-compiler.ts +41 -0
  32. package/src/core/dialect/postgres/returning.ts +4 -0
  33. package/src/core/dialect/postgres/upsert.ts +43 -0
  34. package/src/core/dialect/sqlite/index.ts +15 -70
  35. package/src/core/dialect/sqlite/returning.ts +30 -0
  36. package/src/core/dialect/sqlite/upsert.ts +43 -0
  37. package/src/index.ts +28 -10
package/dist/index.js CHANGED
@@ -1686,6 +1686,57 @@ var DialectBase = class _DialectBase {
1686
1686
  }
1687
1687
  };
1688
1688
 
1689
+ // src/core/dialect/base/pagination-strategy.ts
1690
+ var StandardLimitOffsetPagination = class {
1691
+ /**
1692
+ * Compiles LIMIT/OFFSET pagination clause.
1693
+ * @param limit - The maximum number of rows to return.
1694
+ * @param offset - The number of rows to skip.
1695
+ * @returns SQL pagination clause with LIMIT and/or OFFSET.
1696
+ */
1697
+ compilePagination(limit, offset) {
1698
+ const parts = [];
1699
+ if (limit !== void 0) parts.push(`LIMIT ${limit}`);
1700
+ if (offset !== void 0) parts.push(`OFFSET ${offset}`);
1701
+ return parts.length ? ` ${parts.join(" ")}` : "";
1702
+ }
1703
+ };
1704
+
1705
+ // src/core/dialect/base/returning-strategy.ts
1706
+ var NoReturningStrategy = class {
1707
+ compileReturning(returning, _ctx, _quoteIdentifier) {
1708
+ void _ctx;
1709
+ void _quoteIdentifier;
1710
+ if (!returning || returning.length === 0) return "";
1711
+ throw new Error("RETURNING is not supported by this dialect.");
1712
+ }
1713
+ formatReturningColumns(returning, quoteIdentifier) {
1714
+ return returning.map((column) => {
1715
+ const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
1716
+ const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
1717
+ return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
1718
+ }).join(", ");
1719
+ }
1720
+ };
1721
+ var StandardReturningStrategy = class extends NoReturningStrategy {
1722
+ compileReturning(returning, _ctx, quoteIdentifier) {
1723
+ void _ctx;
1724
+ if (!returning || returning.length === 0) return "";
1725
+ return ` RETURNING ${this.formatReturningColumns(returning, quoteIdentifier)}`;
1726
+ }
1727
+ };
1728
+
1729
+ // src/core/dialect/base/upsert-strategy.ts
1730
+ var NoUpsertStrategy = class {
1731
+ compile(ast, _ctx, services) {
1732
+ void _ctx;
1733
+ if (!ast.onConflict) return "";
1734
+ throw new Error(
1735
+ `UPSERT/ON CONFLICT is not supported by dialect "${services.getDialectName()}".`
1736
+ );
1737
+ }
1738
+ };
1739
+
1689
1740
  // src/core/dialect/base/function-table-formatter.ts
1690
1741
  var FunctionTableFormatter = class {
1691
1742
  static format(fn9, ctx, formatter) {
@@ -1722,19 +1773,71 @@ var FunctionTableFormatter = class {
1722
1773
  }
1723
1774
  };
1724
1775
 
1725
- // src/core/dialect/base/pagination-strategy.ts
1726
- var StandardLimitOffsetPagination = class {
1727
- /**
1728
- * Compiles LIMIT/OFFSET pagination clause.
1729
- * @param limit - The maximum number of rows to return.
1730
- * @param offset - The number of rows to skip.
1731
- * @returns SQL pagination clause with LIMIT and/or OFFSET.
1732
- */
1733
- compilePagination(limit, offset) {
1734
- const parts = [];
1735
- if (limit !== void 0) parts.push(`LIMIT ${limit}`);
1736
- if (offset !== void 0) parts.push(`OFFSET ${offset}`);
1737
- return parts.length ? ` ${parts.join(" ")}` : "";
1776
+ // src/core/dialect/base/standard-sql-source-compiler.ts
1777
+ var StandardSqlSourceCompiler = class {
1778
+ constructor(services) {
1779
+ this.services = services;
1780
+ }
1781
+ compileFrom(source, ctx) {
1782
+ if (source.type === "FunctionTable") return this.compileFunctionTable(source, ctx);
1783
+ if (source.type === "DerivedTable") return this.compileDerivedTable(source, ctx);
1784
+ return this.compileTableSource(source);
1785
+ }
1786
+ compileFunctionTable(fn9, ctx) {
1787
+ const key = fn9.key ?? fn9.name;
1788
+ if (ctx) {
1789
+ const renderer = this.services.getTableFunctionStrategy().getRenderer(key);
1790
+ if (renderer) {
1791
+ const compiledArgs = (fn9.args ?? []).map((arg) => this.services.compileOperand(arg, ctx));
1792
+ return renderer({
1793
+ node: fn9,
1794
+ compiledArgs,
1795
+ compileOperand: (operand) => this.services.compileOperand(operand, ctx),
1796
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id)
1797
+ });
1798
+ }
1799
+ if (fn9.key) {
1800
+ throw new Error(
1801
+ `Table function "${key}" is not supported by dialect "${this.services.getDialectName()}".`
1802
+ );
1803
+ }
1804
+ }
1805
+ return FunctionTableFormatter.format(fn9, ctx, {
1806
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id),
1807
+ compileOperand: (node, compilerContext) => this.services.compileOperand(node, compilerContext)
1808
+ });
1809
+ }
1810
+ compileDerivedTable(table, ctx) {
1811
+ if (!table.alias) throw new Error("Derived tables must have an alias.");
1812
+ if (!ctx) throw new Error("Derived table compilation requires a compiler context.");
1813
+ const normalized = this.services.normalizeSelectAst(table.query);
1814
+ const subquery = this.services.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1815
+ const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((column) => this.services.quoteIdentifier(column)).join(", ")})` : "";
1816
+ return `(${subquery}) AS ${this.services.quoteIdentifier(table.alias)}${columns}`;
1817
+ }
1818
+ compileTableSource(table) {
1819
+ if (table.type === "FunctionTable") return this.compileFunctionTable(table);
1820
+ if (table.type === "DerivedTable") {
1821
+ throw new Error("Derived table compilation requires a compiler context.");
1822
+ }
1823
+ const base = this.compileTableName(table);
1824
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
1825
+ }
1826
+ compileTableName(table) {
1827
+ if (table.schema) {
1828
+ return `${this.services.quoteIdentifier(table.schema)}.${this.services.quoteIdentifier(table.name)}`;
1829
+ }
1830
+ return this.services.quoteIdentifier(table.name);
1831
+ }
1832
+ compileTableReference(table) {
1833
+ const base = this.compileTableName(table);
1834
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
1835
+ }
1836
+ stripTrailingSemicolon(sql) {
1837
+ return sql.trim().replace(/;$/, "");
1838
+ }
1839
+ wrapSetOperand(sql) {
1840
+ return `(${this.stripTrailingSemicolon(sql)})`;
1738
1841
  }
1739
1842
  };
1740
1843
 
@@ -1764,34 +1867,6 @@ var CteCompiler = class {
1764
1867
  }
1765
1868
  };
1766
1869
 
1767
- // src/core/dialect/base/returning-strategy.ts
1768
- var NoReturningStrategy = class {
1769
- /**
1770
- * Throws an error as RETURNING is not supported.
1771
- * @param returning - Columns to return (causes error if non-empty).
1772
- * @param _ctx - Compiler context (unused).
1773
- * @throws Error indicating RETURNING is not supported.
1774
- */
1775
- compileReturning(returning, _ctx) {
1776
- void _ctx;
1777
- if (!returning || returning.length === 0) return "";
1778
- throw new Error("RETURNING is not supported by this dialect.");
1779
- }
1780
- /**
1781
- * Formats column names for RETURNING clause.
1782
- * @param returning - Columns to format.
1783
- * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
1784
- * @returns Simple comma-separated column names.
1785
- */
1786
- formatReturningColumns(returning, quoteIdentifier) {
1787
- return returning.map((column) => {
1788
- const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
1789
- const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
1790
- return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
1791
- }).join(", ");
1792
- }
1793
- };
1794
-
1795
1870
  // src/core/dialect/base/join-compiler.ts
1796
1871
  var JoinCompiler = class {
1797
1872
  static compileJoins(joins, ctx, compileFrom, compileExpression) {
@@ -1842,108 +1917,254 @@ var OrderByCompiler = class {
1842
1917
  }
1843
1918
  };
1844
1919
 
1845
- // src/core/dialect/base/sql-dialect.ts
1846
- var SqlDialectBase = class extends DialectBase {
1847
- paginationStrategy = new StandardLimitOffsetPagination();
1848
- returningStrategy = new NoReturningStrategy();
1849
- compileSelectAst(ast, ctx) {
1920
+ // src/core/dialect/base/standard-select-compiler.ts
1921
+ var StandardSelectCompiler = class {
1922
+ constructor(services, sources) {
1923
+ this.services = services;
1924
+ this.sources = sources;
1925
+ }
1926
+ compile(ast, ctx) {
1850
1927
  const hasSetOps = !!(ast.setOps && ast.setOps.length);
1851
1928
  const ctes = CteCompiler.compileCtes(
1852
1929
  ast,
1853
1930
  ctx,
1854
- this.quoteIdentifier.bind(this),
1855
- this.compileSelectAst.bind(this),
1856
- this.normalizeSelectAst.bind(this),
1857
- this.stripTrailingSemicolon.bind(this)
1931
+ (id) => this.services.quoteIdentifier(id),
1932
+ (query, compilerContext) => this.services.compileSelectAst(query, compilerContext),
1933
+ (query) => this.services.normalizeSelectAst(query),
1934
+ (sql) => this.sources.stripTrailingSemicolon(sql)
1858
1935
  );
1859
1936
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
1860
- const baseSelect = this.compileSelectCore(baseAst, ctx);
1937
+ const baseSelect = this.compileCore(baseAst, ctx);
1861
1938
  if (!hasSetOps) return `${ctes}${baseSelect}`;
1862
- return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
1939
+ const compound = ast.setOps.map((op) => `${op.operator} ${this.sources.wrapSetOperand(this.services.compileSelectAst(op.query, ctx))}`).join(" ");
1940
+ const orderBy = this.compileOrderBy(ast, ctx);
1941
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
1942
+ const combined = `${this.sources.wrapSetOperand(baseSelect)} ${compound}`;
1943
+ return `${ctes}${combined}${orderBy}${pagination}`;
1944
+ }
1945
+ compileCore(ast, ctx) {
1946
+ const columns = this.compileColumns(ast, ctx);
1947
+ const from = this.sources.compileFrom(ast.from, ctx);
1948
+ const joins = JoinCompiler.compileJoins(
1949
+ ast.joins,
1950
+ ctx,
1951
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
1952
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
1953
+ );
1954
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
1955
+ const groupBy = GroupByCompiler.compileGroupBy(
1956
+ ast,
1957
+ (term) => this.services.compileOrderingTerm(term, ctx)
1958
+ );
1959
+ const having = ast.having ? ` HAVING ${this.services.compileExpression(ast.having, ctx)}` : "";
1960
+ const orderBy = this.compileOrderBy(ast, ctx);
1961
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
1962
+ return `SELECT ${ast.distinct ? "DISTINCT " : ""}${columns} FROM ${from}${joins}${where}${groupBy}${having}${orderBy}${pagination}`;
1863
1963
  }
1864
- compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
1865
- const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
1866
- const orderBy = OrderByCompiler.compileOrderBy(
1964
+ compileColumns(ast, ctx) {
1965
+ if (!ast.columns || ast.columns.length === 0) return "*";
1966
+ return ast.columns.map((column) => {
1967
+ const expr = this.services.compileOperand(column, ctx);
1968
+ if (!column.alias) return expr;
1969
+ if (column.alias.includes("(")) return column.alias;
1970
+ return `${expr} AS ${this.services.quoteIdentifier(column.alias)}`;
1971
+ }).join(", ");
1972
+ }
1973
+ compileOrderBy(ast, ctx) {
1974
+ return OrderByCompiler.compileOrderBy(
1867
1975
  ast,
1868
- (term) => this.compileOrderingTerm(term, ctx),
1869
- this.renderOrderByNulls.bind(this),
1870
- this.renderOrderByCollation.bind(this)
1976
+ (term) => this.services.compileOrderingTerm(term, ctx),
1977
+ (order) => this.services.renderOrderByNulls(order),
1978
+ (order) => this.services.renderOrderByCollation(order)
1871
1979
  );
1872
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
1873
- const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
1874
- return `${ctes}${combined}${orderBy}${pagination}`;
1875
1980
  }
1876
- compileInsertAst(ast, ctx) {
1981
+ };
1982
+
1983
+ // src/core/dialect/base/standard-insert-compiler.ts
1984
+ var StandardInsertCompiler = class {
1985
+ constructor(services, sources) {
1986
+ this.services = services;
1987
+ this.sources = sources;
1988
+ }
1989
+ compile(ast, ctx) {
1877
1990
  if (!ast.columns.length) {
1878
1991
  throw new Error("INSERT queries must specify columns.");
1879
1992
  }
1880
- const table = this.compileTableName(ast.into);
1881
- const columnList = this.compileInsertColumnList(ast.columns);
1882
- const source = this.compileInsertSource(ast.source, ctx);
1883
- const upsert = this.compileUpsertClause(ast, ctx);
1884
- const returning = this.compileReturning(ast.returning, ctx);
1993
+ const table = this.sources.compileTableName(ast.into);
1994
+ const columnList = this.compileColumnList(ast.columns);
1995
+ const source = this.compileSource(ast.source, ctx);
1996
+ const upsert = this.services.compileUpsertClause(ast, ctx);
1997
+ const returning = this.services.compileReturning(ast.returning, ctx);
1885
1998
  return `INSERT INTO ${table} (${columnList}) ${source}${upsert}${returning}`;
1886
1999
  }
1887
- compileUpsertClause(ast, _ctx) {
1888
- void _ctx;
1889
- if (!ast.onConflict) return "";
1890
- throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
1891
- }
1892
- compileReturning(returning, ctx) {
1893
- return this.returningStrategy.compileReturning(returning, ctx);
1894
- }
1895
- compileInsertSource(source, ctx) {
2000
+ compileSource(source, ctx) {
1896
2001
  if (source.type === "InsertValues") {
1897
2002
  if (!source.rows.length) {
1898
2003
  throw new Error("INSERT ... VALUES requires at least one row.");
1899
2004
  }
1900
- const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
2005
+ const values = source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
1901
2006
  return `VALUES ${values}`;
1902
2007
  }
1903
- const normalized = this.normalizeSelectAst(source.query);
1904
- return this.compileSelectAst(normalized, ctx).trim();
2008
+ const normalized = this.services.normalizeSelectAst(source.query);
2009
+ return this.services.compileSelectAst(normalized, ctx).trim();
1905
2010
  }
1906
- compileInsertColumnList(columns) {
1907
- return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
2011
+ compileColumnList(columns) {
2012
+ return columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
1908
2013
  }
1909
2014
  ensureConflictColumns(clause, message) {
1910
2015
  if (!clause.target.columns.length) throw new Error(message);
1911
2016
  }
1912
- compileSelectCore(ast, ctx) {
1913
- const columns = this.compileSelectColumns(ast, ctx);
1914
- const from = this.compileFrom(ast.from, ctx);
2017
+ };
2018
+
2019
+ // src/core/dialect/base/standard-update-compiler.ts
2020
+ var StandardUpdateCompiler = class {
2021
+ constructor(services, sources) {
2022
+ this.services = services;
2023
+ this.sources = sources;
2024
+ }
2025
+ compile(ast, ctx) {
2026
+ const target = this.sources.compileTableReference(ast.table);
2027
+ const assignments = this.compileAssignments(ast.set, ast.table, ctx);
2028
+ const from = this.compileFromClause(ast, ctx);
2029
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2030
+ const returning = this.services.compileReturning(ast.returning, ctx);
2031
+ return `UPDATE ${target} SET ${assignments}${from}${where}${returning}`;
2032
+ }
2033
+ compileAssignments(assignments, table, ctx) {
2034
+ return assignments.map((assignment) => {
2035
+ const target = this.services.compileSetTarget(assignment.column, table);
2036
+ const value = this.services.compileOperand(assignment.value, ctx);
2037
+ return `${target} = ${value}`;
2038
+ }).join(", ");
2039
+ }
2040
+ compileFromClause(ast, ctx) {
2041
+ if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2042
+ if (!ast.from) {
2043
+ throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2044
+ }
2045
+ const from = this.sources.compileFrom(ast.from, ctx);
1915
2046
  const joins = JoinCompiler.compileJoins(
1916
2047
  ast.joins,
1917
2048
  ctx,
1918
- this.compileFrom.bind(this),
1919
- this.compileExpression.bind(this)
2049
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2050
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
1920
2051
  );
1921
- const whereClause = this.compileWhere(ast.where, ctx);
1922
- const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
1923
- const having = this.compileHaving(ast, ctx);
1924
- const orderBy = OrderByCompiler.compileOrderBy(
1925
- ast,
1926
- (term) => this.compileOrderingTerm(term, ctx),
1927
- this.renderOrderByNulls.bind(this),
1928
- this.renderOrderByCollation.bind(this)
2052
+ return ` FROM ${from}${joins}`;
2053
+ }
2054
+ };
2055
+
2056
+ // src/core/dialect/base/standard-delete-compiler.ts
2057
+ var StandardDeleteCompiler = class {
2058
+ constructor(services, sources) {
2059
+ this.services = services;
2060
+ this.sources = sources;
2061
+ }
2062
+ compile(ast, ctx) {
2063
+ const target = this.sources.compileTableReference(ast.from);
2064
+ const using = this.compileUsingClause(ast, ctx);
2065
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2066
+ const returning = this.services.compileReturning(ast.returning, ctx);
2067
+ return `DELETE FROM ${target}${using}${where}${returning}`;
2068
+ }
2069
+ compileUsingClause(ast, ctx) {
2070
+ if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2071
+ if (!ast.using) {
2072
+ throw new Error("DELETE with JOINs requires a USING clause.");
2073
+ }
2074
+ const usingTable = this.sources.compileFrom(ast.using, ctx);
2075
+ const joins = JoinCompiler.compileJoins(
2076
+ ast.joins,
2077
+ ctx,
2078
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2079
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
1929
2080
  );
1930
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
1931
- return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
2081
+ return ` USING ${usingTable}${joins}`;
2082
+ }
2083
+ };
2084
+
2085
+ // src/core/dialect/base/sql-dialect.ts
2086
+ var SqlDialectBase = class extends DialectBase {
2087
+ paginationStrategy;
2088
+ returningStrategy;
2089
+ upsertStrategy;
2090
+ dmlReturningSupported;
2091
+ sourceCompiler;
2092
+ standardUpdateCompiler;
2093
+ compilerSet;
2094
+ constructor(options = {}) {
2095
+ super(options.functionStrategy, options.tableFunctionStrategy);
2096
+ this.paginationStrategy = options.paginationStrategy ?? new StandardLimitOffsetPagination();
2097
+ this.returningStrategy = options.returningStrategy ?? new NoReturningStrategy();
2098
+ this.upsertStrategy = options.upsertStrategy ?? new NoUpsertStrategy();
2099
+ this.dmlReturningSupported = options.supportsDmlReturning ?? false;
2100
+ const services = {
2101
+ getDialectName: () => this.dialect,
2102
+ getPaginationStrategy: () => this.paginationStrategy,
2103
+ getTableFunctionStrategy: () => this.tableFunctionStrategy,
2104
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2105
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx),
2106
+ compileExpression: (node, ctx) => this.compileExpression(node, ctx),
2107
+ compileOrderingTerm: (term, ctx) => this.compileOrderingTerm(term, ctx),
2108
+ normalizeSelectAst: (ast) => this.normalizeSelectAst(ast),
2109
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
2110
+ compileReturning: (returning, ctx) => this.compileReturning(returning, ctx),
2111
+ compileUpsertClause: (ast, ctx) => this.compileUpsertClause(ast, ctx),
2112
+ compileSetTarget: (column, table) => this.compileSetTarget(column, table),
2113
+ renderOrderByNulls: (order) => this.renderOrderByNulls(order),
2114
+ renderOrderByCollation: (order) => this.renderOrderByCollation(order)
2115
+ };
2116
+ this.sourceCompiler = new StandardSqlSourceCompiler(services);
2117
+ const standardSelect = new StandardSelectCompiler(services, this.sourceCompiler);
2118
+ const standardInsert = new StandardInsertCompiler(services, this.sourceCompiler);
2119
+ this.standardUpdateCompiler = new StandardUpdateCompiler(services, this.sourceCompiler);
2120
+ const standardDelete = new StandardDeleteCompiler(services, this.sourceCompiler);
2121
+ const overrides = options.compilerFactory?.({
2122
+ services,
2123
+ sources: this.sourceCompiler
2124
+ }) ?? {};
2125
+ this.compilerSet = {
2126
+ select: overrides.select ?? standardSelect,
2127
+ insert: overrides.insert ?? standardInsert,
2128
+ update: overrides.update ?? this.standardUpdateCompiler,
2129
+ delete: overrides.delete ?? standardDelete
2130
+ };
2131
+ }
2132
+ supportsDmlReturningClause() {
2133
+ return this.dmlReturningSupported;
2134
+ }
2135
+ compileSelectAst(ast, ctx) {
2136
+ return this.compilerSet.select.compile(ast, ctx);
2137
+ }
2138
+ compileInsertAst(ast, ctx) {
2139
+ return this.compilerSet.insert.compile(ast, ctx);
1932
2140
  }
1933
2141
  compileUpdateAst(ast, ctx) {
1934
- const target = this.compileTableReference(ast.table);
1935
- const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
1936
- const fromClause = this.compileUpdateFromClause(ast, ctx);
1937
- const whereClause = this.compileWhere(ast.where, ctx);
1938
- const returning = this.compileReturning(ast.returning, ctx);
1939
- return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
2142
+ return this.compilerSet.update.compile(ast, ctx);
2143
+ }
2144
+ compileDeleteAst(ast, ctx) {
2145
+ return this.compilerSet.delete.compile(ast, ctx);
2146
+ }
2147
+ compileUpsertClause(ast, ctx) {
2148
+ return this.upsertStrategy.compile(ast, ctx, {
2149
+ getDialectName: () => this.dialect,
2150
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2151
+ compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext),
2152
+ compileExpression: (node, compilerContext) => this.compileExpression(node, compilerContext),
2153
+ compileUpdateAssignments: (assignments, table, compilerContext) => this.standardUpdateCompiler.compileAssignments(assignments, table, compilerContext)
2154
+ });
2155
+ }
2156
+ compileReturning(returning, ctx) {
2157
+ return this.returningStrategy.compileReturning(
2158
+ returning,
2159
+ ctx,
2160
+ (id) => this.quoteIdentifier(id)
2161
+ );
2162
+ }
2163
+ ensureConflictColumns(clause, message) {
2164
+ if (!clause.target.columns.length) throw new Error(message);
1940
2165
  }
1941
2166
  compileUpdateAssignments(assignments, table, ctx) {
1942
- return assignments.map((assignment) => {
1943
- const target = this.compileSetTarget(assignment.column, table);
1944
- const value = this.compileOperand(assignment.value, ctx);
1945
- return `${target} = ${value}`;
1946
- }).join(", ");
2167
+ return this.standardUpdateCompiler.compileAssignments(assignments, table, ctx);
1947
2168
  }
1948
2169
  compileSetTarget(column, table) {
1949
2170
  return this.compileQualifiedColumn(column, table);
@@ -1956,112 +2177,35 @@ var SqlDialectBase = class extends DialectBase {
1956
2177
  if (!tableQualifier) return this.quoteIdentifier(column.name);
1957
2178
  return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
1958
2179
  }
1959
- compileDeleteAst(ast, ctx) {
1960
- const target = this.compileTableReference(ast.from);
1961
- const usingClause = this.compileDeleteUsingClause(ast, ctx);
1962
- const whereClause = this.compileWhere(ast.where, ctx);
1963
- const returning = this.compileReturning(ast.returning, ctx);
1964
- return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
1965
- }
1966
2180
  formatReturningColumns(returning) {
1967
- return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
1968
- }
1969
- compileDistinct(ast) {
1970
- return ast.distinct ? "DISTINCT " : "";
1971
- }
1972
- compileSelectColumns(ast, ctx) {
1973
- if (!ast.columns || ast.columns.length === 0) return "*";
1974
- return ast.columns.map((column) => {
1975
- const expr = this.compileOperand(column, ctx);
1976
- if (column.alias) {
1977
- if (column.alias.includes("(")) return column.alias;
1978
- return `${expr} AS ${this.quoteIdentifier(column.alias)}`;
1979
- }
1980
- return expr;
1981
- }).join(", ");
2181
+ return this.returningStrategy.formatReturningColumns(
2182
+ returning,
2183
+ (id) => this.quoteIdentifier(id)
2184
+ );
1982
2185
  }
1983
- compileFrom(ast, ctx) {
1984
- if (ast.type === "FunctionTable") return this.compileFunctionTable(ast, ctx);
1985
- if (ast.type === "DerivedTable") return this.compileDerivedTable(ast, ctx);
1986
- return this.compileTableSource(ast);
2186
+ compileFrom(source, ctx) {
2187
+ return this.sourceCompiler.compileFrom(source, ctx);
1987
2188
  }
1988
2189
  compileFunctionTable(fn9, ctx) {
1989
- const key = fn9.key ?? fn9.name;
1990
- if (ctx) {
1991
- const renderer = this.tableFunctionStrategy.getRenderer(key);
1992
- if (renderer) {
1993
- const compiledArgs = (fn9.args ?? []).map((arg) => this.compileOperand(arg, ctx));
1994
- return renderer({
1995
- node: fn9,
1996
- compiledArgs,
1997
- compileOperand: (operand) => this.compileOperand(operand, ctx),
1998
- quoteIdentifier: this.quoteIdentifier.bind(this)
1999
- });
2000
- }
2001
- if (fn9.key) {
2002
- throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
2003
- }
2004
- }
2005
- return FunctionTableFormatter.format(fn9, ctx, {
2006
- quoteIdentifier: (id) => this.quoteIdentifier(id),
2007
- compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext)
2008
- });
2190
+ return this.sourceCompiler.compileFunctionTable(fn9, ctx);
2009
2191
  }
2010
2192
  compileDerivedTable(table, ctx) {
2011
- if (!table.alias) throw new Error("Derived tables must have an alias.");
2012
- const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2013
- const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2014
- return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
2193
+ return this.sourceCompiler.compileDerivedTable(table, ctx);
2015
2194
  }
2016
2195
  compileTableSource(table) {
2017
- if (table.type === "FunctionTable") return this.compileFunctionTable(table);
2018
- if (table.type === "DerivedTable") return this.compileDerivedTable(table);
2019
- const base = this.compileTableName(table);
2020
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2196
+ return this.sourceCompiler.compileTableSource(table);
2021
2197
  }
2022
2198
  compileTableName(table) {
2023
- if (table.schema) {
2024
- return `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`;
2025
- }
2026
- return this.quoteIdentifier(table.name);
2199
+ return this.sourceCompiler.compileTableName(table);
2027
2200
  }
2028
2201
  compileTableReference(table) {
2029
- const base = this.compileTableName(table);
2030
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2031
- }
2032
- compileUpdateFromClause(ast, ctx) {
2033
- if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2034
- if (!ast.from) throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2035
- const from = this.compileFrom(ast.from, ctx);
2036
- const joins = JoinCompiler.compileJoins(
2037
- ast.joins,
2038
- ctx,
2039
- this.compileFrom.bind(this),
2040
- this.compileExpression.bind(this)
2041
- );
2042
- return ` FROM ${from}${joins}`;
2043
- }
2044
- compileDeleteUsingClause(ast, ctx) {
2045
- if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2046
- if (!ast.using) throw new Error("DELETE with JOINs requires a USING clause.");
2047
- const usingTable = this.compileFrom(ast.using, ctx);
2048
- const joins = JoinCompiler.compileJoins(
2049
- ast.joins,
2050
- ctx,
2051
- this.compileFrom.bind(this),
2052
- this.compileExpression.bind(this)
2053
- );
2054
- return ` USING ${usingTable}${joins}`;
2055
- }
2056
- compileHaving(ast, ctx) {
2057
- if (!ast.having) return "";
2058
- return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
2202
+ return this.sourceCompiler.compileTableReference(table);
2059
2203
  }
2060
2204
  stripTrailingSemicolon(sql) {
2061
- return sql.trim().replace(/;$/, "");
2205
+ return this.sourceCompiler.stripTrailingSemicolon(sql);
2062
2206
  }
2063
2207
  wrapSetOperand(sql) {
2064
- return `(${this.stripTrailingSemicolon(sql)})`;
2208
+ return this.sourceCompiler.wrapSetOperand(sql);
2065
2209
  }
2066
2210
  renderOrderByNulls(order) {
2067
2211
  return order.nulls ? ` NULLS ${order.nulls}` : "";
@@ -2246,105 +2390,112 @@ var PostgresTableFunctionStrategy = class extends StandardTableFunctionStrategy
2246
2390
  }
2247
2391
  };
2248
2392
 
2393
+ // src/core/dialect/postgres/procedure-compiler.ts
2394
+ var PostgresProcedureCompiler = class {
2395
+ constructor(services) {
2396
+ this.services = services;
2397
+ }
2398
+ compileProcedureCall(ast) {
2399
+ const ctx = this.services.createCompilerContext();
2400
+ const qualifiedName = ast.ref.schema ? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}` : this.services.quoteIdentifier(ast.ref.name);
2401
+ const args = [];
2402
+ for (const param of ast.params) {
2403
+ if (param.direction === "out") continue;
2404
+ if (!param.value) {
2405
+ throw new Error(
2406
+ `Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`
2407
+ );
2408
+ }
2409
+ args.push(this.services.compileOperand(param.value, ctx));
2410
+ }
2411
+ const outNames = ast.params.filter((param) => param.direction === "out" || param.direction === "inout").map((param) => param.name);
2412
+ return {
2413
+ sql: `CALL ${qualifiedName}(${args.join(", ")});`,
2414
+ params: [...ctx.params],
2415
+ outParams: {
2416
+ source: outNames.length ? "firstResultSet" : "none",
2417
+ names: outNames
2418
+ }
2419
+ };
2420
+ }
2421
+ };
2422
+
2423
+ // src/core/dialect/postgres/returning.ts
2424
+ var PostgresReturningStrategy = class extends StandardReturningStrategy {
2425
+ };
2426
+
2427
+ // src/core/dialect/postgres/upsert.ts
2428
+ var PostgresUpsertStrategy = class {
2429
+ compile(ast, ctx, services) {
2430
+ if (!ast.onConflict) return "";
2431
+ const clause = ast.onConflict;
2432
+ const target = clause.target.constraint ? ` ON CONFLICT ON CONSTRAINT ${services.quoteIdentifier(clause.target.constraint)}` : (() => {
2433
+ if (!clause.target.columns.length) {
2434
+ throw new Error("PostgreSQL ON CONFLICT requires conflict columns or a constraint name.");
2435
+ }
2436
+ const columns = clause.target.columns.map((column) => services.quoteIdentifier(column.name)).join(", ");
2437
+ return ` ON CONFLICT (${columns})`;
2438
+ })();
2439
+ if (clause.action.type === "DoNothing") {
2440
+ return `${target} DO NOTHING`;
2441
+ }
2442
+ if (!clause.action.set.length) {
2443
+ throw new Error("PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.");
2444
+ }
2445
+ const assignments = services.compileUpdateAssignments(clause.action.set, ast.into, ctx);
2446
+ const where = clause.action.where ? ` WHERE ${services.compileExpression(clause.action.where, ctx)}` : "";
2447
+ return `${target} DO UPDATE SET ${assignments}${where}`;
2448
+ }
2449
+ };
2450
+
2249
2451
  // src/core/dialect/postgres/index.ts
2250
2452
  var PostgresDialect = class extends SqlDialectBase {
2251
2453
  dialect = "postgres";
2252
- /**
2253
- * Creates a new PostgresDialect instance
2254
- */
2454
+ procedureCompiler;
2255
2455
  constructor() {
2256
- super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
2456
+ super({
2457
+ functionStrategy: new PostgresFunctionStrategy(),
2458
+ tableFunctionStrategy: new PostgresTableFunctionStrategy(),
2459
+ returningStrategy: new PostgresReturningStrategy(),
2460
+ upsertStrategy: new PostgresUpsertStrategy(),
2461
+ supportsDmlReturning: true
2462
+ });
2463
+ this.procedureCompiler = new PostgresProcedureCompiler({
2464
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2465
+ createCompilerContext: () => this.createCompilerContext(),
2466
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx)
2467
+ });
2257
2468
  this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
2258
2469
  const left2 = this.compileOperand(node.left, ctx);
2259
2470
  const right2 = this.compileOperand(node.right, ctx);
2260
- const op = node.operator === "^" ? "#" : node.operator;
2261
- return `${left2} ${op} ${right2}`;
2471
+ const operator = node.operator === "^" ? "#" : node.operator;
2472
+ return `${left2} ${operator} ${right2}`;
2262
2473
  });
2263
2474
  this.registerOperandCompiler("BitwiseExpression", (node, ctx) => {
2264
2475
  const left2 = this.compileOperand(node.left, ctx);
2265
2476
  const right2 = this.compileOperand(node.right, ctx);
2266
- const op = node.operator === "^" ? "#" : node.operator;
2267
- return `(${left2} ${op} ${right2})`;
2477
+ const operator = node.operator === "^" ? "#" : node.operator;
2478
+ return `(${left2} ${operator} ${right2})`;
2268
2479
  });
2269
2480
  }
2270
- /**
2271
- * Quotes an identifier using PostgreSQL double-quote syntax
2272
- * @param id - Identifier to quote
2273
- * @returns Quoted identifier
2274
- */
2275
2481
  quoteIdentifier(id) {
2276
2482
  return `"${id}"`;
2277
2483
  }
2278
2484
  formatPlaceholder(index) {
2279
2485
  return `$${index}`;
2280
2486
  }
2281
- /**
2282
- * Compiles JSON path expression using PostgreSQL syntax
2283
- * @param node - JSON path node
2284
- * @returns PostgreSQL JSON path expression
2285
- */
2286
2487
  compileJsonPath(node) {
2287
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2288
- return `${col2}->>'${node.path}'`;
2289
- }
2290
- compileReturning(returning, ctx) {
2291
- void ctx;
2292
- if (!returning || returning.length === 0) return "";
2293
- const columns = this.formatReturningColumns(returning);
2294
- return ` RETURNING ${columns}`;
2295
- }
2296
- compileUpsertClause(ast, ctx) {
2297
- if (!ast.onConflict) return "";
2298
- const clause = ast.onConflict;
2299
- const target = clause.target.constraint ? ` ON CONFLICT ON CONSTRAINT ${this.quoteIdentifier(clause.target.constraint)}` : (() => {
2300
- this.ensureConflictColumns(
2301
- clause,
2302
- "PostgreSQL ON CONFLICT requires conflict columns or a constraint name."
2303
- );
2304
- const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
2305
- return ` ON CONFLICT (${cols})`;
2306
- })();
2307
- if (clause.action.type === "DoNothing") {
2308
- return `${target} DO NOTHING`;
2309
- }
2310
- if (!clause.action.set.length) {
2311
- throw new Error("PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.");
2312
- }
2313
- const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
2314
- const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
2315
- return `${target} DO UPDATE SET ${assignments}${where}`;
2316
- }
2317
- supportsDmlReturningClause() {
2318
- return true;
2319
- }
2320
- compileProcedureCall(ast) {
2321
- const ctx = this.createCompilerContext();
2322
- const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
2323
- const args = [];
2324
- for (const param of ast.params) {
2325
- if (param.direction === "out") continue;
2326
- if (!param.value) {
2327
- throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
2328
- }
2329
- args.push(this.compileOperand(param.value, ctx));
2330
- }
2331
- const outNames = ast.params.filter((param) => param.direction === "out" || param.direction === "inout").map((param) => param.name);
2332
- const rawSql = `CALL ${qualifiedName}(${args.join(", ")})`;
2333
- return {
2334
- sql: `${rawSql};`,
2335
- params: [...ctx.params],
2336
- outParams: {
2337
- source: outNames.length ? "firstResultSet" : "none",
2338
- names: outNames
2339
- }
2340
- };
2488
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2489
+ return `${column}->>'${node.path}'`;
2341
2490
  }
2342
- /**
2343
- * PostgreSQL requires unqualified column names in SET clause
2344
- */
2491
+ /** PostgreSQL requires unqualified column names in SET clauses. */
2345
2492
  compileSetTarget(column, _table) {
2493
+ void _table;
2346
2494
  return this.quoteIdentifier(column.name);
2347
2495
  }
2496
+ compileProcedureCall(ast) {
2497
+ return this.procedureCompiler.compileProcedureCall(ast);
2498
+ }
2348
2499
  };
2349
2500
 
2350
2501
  // src/core/dialect/mysql/functions.ts
@@ -2445,72 +2596,15 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
2445
2596
  }
2446
2597
  };
2447
2598
 
2448
- // src/core/dialect/mysql/index.ts
2599
+ // src/core/dialect/mysql/procedure-compiler.ts
2449
2600
  var sanitizeVariableSuffix = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
2450
- var MySqlDialect = class extends SqlDialectBase {
2451
- dialect = "mysql";
2452
- /**
2453
- * Creates a new MySqlDialect instance
2454
- */
2455
- constructor() {
2456
- super(new MysqlFunctionStrategy());
2457
- this.registerExpressionCompiler(
2458
- "IsDistinctExpression",
2459
- (node, ctx) => {
2460
- const left2 = this.compileOperand(node.left, ctx);
2461
- const right2 = this.compileOperand(node.right, ctx);
2462
- const spaceship = `${left2} <=> ${right2}`;
2463
- if (node.operator === "IS NOT DISTINCT FROM") {
2464
- return spaceship;
2465
- }
2466
- return `NOT (${spaceship})`;
2467
- }
2468
- );
2469
- }
2470
- /**
2471
- * Quotes an identifier using MySQL backtick syntax
2472
- * @param id - Identifier to quote
2473
- * @returns Quoted identifier
2474
- */
2475
- quoteIdentifier(id) {
2476
- return `\`${id}\``;
2477
- }
2478
- /**
2479
- * Compiles JSON path expression using MySQL syntax
2480
- * @param node - JSON path node
2481
- * @returns MySQL JSON path expression
2482
- */
2483
- compileJsonPath(node) {
2484
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2485
- return `${col2}->'${node.path}'`;
2486
- }
2487
- compileUpsertClause(ast, ctx) {
2488
- if (!ast.onConflict) return "";
2489
- const clause = ast.onConflict;
2490
- if (clause.action.type === "DoNothing") {
2491
- const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
2492
- if (!noOpColumn) {
2493
- throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one target column.");
2494
- }
2495
- const col2 = this.quoteIdentifier(noOpColumn.name);
2496
- return ` ON DUPLICATE KEY UPDATE ${col2} = ${col2}`;
2497
- }
2498
- if (clause.action.where) {
2499
- throw new Error("MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.");
2500
- }
2501
- if (!clause.action.set.length) {
2502
- throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.");
2503
- }
2504
- const assignments = clause.action.set.map((assignment) => {
2505
- const target = this.quoteIdentifier(assignment.column.name);
2506
- const value = this.compileOperand(assignment.value, ctx);
2507
- return `${target} = ${value}`;
2508
- }).join(", ");
2509
- return ` ON DUPLICATE KEY UPDATE ${assignments}`;
2601
+ var MySqlProcedureCompiler = class {
2602
+ constructor(services) {
2603
+ this.services = services;
2510
2604
  }
2511
2605
  compileProcedureCall(ast) {
2512
- const ctx = this.createCompilerContext();
2513
- const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
2606
+ const ctx = this.services.createCompilerContext();
2607
+ const qualifiedName = ast.ref.schema ? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}` : this.services.quoteIdentifier(ast.ref.name);
2514
2608
  const prelude = [];
2515
2609
  const callArgs = [];
2516
2610
  const outVars = [];
@@ -2521,35 +2615,97 @@ var MySqlDialect = class extends SqlDialectBase {
2521
2615
  if (!param.value) {
2522
2616
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
2523
2617
  }
2524
- callArgs.push(this.compileOperand(param.value, ctx));
2618
+ callArgs.push(this.services.compileOperand(param.value, ctx));
2525
2619
  return;
2526
2620
  }
2527
2621
  if (param.direction === "inout") {
2528
2622
  if (!param.value) {
2529
2623
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
2530
2624
  }
2531
- prelude.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
2625
+ prelude.push(`SET ${variable} = ${this.services.compileOperand(param.value, ctx)};`);
2532
2626
  }
2533
2627
  callArgs.push(variable);
2534
2628
  outVars.push({ variable, name: param.name });
2535
2629
  });
2536
2630
  const statements = [];
2537
- if (prelude.length) {
2538
- statements.push(...prelude);
2631
+ if (prelude.length) statements.push(...prelude);
2632
+ statements.push(`CALL ${qualifiedName}(${callArgs.join(", ")});`);
2633
+ if (outVars.length) {
2634
+ const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.services.quoteIdentifier(name)}`).join(", ");
2635
+ statements.push(`SELECT ${selectOut};`);
2636
+ }
2637
+ return {
2638
+ sql: statements.join(" "),
2639
+ params: [...ctx.params],
2640
+ outParams: {
2641
+ source: outVars.length ? "lastResultSet" : "none",
2642
+ names: outVars.map((item) => item.name)
2643
+ }
2644
+ };
2645
+ }
2646
+ };
2647
+
2648
+ // src/core/dialect/mysql/upsert.ts
2649
+ var MySqlUpsertStrategy = class {
2650
+ compile(ast, ctx, services) {
2651
+ if (!ast.onConflict) return "";
2652
+ const clause = ast.onConflict;
2653
+ if (clause.action.type === "DoNothing") {
2654
+ const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
2655
+ if (!noOpColumn) {
2656
+ throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one target column.");
2657
+ }
2658
+ const col2 = services.quoteIdentifier(noOpColumn.name);
2659
+ return ` ON DUPLICATE KEY UPDATE ${col2} = ${col2}`;
2660
+ }
2661
+ if (clause.action.where) {
2662
+ throw new Error("MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.");
2539
2663
  }
2540
- statements.push(`CALL ${qualifiedName}(${callArgs.join(", ")});`);
2541
- if (outVars.length) {
2542
- const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
2543
- statements.push(`SELECT ${selectOut};`);
2664
+ if (!clause.action.set.length) {
2665
+ throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.");
2544
2666
  }
2545
- return {
2546
- sql: statements.join(" "),
2547
- params: [...ctx.params],
2548
- outParams: {
2549
- source: outVars.length ? "lastResultSet" : "none",
2550
- names: outVars.map((item) => item.name)
2667
+ const assignments = clause.action.set.map((assignment) => {
2668
+ const target = services.quoteIdentifier(assignment.column.name);
2669
+ const value = services.compileOperand(assignment.value, ctx);
2670
+ return `${target} = ${value}`;
2671
+ }).join(", ");
2672
+ return ` ON DUPLICATE KEY UPDATE ${assignments}`;
2673
+ }
2674
+ };
2675
+
2676
+ // src/core/dialect/mysql/index.ts
2677
+ var MySqlDialect = class extends SqlDialectBase {
2678
+ dialect = "mysql";
2679
+ procedureCompiler;
2680
+ constructor() {
2681
+ super({
2682
+ functionStrategy: new MysqlFunctionStrategy(),
2683
+ upsertStrategy: new MySqlUpsertStrategy()
2684
+ });
2685
+ this.procedureCompiler = new MySqlProcedureCompiler({
2686
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2687
+ createCompilerContext: () => this.createCompilerContext(),
2688
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx)
2689
+ });
2690
+ this.registerExpressionCompiler(
2691
+ "IsDistinctExpression",
2692
+ (node, ctx) => {
2693
+ const left2 = this.compileOperand(node.left, ctx);
2694
+ const right2 = this.compileOperand(node.right, ctx);
2695
+ const spaceship = `${left2} <=> ${right2}`;
2696
+ return node.operator === "IS NOT DISTINCT FROM" ? spaceship : `NOT (${spaceship})`;
2551
2697
  }
2552
- };
2698
+ );
2699
+ }
2700
+ quoteIdentifier(id) {
2701
+ return `\`${id}\``;
2702
+ }
2703
+ compileJsonPath(node) {
2704
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2705
+ return `${column}->'${node.path}'`;
2706
+ }
2707
+ compileProcedureCall(ast) {
2708
+ return this.procedureCompiler.compileProcedureCall(ast);
2553
2709
  }
2554
2710
  };
2555
2711
 
@@ -2690,14 +2846,56 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
2690
2846
  }
2691
2847
  };
2692
2848
 
2849
+ // src/core/dialect/sqlite/returning.ts
2850
+ var SqliteReturningStrategy = class {
2851
+ compileReturning(returning, _ctx, quoteIdentifier) {
2852
+ void _ctx;
2853
+ if (!returning || returning.length === 0) return "";
2854
+ return ` RETURNING ${this.formatReturningColumns(returning, quoteIdentifier)}`;
2855
+ }
2856
+ formatReturningColumns(returning, quoteIdentifier) {
2857
+ return returning.map((column) => {
2858
+ const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
2859
+ return `${quoteIdentifier(column.name)}${alias}`;
2860
+ }).join(", ");
2861
+ }
2862
+ };
2863
+
2864
+ // src/core/dialect/sqlite/upsert.ts
2865
+ var SqliteUpsertStrategy = class {
2866
+ compile(ast, ctx, services) {
2867
+ if (!ast.onConflict) return "";
2868
+ const clause = ast.onConflict;
2869
+ if (clause.target.constraint) {
2870
+ throw new Error("SQLite ON CONFLICT does not support named constraints.");
2871
+ }
2872
+ if (!clause.target.columns.length) {
2873
+ throw new Error("SQLite ON CONFLICT requires conflict columns.");
2874
+ }
2875
+ const columns = clause.target.columns.map((column) => services.quoteIdentifier(column.name)).join(", ");
2876
+ const target = ` ON CONFLICT (${columns})`;
2877
+ if (clause.action.type === "DoNothing") {
2878
+ return `${target} DO NOTHING`;
2879
+ }
2880
+ if (!clause.action.set.length) {
2881
+ throw new Error("SQLite ON CONFLICT DO UPDATE requires at least one assignment.");
2882
+ }
2883
+ const assignments = services.compileUpdateAssignments(clause.action.set, ast.into, ctx);
2884
+ const where = clause.action.where ? ` WHERE ${services.compileExpression(clause.action.where, ctx)}` : "";
2885
+ return `${target} DO UPDATE SET ${assignments}${where}`;
2886
+ }
2887
+ };
2888
+
2693
2889
  // src/core/dialect/sqlite/index.ts
2694
2890
  var SqliteDialect = class extends SqlDialectBase {
2695
2891
  dialect = "sqlite";
2696
- /**
2697
- * Creates a new SqliteDialect instance
2698
- */
2699
2892
  constructor() {
2700
- super(new SqliteFunctionStrategy());
2893
+ super({
2894
+ functionStrategy: new SqliteFunctionStrategy(),
2895
+ returningStrategy: new SqliteReturningStrategy(),
2896
+ upsertStrategy: new SqliteUpsertStrategy(),
2897
+ supportsDmlReturning: true
2898
+ });
2701
2899
  this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
2702
2900
  const left2 = this.compileOperand(node.left, ctx);
2703
2901
  const right2 = this.compileOperand(node.right, ctx);
@@ -2715,61 +2913,17 @@ var SqliteDialect = class extends SqlDialectBase {
2715
2913
  return `(${left2} ${node.operator} ${right2})`;
2716
2914
  });
2717
2915
  }
2718
- /**
2719
- * Quotes an identifier using SQLite double-quote syntax
2720
- * @param id - Identifier to quote
2721
- * @returns Quoted identifier
2722
- */
2723
2916
  quoteIdentifier(id) {
2724
2917
  return `"${id}"`;
2725
2918
  }
2726
- /**
2727
- * Compiles JSON path expression using SQLite syntax
2728
- * @param node - JSON path node
2729
- * @returns SQLite JSON path expression
2730
- */
2731
2919
  compileJsonPath(node) {
2732
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2733
- return `json_extract(${col2}, '${node.path}')`;
2920
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2921
+ return `json_extract(${column}, '${node.path}')`;
2734
2922
  }
2735
2923
  compileQualifiedColumn(column, _table) {
2736
2924
  void _table;
2737
2925
  return this.quoteIdentifier(column.name);
2738
2926
  }
2739
- compileReturning(returning, ctx) {
2740
- void ctx;
2741
- if (!returning || returning.length === 0) return "";
2742
- const columns = this.formatReturningColumns(returning);
2743
- return ` RETURNING ${columns}`;
2744
- }
2745
- formatReturningColumns(returning) {
2746
- return returning.map((column) => {
2747
- const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
2748
- return `${this.quoteIdentifier(column.name)}${alias}`;
2749
- }).join(", ");
2750
- }
2751
- compileUpsertClause(ast, ctx) {
2752
- if (!ast.onConflict) return "";
2753
- const clause = ast.onConflict;
2754
- if (clause.target.constraint) {
2755
- throw new Error("SQLite ON CONFLICT does not support named constraints.");
2756
- }
2757
- this.ensureConflictColumns(clause, "SQLite ON CONFLICT requires conflict columns.");
2758
- const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
2759
- const target = ` ON CONFLICT (${cols})`;
2760
- if (clause.action.type === "DoNothing") {
2761
- return `${target} DO NOTHING`;
2762
- }
2763
- if (!clause.action.set.length) {
2764
- throw new Error("SQLite ON CONFLICT DO UPDATE requires at least one assignment.");
2765
- }
2766
- const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
2767
- const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
2768
- return `${target} DO UPDATE SET ${assignments}${where}`;
2769
- }
2770
- supportsDmlReturningClause() {
2771
- return true;
2772
- }
2773
2927
  };
2774
2928
 
2775
2929
  // src/core/dialect/mssql/functions.ts
@@ -2896,202 +3050,107 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
2896
3050
  }
2897
3051
  };
2898
3052
 
2899
- // src/core/dialect/mssql/index.ts
2900
- var sanitizeVariableSuffix2 = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
2901
- var toProcedureParamReference = (value) => value.startsWith("@") ? value : `@${value}`;
2902
- var SqlServerDialect = class extends SqlDialectBase {
2903
- dialect = "mssql";
2904
- /**
2905
- * Creates a new SqlServerDialect instance
2906
- */
2907
- constructor() {
2908
- super(new MssqlFunctionStrategy());
2909
- }
2910
- /**
2911
- * Quotes an identifier using SQL Server bracket syntax
2912
- * @param id - Identifier to quote
2913
- * @returns Quoted identifier
2914
- */
2915
- quoteIdentifier(id) {
2916
- return `[${id}]`;
2917
- }
2918
- /**
2919
- * Compiles JSON path expression using SQL Server syntax
2920
- * @param node - JSON path node
2921
- * @returns SQL Server JSON path expression
2922
- */
2923
- compileJsonPath(node) {
2924
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2925
- return `JSON_VALUE(${col2}, '${node.path}')`;
3053
+ // src/core/dialect/mssql/output.ts
3054
+ var MssqlOutputStrategy = class {
3055
+ compileReturning(returning, _ctx, quoteIdentifier) {
3056
+ void _ctx;
3057
+ return this.compileOutput(returning, "inserted", quoteIdentifier);
2926
3058
  }
2927
- /**
2928
- * Formats parameter placeholders using SQL Server named parameter syntax
2929
- * @param index - Parameter index
2930
- * @returns Named parameter placeholder
2931
- */
2932
- formatPlaceholder(index) {
2933
- return `@p${index}`;
3059
+ compileOutput(returning, prefix, quoteIdentifier) {
3060
+ if (!returning || returning.length === 0) return "";
3061
+ const columns = returning.map((column) => {
3062
+ const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
3063
+ return `${prefix}.${quoteIdentifier(column.name)}${alias}`;
3064
+ }).join(", ");
3065
+ return ` OUTPUT ${columns}`;
2934
3066
  }
2935
- /**
2936
- * Compiles SELECT query AST to SQL Server SQL
2937
- * @param ast - Query AST
2938
- * @param ctx - Compiler context
2939
- * @returns SQL Server SQL string
2940
- */
2941
- compileSelectAst(ast, ctx) {
2942
- const hasSetOps = !!(ast.setOps && ast.setOps.length);
2943
- const ctes = this.compileCtes(ast, ctx);
2944
- const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
2945
- const baseSelect = this.compileSelectCoreForMssql(baseAst, ctx);
2946
- if (!hasSetOps) {
2947
- return `${ctes}${baseSelect}`;
2948
- }
2949
- const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
2950
- const orderBy = this.compileOrderBy(ast, ctx);
2951
- const pagination = this.compilePagination(ast, orderBy);
2952
- const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
2953
- const tail = pagination || orderBy;
2954
- return `${ctes}${combined}${tail}`;
3067
+ formatReturningColumns(returning, quoteIdentifier) {
3068
+ return returning.map((column) => {
3069
+ const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
3070
+ return `${quoteIdentifier(column.name)}${alias}`;
3071
+ }).join(", ");
2955
3072
  }
2956
- compileDeleteAst(ast, ctx) {
3073
+ };
3074
+
3075
+ // src/core/dialect/mssql/delete-compiler.ts
3076
+ var MssqlDeleteCompiler = class {
3077
+ constructor(services, sources) {
3078
+ this.services = services;
3079
+ this.sources = sources;
3080
+ }
3081
+ output = new MssqlOutputStrategy();
3082
+ compile(ast, ctx) {
2957
3083
  if (ast.using) {
2958
3084
  throw new Error("DELETE ... USING is not supported in the MSSQL dialect; use join() instead.");
2959
3085
  }
2960
- if (ast.from.type !== "Table") {
2961
- throw new Error("DELETE only supports base tables in the MSSQL dialect.");
2962
- }
2963
3086
  const alias = ast.from.alias ?? ast.from.name;
2964
- const target = this.compileTableReference(ast.from);
3087
+ const target = this.sources.compileTableReference(ast.from);
2965
3088
  const joins = JoinCompiler.compileJoins(
2966
3089
  ast.joins,
2967
3090
  ctx,
2968
- this.compileFrom.bind(this),
2969
- this.compileExpression.bind(this)
3091
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
3092
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2970
3093
  );
2971
- const whereClause = this.compileWhere(ast.where, ctx);
2972
- const returning = this.compileOutputClause(ast.returning, "deleted");
2973
- return `DELETE ${this.quoteIdentifier(alias)}${returning} FROM ${target}${joins}${whereClause}`;
2974
- }
2975
- compileUpdateAst(ast, ctx) {
2976
- const target = this.compileTableReference(ast.table);
2977
- const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
2978
- const output = this.compileReturning(ast.returning, ctx);
2979
- const fromClause = ast.from ? ` FROM ${this.compileFrom(ast.from, ctx)}` : "";
2980
- const joins = ast.joins ? ast.joins.map((j) => {
2981
- const table = this.compileFrom(j.table, ctx);
2982
- const cond = this.compileExpression(j.condition, ctx);
2983
- return ` ${j.kind} JOIN ${table} ON ${cond}`;
2984
- }).join("") : "";
2985
- const whereClause = this.compileWhere(ast.where, ctx);
2986
- return `UPDATE ${target} SET ${assignments}${output}${fromClause}${joins}${whereClause}`;
2987
- }
2988
- compileSelectCoreForMssql(ast, ctx) {
2989
- const columns = ast.columns.map((c) => {
2990
- const expr = c.type === "Column" ? `${this.quoteIdentifier(c.table)}.${this.quoteIdentifier(c.name)}` : this.compileOperand(c, ctx);
2991
- if (c.alias) {
2992
- if (c.alias.includes("(")) return c.alias;
2993
- return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
2994
- }
2995
- return expr;
2996
- }).join(", ");
2997
- const distinct = ast.distinct ? "DISTINCT " : "";
2998
- const from = this.compileFrom(ast.from, ctx);
2999
- const joins = ast.joins.map((j) => {
3000
- const table = this.compileFrom(j.table, ctx);
3001
- const cond = this.compileExpression(j.condition, ctx);
3002
- return `${j.kind} JOIN ${table} ON ${cond}`;
3003
- }).join(" ");
3004
- const whereClause = this.compileWhere(ast.where, ctx);
3005
- const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((term) => this.compileOrderingTerm(term, ctx)).join(", ") : "";
3006
- const having = ast.having ? ` HAVING ${this.compileExpression(ast.having, ctx)}` : "";
3007
- const orderBy = this.compileOrderBy(ast, ctx);
3008
- const pagination = this.compilePagination(ast, orderBy);
3009
- if (pagination) {
3010
- return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${pagination}`;
3011
- }
3012
- return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${orderBy}`;
3013
- }
3014
- compileOrderBy(ast, ctx) {
3015
- return OrderByCompiler.compileOrderBy(
3016
- ast,
3017
- (term) => this.compileOrderingTerm(term, ctx),
3018
- this.renderOrderByNulls.bind(this),
3019
- this.renderOrderByCollation.bind(this)
3094
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
3095
+ const returning = this.output.compileOutput(
3096
+ ast.returning,
3097
+ "deleted",
3098
+ (id) => this.services.quoteIdentifier(id)
3020
3099
  );
3100
+ return `DELETE ${this.services.quoteIdentifier(alias)}${returning} FROM ${target}${joins}${where}`;
3021
3101
  }
3022
- compilePagination(ast, orderBy) {
3023
- const hasLimit = ast.limit !== void 0;
3024
- const hasOffset = ast.offset !== void 0;
3025
- if (!hasLimit && !hasOffset) return "";
3026
- const off = ast.offset ?? 0;
3027
- let orderClause = orderBy;
3028
- if (!orderClause) {
3029
- orderClause = ast.distinct && ast.distinct.length > 0 ? " ORDER BY 1" : " ORDER BY (SELECT NULL)";
3030
- }
3031
- let pagination = `${orderClause} OFFSET ${off} ROWS`;
3032
- if (hasLimit) {
3033
- pagination += ` FETCH NEXT ${ast.limit} ROWS ONLY`;
3034
- }
3035
- return pagination;
3036
- }
3037
- supportsDmlReturningClause() {
3038
- return true;
3039
- }
3040
- compileReturning(returning, _ctx) {
3041
- void _ctx;
3042
- return this.compileOutputClause(returning, "inserted");
3043
- }
3044
- compileOutputClause(returning, prefix) {
3045
- if (!returning || returning.length === 0) return "";
3046
- const columns = returning.map((column) => {
3047
- const colName = this.quoteIdentifier(column.name);
3048
- const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
3049
- return `${prefix}.${colName}${alias}`;
3050
- }).join(", ");
3051
- return ` OUTPUT ${columns}`;
3102
+ };
3103
+
3104
+ // src/core/dialect/mssql/insert-compiler.ts
3105
+ var MssqlInsertCompiler = class {
3106
+ constructor(services, sources) {
3107
+ this.services = services;
3108
+ this.sources = sources;
3052
3109
  }
3053
- compileInsertAst(ast, ctx) {
3110
+ compile(ast, ctx) {
3054
3111
  if (!ast.columns.length) {
3055
3112
  throw new Error("INSERT queries must specify columns.");
3056
3113
  }
3057
- if (ast.onConflict) {
3058
- return this.compileMergeInsert(ast, ctx);
3059
- }
3060
- const table = this.compileTableName(ast.into);
3061
- const columnList = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
3062
- const output = this.compileReturning(ast.returning, ctx);
3063
- const source = this.compileInsertValues(ast, ctx);
3064
- return `INSERT INTO ${table} (${columnList})${output} ${source}`;
3114
+ if (ast.onConflict) return this.compileMerge(ast, ctx);
3115
+ const table = this.sources.compileTableName(ast.into);
3116
+ const columns = ast.columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
3117
+ const output = this.services.compileReturning(ast.returning, ctx);
3118
+ const source = this.compileInsertSource(ast, ctx);
3119
+ return `INSERT INTO ${table} (${columns})${output} ${source}`;
3065
3120
  }
3066
- compileMergeInsert(ast, ctx) {
3121
+ compileMerge(ast, ctx) {
3067
3122
  const clause = ast.onConflict;
3068
3123
  if (clause.target.constraint) {
3069
3124
  throw new Error("MSSQL MERGE does not support conflict target by constraint name.");
3070
3125
  }
3071
- this.ensureConflictColumns(clause, "MSSQL MERGE requires conflict columns for the ON clause.");
3072
- const table = this.compileTableName(ast.into);
3073
- const targetRef = this.quoteIdentifier(ast.into.alias ?? ast.into.name);
3074
- const sourceAlias = this.quoteIdentifier("src");
3075
- const sourceColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
3126
+ if (!clause.target.columns.length) {
3127
+ throw new Error("MSSQL MERGE requires conflict columns for the ON clause.");
3128
+ }
3129
+ const table = this.sources.compileTableName(ast.into);
3130
+ const targetRef = this.services.quoteIdentifier(ast.into.alias ?? ast.into.name);
3131
+ const sourceAlias = this.services.quoteIdentifier("src");
3132
+ const sourceColumns = ast.columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
3076
3133
  const usingSource = this.compileMergeUsingSource(ast, ctx);
3077
- const onClause = clause.target.columns.map((column) => `${targetRef}.${this.quoteIdentifier(column.name)} = ${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(" AND ");
3134
+ const onClause = clause.target.columns.map(
3135
+ (column) => `${targetRef}.${this.services.quoteIdentifier(column.name)} = ${sourceAlias}.${this.services.quoteIdentifier(column.name)}`
3136
+ ).join(" AND ");
3078
3137
  const branches = [];
3079
3138
  if (clause.action.type === "DoUpdate") {
3080
3139
  if (!clause.action.set.length) {
3081
3140
  throw new Error("MSSQL MERGE WHEN MATCHED UPDATE requires at least one assignment.");
3082
3141
  }
3083
3142
  const assignments = clause.action.set.map((assignment) => {
3084
- const target = `${targetRef}.${this.quoteIdentifier(assignment.column.name)}`;
3085
- const value = this.compileOperand(assignment.value, ctx);
3143
+ const target = `${targetRef}.${this.services.quoteIdentifier(assignment.column.name)}`;
3144
+ const value = this.services.compileOperand(assignment.value, ctx);
3086
3145
  return `${target} = ${value}`;
3087
3146
  }).join(", ");
3088
- const guard = clause.action.where ? ` AND ${this.compileExpression(clause.action.where, ctx)}` : "";
3147
+ const guard = clause.action.where ? ` AND ${this.services.compileExpression(clause.action.where, ctx)}` : "";
3089
3148
  branches.push(`WHEN MATCHED${guard} THEN UPDATE SET ${assignments}`);
3090
3149
  }
3091
- const insertColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
3092
- const insertValues = ast.columns.map((column) => `${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(", ");
3150
+ const insertColumns = ast.columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
3151
+ const insertValues = ast.columns.map((column) => `${sourceAlias}.${this.services.quoteIdentifier(column.name)}`).join(", ");
3093
3152
  branches.push(`WHEN NOT MATCHED THEN INSERT (${insertColumns}) VALUES (${insertValues})`);
3094
- const output = this.compileReturning(ast.returning, ctx);
3153
+ const output = this.services.compileReturning(ast.returning, ctx);
3095
3154
  return `MERGE INTO ${table} USING ${usingSource} AS ${sourceAlias} (${sourceColumns}) ON ${onClause} ${branches.join(" ")}${output}`;
3096
3155
  }
3097
3156
  compileMergeUsingSource(ast, ctx) {
@@ -3099,38 +3158,146 @@ var SqlServerDialect = class extends SqlDialectBase {
3099
3158
  if (!ast.source.rows.length) {
3100
3159
  throw new Error("INSERT ... VALUES requires at least one row.");
3101
3160
  }
3102
- const rows = ast.source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
3161
+ const rows = ast.source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
3103
3162
  return `(VALUES ${rows})`;
3104
3163
  }
3105
- const normalized = this.normalizeSelectAst(ast.source.query);
3106
- const selectSql = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
3164
+ const normalized = this.services.normalizeSelectAst(ast.source.query);
3165
+ const selectSql = this.sources.stripTrailingSemicolon(
3166
+ this.services.compileSelectAst(normalized, ctx)
3167
+ );
3107
3168
  return `(${selectSql})`;
3108
3169
  }
3109
- compileInsertValues(ast, ctx) {
3110
- const source = ast.source;
3111
- if (source.type === "InsertValues") {
3112
- if (!source.rows.length) {
3170
+ compileInsertSource(ast, ctx) {
3171
+ if (ast.source.type === "InsertValues") {
3172
+ if (!ast.source.rows.length) {
3113
3173
  throw new Error("INSERT ... VALUES requires at least one row.");
3114
3174
  }
3115
- const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
3175
+ const values = ast.source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
3116
3176
  return `VALUES ${values}`;
3117
3177
  }
3118
- const normalized = this.normalizeSelectAst(source.query);
3119
- return this.compileSelectAst(normalized, ctx).trim();
3178
+ const normalized = this.services.normalizeSelectAst(ast.source.query);
3179
+ return this.services.compileSelectAst(normalized, ctx).trim();
3180
+ }
3181
+ };
3182
+
3183
+ // src/core/dialect/mssql/select-compiler.ts
3184
+ var MssqlSelectCompiler = class {
3185
+ constructor(services, sources) {
3186
+ this.services = services;
3187
+ this.sources = sources;
3188
+ }
3189
+ compile(ast, ctx) {
3190
+ const hasSetOps = !!(ast.setOps && ast.setOps.length);
3191
+ const ctes = this.compileCtes(ast, ctx);
3192
+ const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
3193
+ const baseSelect = this.compileCore(baseAst, ctx);
3194
+ if (!hasSetOps) return `${ctes}${baseSelect}`;
3195
+ const compound = ast.setOps.map((op) => `${op.operator} ${this.sources.wrapSetOperand(this.services.compileSelectAst(op.query, ctx))}`).join(" ");
3196
+ const orderBy = this.compileOrderBy(ast, ctx);
3197
+ const pagination = this.compilePagination(ast, orderBy);
3198
+ const combined = `${this.sources.wrapSetOperand(baseSelect)} ${compound}`;
3199
+ return `${ctes}${combined}${pagination || orderBy}`;
3200
+ }
3201
+ compileCore(ast, ctx) {
3202
+ const columns = ast.columns.map((column) => {
3203
+ const expr = column.type === "Column" ? `${this.services.quoteIdentifier(column.table)}.${this.services.quoteIdentifier(column.name)}` : this.services.compileOperand(column, ctx);
3204
+ if (!column.alias) return expr;
3205
+ if (column.alias.includes("(")) return column.alias;
3206
+ return `${expr} AS ${this.services.quoteIdentifier(column.alias)}`;
3207
+ }).join(", ");
3208
+ const distinct = ast.distinct ? "DISTINCT " : "";
3209
+ const from = this.sources.compileFrom(ast.from, ctx);
3210
+ const joins = ast.joins.map((join) => {
3211
+ const table = this.sources.compileFrom(join.table, ctx);
3212
+ const condition = this.services.compileExpression(join.condition, ctx);
3213
+ return `${join.kind} JOIN ${table} ON ${condition}`;
3214
+ }).join(" ");
3215
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
3216
+ const groupBy = ast.groupBy && ast.groupBy.length > 0 ? ` GROUP BY ${ast.groupBy.map((term) => this.services.compileOrderingTerm(term, ctx)).join(", ")}` : "";
3217
+ const having = ast.having ? ` HAVING ${this.services.compileExpression(ast.having, ctx)}` : "";
3218
+ const orderBy = this.compileOrderBy(ast, ctx);
3219
+ const pagination = this.compilePagination(ast, orderBy);
3220
+ if (pagination) {
3221
+ return `SELECT ${distinct}${columns} FROM ${from}${joins ? ` ${joins}` : ""}${where}${groupBy}${having}${pagination}`;
3222
+ }
3223
+ return `SELECT ${distinct}${columns} FROM ${from}${joins ? ` ${joins}` : ""}${where}${groupBy}${having}${orderBy}`;
3224
+ }
3225
+ compileOrderBy(ast, ctx) {
3226
+ return OrderByCompiler.compileOrderBy(
3227
+ ast,
3228
+ (term) => this.services.compileOrderingTerm(term, ctx),
3229
+ (order) => this.services.renderOrderByNulls(order),
3230
+ (order) => this.services.renderOrderByCollation(order)
3231
+ );
3232
+ }
3233
+ compilePagination(ast, orderBy) {
3234
+ const hasLimit = ast.limit !== void 0;
3235
+ const hasOffset = ast.offset !== void 0;
3236
+ if (!hasLimit && !hasOffset) return "";
3237
+ const offset = ast.offset ?? 0;
3238
+ let orderClause = orderBy;
3239
+ if (!orderClause) {
3240
+ orderClause = ast.distinct && ast.distinct.length > 0 ? " ORDER BY 1" : " ORDER BY (SELECT NULL)";
3241
+ }
3242
+ let pagination = `${orderClause} OFFSET ${offset} ROWS`;
3243
+ if (hasLimit) pagination += ` FETCH NEXT ${ast.limit} ROWS ONLY`;
3244
+ return pagination;
3120
3245
  }
3121
3246
  compileCtes(ast, ctx) {
3122
3247
  if (!ast.ctes || ast.ctes.length === 0) return "";
3123
- const defs = ast.ctes.map((cte) => {
3124
- const name = this.quoteIdentifier(cte.name);
3125
- const cols = cte.columns ? `(${cte.columns.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
3126
- const query = this.compileSelectAst(this.normalizeSelectAst(cte.query), ctx).trim().replace(/;$/, "");
3127
- return `${name}${cols} AS (${query})`;
3248
+ const definitions = ast.ctes.map((cte) => {
3249
+ const name = this.services.quoteIdentifier(cte.name);
3250
+ const columns = cte.columns ? `(${cte.columns.map((column) => this.services.quoteIdentifier(column)).join(", ")})` : "";
3251
+ const query = this.sources.stripTrailingSemicolon(
3252
+ this.services.compileSelectAst(this.services.normalizeSelectAst(cte.query), ctx)
3253
+ );
3254
+ return `${name}${columns} AS (${query})`;
3128
3255
  }).join(", ");
3129
- return `WITH ${defs} `;
3256
+ return `WITH ${definitions} `;
3257
+ }
3258
+ };
3259
+
3260
+ // src/core/dialect/mssql/update-compiler.ts
3261
+ var MssqlUpdateCompiler = class {
3262
+ constructor(services, sources) {
3263
+ this.services = services;
3264
+ this.sources = sources;
3265
+ this.standardUpdate = new StandardUpdateCompiler(services, sources);
3266
+ }
3267
+ standardUpdate;
3268
+ compile(ast, ctx) {
3269
+ const target = this.sources.compileTableReference(ast.table);
3270
+ const assignments = this.standardUpdate.compileAssignments(ast.set, ast.table, ctx);
3271
+ const output = this.services.compileReturning(ast.returning, ctx);
3272
+ const from = ast.from ? ` FROM ${this.sources.compileFrom(ast.from, ctx)}` : "";
3273
+ const joins = ast.joins ? ast.joins.map((join) => {
3274
+ const table = this.sources.compileFrom(join.table, ctx);
3275
+ const condition = this.services.compileExpression(join.condition, ctx);
3276
+ return ` ${join.kind} JOIN ${table} ON ${condition}`;
3277
+ }).join("") : "";
3278
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
3279
+ return `UPDATE ${target} SET ${assignments}${output}${from}${joins}${where}`;
3280
+ }
3281
+ };
3282
+
3283
+ // src/core/dialect/mssql/compiler-factory.ts
3284
+ var createMssqlCompilerSet = ({ services, sources }) => ({
3285
+ select: new MssqlSelectCompiler(services, sources),
3286
+ insert: new MssqlInsertCompiler(services, sources),
3287
+ update: new MssqlUpdateCompiler(services, sources),
3288
+ delete: new MssqlDeleteCompiler(services, sources)
3289
+ });
3290
+
3291
+ // src/core/dialect/mssql/procedure-compiler.ts
3292
+ var sanitizeVariableSuffix2 = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
3293
+ var toProcedureParamReference = (value) => value.startsWith("@") ? value : `@${value}`;
3294
+ var MssqlProcedureCompiler = class {
3295
+ constructor(services) {
3296
+ this.services = services;
3130
3297
  }
3131
3298
  compileProcedureCall(ast) {
3132
- const ctx = this.createCompilerContext();
3133
- const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
3299
+ const ctx = this.services.createCompilerContext();
3300
+ const qualifiedName = ast.ref.schema ? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}` : this.services.quoteIdentifier(ast.ref.name);
3134
3301
  const declarations = [];
3135
3302
  const assignments = [];
3136
3303
  const execArgs = [];
@@ -3141,7 +3308,7 @@ var SqlServerDialect = class extends SqlDialectBase {
3141
3308
  if (!param.value) {
3142
3309
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
3143
3310
  }
3144
- execArgs.push(`${targetParam} = ${this.compileOperand(param.value, ctx)}`);
3311
+ execArgs.push(`${targetParam} = ${this.services.compileOperand(param.value, ctx)}`);
3145
3312
  return;
3146
3313
  }
3147
3314
  if (!param.dbType) {
@@ -3156,7 +3323,7 @@ var SqlServerDialect = class extends SqlDialectBase {
3156
3323
  if (!param.value) {
3157
3324
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
3158
3325
  }
3159
- assignments.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
3326
+ assignments.push(`SET ${variable} = ${this.services.compileOperand(param.value, ctx)};`);
3160
3327
  }
3161
3328
  execArgs.push(`${targetParam} = ${variable} OUTPUT`);
3162
3329
  outVars.push({ variable, name: param.name });
@@ -3167,7 +3334,7 @@ var SqlServerDialect = class extends SqlDialectBase {
3167
3334
  const argsSql = execArgs.length ? ` ${execArgs.join(", ")}` : "";
3168
3335
  statements.push(`EXEC ${qualifiedName}${argsSql};`);
3169
3336
  if (outVars.length) {
3170
- const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
3337
+ const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.services.quoteIdentifier(name)}`).join(", ");
3171
3338
  statements.push(`SELECT ${selectOut};`);
3172
3339
  }
3173
3340
  return {
@@ -3181,6 +3348,38 @@ var SqlServerDialect = class extends SqlDialectBase {
3181
3348
  }
3182
3349
  };
3183
3350
 
3351
+ // src/core/dialect/mssql/index.ts
3352
+ var SqlServerDialect = class extends SqlDialectBase {
3353
+ dialect = "mssql";
3354
+ procedureCompiler;
3355
+ constructor() {
3356
+ super({
3357
+ functionStrategy: new MssqlFunctionStrategy(),
3358
+ returningStrategy: new MssqlOutputStrategy(),
3359
+ compilerFactory: createMssqlCompilerSet,
3360
+ supportsDmlReturning: true
3361
+ });
3362
+ this.procedureCompiler = new MssqlProcedureCompiler({
3363
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
3364
+ createCompilerContext: () => this.createCompilerContext(),
3365
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx)
3366
+ });
3367
+ }
3368
+ quoteIdentifier(id) {
3369
+ return `[${id}]`;
3370
+ }
3371
+ compileJsonPath(node) {
3372
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
3373
+ return `JSON_VALUE(${column}, '${node.path}')`;
3374
+ }
3375
+ formatPlaceholder(index) {
3376
+ return `@p${index}`;
3377
+ }
3378
+ compileProcedureCall(ast) {
3379
+ return this.procedureCompiler.compileProcedureCall(ast);
3380
+ }
3381
+ };
3382
+
3184
3383
  // src/core/dialect/dialect-factory.ts
3185
3384
  var DialectFactory = class {
3186
3385
  static registry = /* @__PURE__ */ new Map();
@@ -21658,13 +21857,26 @@ export {
21658
21857
  MorphMany,
21659
21858
  MorphOne,
21660
21859
  MorphTo,
21860
+ MssqlDeleteCompiler,
21861
+ MssqlInsertCompiler,
21862
+ MssqlOutputStrategy,
21863
+ MssqlProcedureCompiler,
21864
+ MssqlSelectCompiler,
21865
+ MssqlUpdateCompiler,
21661
21866
  MySqlDialect,
21867
+ MySqlProcedureCompiler,
21868
+ MySqlUpsertStrategy,
21662
21869
  NestedSetStrategy,
21870
+ NoReturningStrategy,
21871
+ NoUpsertStrategy,
21663
21872
  Orm,
21664
21873
  OrmSession,
21665
21874
  Pattern,
21666
21875
  Pool,
21667
21876
  PostgresDialect,
21877
+ PostgresProcedureCompiler,
21878
+ PostgresReturningStrategy,
21879
+ PostgresUpsertStrategy,
21668
21880
  PrimaryKey,
21669
21881
  ProcedureCallBuilder,
21670
21882
  PrototypeMaterializationStrategy,
@@ -21673,8 +21885,19 @@ export {
21673
21885
  RelationKinds,
21674
21886
  STANDARD_COLUMN_TYPES,
21675
21887
  SelectQueryBuilder,
21888
+ SqlDialectBase,
21676
21889
  SqlServerDialect,
21677
21890
  SqliteDialect,
21891
+ SqliteReturningStrategy,
21892
+ SqliteUpsertStrategy,
21893
+ StandardDeleteCompiler,
21894
+ StandardInsertCompiler,
21895
+ StandardLimitOffsetPagination,
21896
+ StandardReturningStrategy,
21897
+ StandardSelectCompiler,
21898
+ StandardSqlSourceCompiler,
21899
+ StandardTableFunctionStrategy,
21900
+ StandardUpdateCompiler,
21678
21901
  StringTypeStrategy,
21679
21902
  TagIndex,
21680
21903
  Title,
@@ -21761,6 +21984,7 @@ export {
21761
21984
  createEntityFromRow,
21762
21985
  createEntityProxy,
21763
21986
  createExecutorFromQueryRunner,
21987
+ createMssqlCompilerSet,
21764
21988
  createMssqlExecutor,
21765
21989
  createMysqlExecutor,
21766
21990
  createPooledExecutorFactory,