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.cjs CHANGED
@@ -92,13 +92,26 @@ __export(index_exports, {
92
92
  MorphMany: () => MorphMany,
93
93
  MorphOne: () => MorphOne,
94
94
  MorphTo: () => MorphTo,
95
+ MssqlDeleteCompiler: () => MssqlDeleteCompiler,
96
+ MssqlInsertCompiler: () => MssqlInsertCompiler,
97
+ MssqlOutputStrategy: () => MssqlOutputStrategy,
98
+ MssqlProcedureCompiler: () => MssqlProcedureCompiler,
99
+ MssqlSelectCompiler: () => MssqlSelectCompiler,
100
+ MssqlUpdateCompiler: () => MssqlUpdateCompiler,
95
101
  MySqlDialect: () => MySqlDialect,
102
+ MySqlProcedureCompiler: () => MySqlProcedureCompiler,
103
+ MySqlUpsertStrategy: () => MySqlUpsertStrategy,
96
104
  NestedSetStrategy: () => NestedSetStrategy,
105
+ NoReturningStrategy: () => NoReturningStrategy,
106
+ NoUpsertStrategy: () => NoUpsertStrategy,
97
107
  Orm: () => Orm,
98
108
  OrmSession: () => OrmSession,
99
109
  Pattern: () => Pattern,
100
110
  Pool: () => Pool,
101
111
  PostgresDialect: () => PostgresDialect,
112
+ PostgresProcedureCompiler: () => PostgresProcedureCompiler,
113
+ PostgresReturningStrategy: () => PostgresReturningStrategy,
114
+ PostgresUpsertStrategy: () => PostgresUpsertStrategy,
102
115
  PrimaryKey: () => PrimaryKey,
103
116
  ProcedureCallBuilder: () => ProcedureCallBuilder,
104
117
  PrototypeMaterializationStrategy: () => PrototypeMaterializationStrategy,
@@ -107,8 +120,19 @@ __export(index_exports, {
107
120
  RelationKinds: () => RelationKinds,
108
121
  STANDARD_COLUMN_TYPES: () => STANDARD_COLUMN_TYPES,
109
122
  SelectQueryBuilder: () => SelectQueryBuilder,
123
+ SqlDialectBase: () => SqlDialectBase,
110
124
  SqlServerDialect: () => SqlServerDialect,
111
125
  SqliteDialect: () => SqliteDialect,
126
+ SqliteReturningStrategy: () => SqliteReturningStrategy,
127
+ SqliteUpsertStrategy: () => SqliteUpsertStrategy,
128
+ StandardDeleteCompiler: () => StandardDeleteCompiler,
129
+ StandardInsertCompiler: () => StandardInsertCompiler,
130
+ StandardLimitOffsetPagination: () => StandardLimitOffsetPagination,
131
+ StandardReturningStrategy: () => StandardReturningStrategy,
132
+ StandardSelectCompiler: () => StandardSelectCompiler,
133
+ StandardSqlSourceCompiler: () => StandardSqlSourceCompiler,
134
+ StandardTableFunctionStrategy: () => StandardTableFunctionStrategy,
135
+ StandardUpdateCompiler: () => StandardUpdateCompiler,
112
136
  StringTypeStrategy: () => StringTypeStrategy,
113
137
  TagIndex: () => TagIndex,
114
138
  Title: () => Title,
@@ -195,6 +219,7 @@ __export(index_exports, {
195
219
  createEntityFromRow: () => createEntityFromRow,
196
220
  createEntityProxy: () => createEntityProxy,
197
221
  createExecutorFromQueryRunner: () => createExecutorFromQueryRunner,
222
+ createMssqlCompilerSet: () => createMssqlCompilerSet,
198
223
  createMssqlExecutor: () => createMssqlExecutor,
199
224
  createMysqlExecutor: () => createMysqlExecutor,
200
225
  createPooledExecutorFactory: () => createPooledExecutorFactory,
@@ -2132,6 +2157,57 @@ var DialectBase = class _DialectBase {
2132
2157
  }
2133
2158
  };
2134
2159
 
2160
+ // src/core/dialect/base/pagination-strategy.ts
2161
+ var StandardLimitOffsetPagination = class {
2162
+ /**
2163
+ * Compiles LIMIT/OFFSET pagination clause.
2164
+ * @param limit - The maximum number of rows to return.
2165
+ * @param offset - The number of rows to skip.
2166
+ * @returns SQL pagination clause with LIMIT and/or OFFSET.
2167
+ */
2168
+ compilePagination(limit, offset) {
2169
+ const parts = [];
2170
+ if (limit !== void 0) parts.push(`LIMIT ${limit}`);
2171
+ if (offset !== void 0) parts.push(`OFFSET ${offset}`);
2172
+ return parts.length ? ` ${parts.join(" ")}` : "";
2173
+ }
2174
+ };
2175
+
2176
+ // src/core/dialect/base/returning-strategy.ts
2177
+ var NoReturningStrategy = class {
2178
+ compileReturning(returning, _ctx, _quoteIdentifier) {
2179
+ void _ctx;
2180
+ void _quoteIdentifier;
2181
+ if (!returning || returning.length === 0) return "";
2182
+ throw new Error("RETURNING is not supported by this dialect.");
2183
+ }
2184
+ formatReturningColumns(returning, quoteIdentifier) {
2185
+ return returning.map((column) => {
2186
+ const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
2187
+ const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
2188
+ return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
2189
+ }).join(", ");
2190
+ }
2191
+ };
2192
+ var StandardReturningStrategy = class extends NoReturningStrategy {
2193
+ compileReturning(returning, _ctx, quoteIdentifier) {
2194
+ void _ctx;
2195
+ if (!returning || returning.length === 0) return "";
2196
+ return ` RETURNING ${this.formatReturningColumns(returning, quoteIdentifier)}`;
2197
+ }
2198
+ };
2199
+
2200
+ // src/core/dialect/base/upsert-strategy.ts
2201
+ var NoUpsertStrategy = class {
2202
+ compile(ast, _ctx, services) {
2203
+ void _ctx;
2204
+ if (!ast.onConflict) return "";
2205
+ throw new Error(
2206
+ `UPSERT/ON CONFLICT is not supported by dialect "${services.getDialectName()}".`
2207
+ );
2208
+ }
2209
+ };
2210
+
2135
2211
  // src/core/dialect/base/function-table-formatter.ts
2136
2212
  var FunctionTableFormatter = class {
2137
2213
  static format(fn9, ctx, formatter) {
@@ -2168,19 +2244,71 @@ var FunctionTableFormatter = class {
2168
2244
  }
2169
2245
  };
2170
2246
 
2171
- // src/core/dialect/base/pagination-strategy.ts
2172
- var StandardLimitOffsetPagination = class {
2173
- /**
2174
- * Compiles LIMIT/OFFSET pagination clause.
2175
- * @param limit - The maximum number of rows to return.
2176
- * @param offset - The number of rows to skip.
2177
- * @returns SQL pagination clause with LIMIT and/or OFFSET.
2178
- */
2179
- compilePagination(limit, offset) {
2180
- const parts = [];
2181
- if (limit !== void 0) parts.push(`LIMIT ${limit}`);
2182
- if (offset !== void 0) parts.push(`OFFSET ${offset}`);
2183
- return parts.length ? ` ${parts.join(" ")}` : "";
2247
+ // src/core/dialect/base/standard-sql-source-compiler.ts
2248
+ var StandardSqlSourceCompiler = class {
2249
+ constructor(services) {
2250
+ this.services = services;
2251
+ }
2252
+ compileFrom(source, ctx) {
2253
+ if (source.type === "FunctionTable") return this.compileFunctionTable(source, ctx);
2254
+ if (source.type === "DerivedTable") return this.compileDerivedTable(source, ctx);
2255
+ return this.compileTableSource(source);
2256
+ }
2257
+ compileFunctionTable(fn9, ctx) {
2258
+ const key = fn9.key ?? fn9.name;
2259
+ if (ctx) {
2260
+ const renderer = this.services.getTableFunctionStrategy().getRenderer(key);
2261
+ if (renderer) {
2262
+ const compiledArgs = (fn9.args ?? []).map((arg) => this.services.compileOperand(arg, ctx));
2263
+ return renderer({
2264
+ node: fn9,
2265
+ compiledArgs,
2266
+ compileOperand: (operand) => this.services.compileOperand(operand, ctx),
2267
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id)
2268
+ });
2269
+ }
2270
+ if (fn9.key) {
2271
+ throw new Error(
2272
+ `Table function "${key}" is not supported by dialect "${this.services.getDialectName()}".`
2273
+ );
2274
+ }
2275
+ }
2276
+ return FunctionTableFormatter.format(fn9, ctx, {
2277
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id),
2278
+ compileOperand: (node, compilerContext) => this.services.compileOperand(node, compilerContext)
2279
+ });
2280
+ }
2281
+ compileDerivedTable(table, ctx) {
2282
+ if (!table.alias) throw new Error("Derived tables must have an alias.");
2283
+ if (!ctx) throw new Error("Derived table compilation requires a compiler context.");
2284
+ const normalized = this.services.normalizeSelectAst(table.query);
2285
+ const subquery = this.services.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
2286
+ const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((column) => this.services.quoteIdentifier(column)).join(", ")})` : "";
2287
+ return `(${subquery}) AS ${this.services.quoteIdentifier(table.alias)}${columns}`;
2288
+ }
2289
+ compileTableSource(table) {
2290
+ if (table.type === "FunctionTable") return this.compileFunctionTable(table);
2291
+ if (table.type === "DerivedTable") {
2292
+ throw new Error("Derived table compilation requires a compiler context.");
2293
+ }
2294
+ const base = this.compileTableName(table);
2295
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
2296
+ }
2297
+ compileTableName(table) {
2298
+ if (table.schema) {
2299
+ return `${this.services.quoteIdentifier(table.schema)}.${this.services.quoteIdentifier(table.name)}`;
2300
+ }
2301
+ return this.services.quoteIdentifier(table.name);
2302
+ }
2303
+ compileTableReference(table) {
2304
+ const base = this.compileTableName(table);
2305
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
2306
+ }
2307
+ stripTrailingSemicolon(sql) {
2308
+ return sql.trim().replace(/;$/, "");
2309
+ }
2310
+ wrapSetOperand(sql) {
2311
+ return `(${this.stripTrailingSemicolon(sql)})`;
2184
2312
  }
2185
2313
  };
2186
2314
 
@@ -2210,34 +2338,6 @@ var CteCompiler = class {
2210
2338
  }
2211
2339
  };
2212
2340
 
2213
- // src/core/dialect/base/returning-strategy.ts
2214
- var NoReturningStrategy = class {
2215
- /**
2216
- * Throws an error as RETURNING is not supported.
2217
- * @param returning - Columns to return (causes error if non-empty).
2218
- * @param _ctx - Compiler context (unused).
2219
- * @throws Error indicating RETURNING is not supported.
2220
- */
2221
- compileReturning(returning, _ctx) {
2222
- void _ctx;
2223
- if (!returning || returning.length === 0) return "";
2224
- throw new Error("RETURNING is not supported by this dialect.");
2225
- }
2226
- /**
2227
- * Formats column names for RETURNING clause.
2228
- * @param returning - Columns to format.
2229
- * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
2230
- * @returns Simple comma-separated column names.
2231
- */
2232
- formatReturningColumns(returning, quoteIdentifier) {
2233
- return returning.map((column) => {
2234
- const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
2235
- const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
2236
- return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
2237
- }).join(", ");
2238
- }
2239
- };
2240
-
2241
2341
  // src/core/dialect/base/join-compiler.ts
2242
2342
  var JoinCompiler = class {
2243
2343
  static compileJoins(joins, ctx, compileFrom, compileExpression) {
@@ -2288,108 +2388,254 @@ var OrderByCompiler = class {
2288
2388
  }
2289
2389
  };
2290
2390
 
2291
- // src/core/dialect/base/sql-dialect.ts
2292
- var SqlDialectBase = class extends DialectBase {
2293
- paginationStrategy = new StandardLimitOffsetPagination();
2294
- returningStrategy = new NoReturningStrategy();
2295
- compileSelectAst(ast, ctx) {
2391
+ // src/core/dialect/base/standard-select-compiler.ts
2392
+ var StandardSelectCompiler = class {
2393
+ constructor(services, sources) {
2394
+ this.services = services;
2395
+ this.sources = sources;
2396
+ }
2397
+ compile(ast, ctx) {
2296
2398
  const hasSetOps = !!(ast.setOps && ast.setOps.length);
2297
2399
  const ctes = CteCompiler.compileCtes(
2298
2400
  ast,
2299
2401
  ctx,
2300
- this.quoteIdentifier.bind(this),
2301
- this.compileSelectAst.bind(this),
2302
- this.normalizeSelectAst.bind(this),
2303
- this.stripTrailingSemicolon.bind(this)
2402
+ (id) => this.services.quoteIdentifier(id),
2403
+ (query, compilerContext) => this.services.compileSelectAst(query, compilerContext),
2404
+ (query) => this.services.normalizeSelectAst(query),
2405
+ (sql) => this.sources.stripTrailingSemicolon(sql)
2304
2406
  );
2305
2407
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
2306
- const baseSelect = this.compileSelectCore(baseAst, ctx);
2408
+ const baseSelect = this.compileCore(baseAst, ctx);
2307
2409
  if (!hasSetOps) return `${ctes}${baseSelect}`;
2308
- return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
2410
+ const compound = ast.setOps.map((op) => `${op.operator} ${this.sources.wrapSetOperand(this.services.compileSelectAst(op.query, ctx))}`).join(" ");
2411
+ const orderBy = this.compileOrderBy(ast, ctx);
2412
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
2413
+ const combined = `${this.sources.wrapSetOperand(baseSelect)} ${compound}`;
2414
+ return `${ctes}${combined}${orderBy}${pagination}`;
2415
+ }
2416
+ compileCore(ast, ctx) {
2417
+ const columns = this.compileColumns(ast, ctx);
2418
+ const from = this.sources.compileFrom(ast.from, ctx);
2419
+ const joins = JoinCompiler.compileJoins(
2420
+ ast.joins,
2421
+ ctx,
2422
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2423
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2424
+ );
2425
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2426
+ const groupBy = GroupByCompiler.compileGroupBy(
2427
+ ast,
2428
+ (term) => this.services.compileOrderingTerm(term, ctx)
2429
+ );
2430
+ const having = ast.having ? ` HAVING ${this.services.compileExpression(ast.having, ctx)}` : "";
2431
+ const orderBy = this.compileOrderBy(ast, ctx);
2432
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
2433
+ return `SELECT ${ast.distinct ? "DISTINCT " : ""}${columns} FROM ${from}${joins}${where}${groupBy}${having}${orderBy}${pagination}`;
2309
2434
  }
2310
- compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
2311
- const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
2312
- const orderBy = OrderByCompiler.compileOrderBy(
2435
+ compileColumns(ast, ctx) {
2436
+ if (!ast.columns || ast.columns.length === 0) return "*";
2437
+ return ast.columns.map((column) => {
2438
+ const expr = this.services.compileOperand(column, ctx);
2439
+ if (!column.alias) return expr;
2440
+ if (column.alias.includes("(")) return column.alias;
2441
+ return `${expr} AS ${this.services.quoteIdentifier(column.alias)}`;
2442
+ }).join(", ");
2443
+ }
2444
+ compileOrderBy(ast, ctx) {
2445
+ return OrderByCompiler.compileOrderBy(
2313
2446
  ast,
2314
- (term) => this.compileOrderingTerm(term, ctx),
2315
- this.renderOrderByNulls.bind(this),
2316
- this.renderOrderByCollation.bind(this)
2447
+ (term) => this.services.compileOrderingTerm(term, ctx),
2448
+ (order) => this.services.renderOrderByNulls(order),
2449
+ (order) => this.services.renderOrderByCollation(order)
2317
2450
  );
2318
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
2319
- const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
2320
- return `${ctes}${combined}${orderBy}${pagination}`;
2321
2451
  }
2322
- compileInsertAst(ast, ctx) {
2452
+ };
2453
+
2454
+ // src/core/dialect/base/standard-insert-compiler.ts
2455
+ var StandardInsertCompiler = class {
2456
+ constructor(services, sources) {
2457
+ this.services = services;
2458
+ this.sources = sources;
2459
+ }
2460
+ compile(ast, ctx) {
2323
2461
  if (!ast.columns.length) {
2324
2462
  throw new Error("INSERT queries must specify columns.");
2325
2463
  }
2326
- const table = this.compileTableName(ast.into);
2327
- const columnList = this.compileInsertColumnList(ast.columns);
2328
- const source = this.compileInsertSource(ast.source, ctx);
2329
- const upsert = this.compileUpsertClause(ast, ctx);
2330
- const returning = this.compileReturning(ast.returning, ctx);
2464
+ const table = this.sources.compileTableName(ast.into);
2465
+ const columnList = this.compileColumnList(ast.columns);
2466
+ const source = this.compileSource(ast.source, ctx);
2467
+ const upsert = this.services.compileUpsertClause(ast, ctx);
2468
+ const returning = this.services.compileReturning(ast.returning, ctx);
2331
2469
  return `INSERT INTO ${table} (${columnList}) ${source}${upsert}${returning}`;
2332
2470
  }
2333
- compileUpsertClause(ast, _ctx) {
2334
- void _ctx;
2335
- if (!ast.onConflict) return "";
2336
- throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
2337
- }
2338
- compileReturning(returning, ctx) {
2339
- return this.returningStrategy.compileReturning(returning, ctx);
2340
- }
2341
- compileInsertSource(source, ctx) {
2471
+ compileSource(source, ctx) {
2342
2472
  if (source.type === "InsertValues") {
2343
2473
  if (!source.rows.length) {
2344
2474
  throw new Error("INSERT ... VALUES requires at least one row.");
2345
2475
  }
2346
- const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
2476
+ const values = source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
2347
2477
  return `VALUES ${values}`;
2348
2478
  }
2349
- const normalized = this.normalizeSelectAst(source.query);
2350
- return this.compileSelectAst(normalized, ctx).trim();
2479
+ const normalized = this.services.normalizeSelectAst(source.query);
2480
+ return this.services.compileSelectAst(normalized, ctx).trim();
2351
2481
  }
2352
- compileInsertColumnList(columns) {
2353
- return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
2482
+ compileColumnList(columns) {
2483
+ return columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
2354
2484
  }
2355
2485
  ensureConflictColumns(clause, message) {
2356
2486
  if (!clause.target.columns.length) throw new Error(message);
2357
2487
  }
2358
- compileSelectCore(ast, ctx) {
2359
- const columns = this.compileSelectColumns(ast, ctx);
2360
- const from = this.compileFrom(ast.from, ctx);
2488
+ };
2489
+
2490
+ // src/core/dialect/base/standard-update-compiler.ts
2491
+ var StandardUpdateCompiler = class {
2492
+ constructor(services, sources) {
2493
+ this.services = services;
2494
+ this.sources = sources;
2495
+ }
2496
+ compile(ast, ctx) {
2497
+ const target = this.sources.compileTableReference(ast.table);
2498
+ const assignments = this.compileAssignments(ast.set, ast.table, ctx);
2499
+ const from = this.compileFromClause(ast, ctx);
2500
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2501
+ const returning = this.services.compileReturning(ast.returning, ctx);
2502
+ return `UPDATE ${target} SET ${assignments}${from}${where}${returning}`;
2503
+ }
2504
+ compileAssignments(assignments, table, ctx) {
2505
+ return assignments.map((assignment) => {
2506
+ const target = this.services.compileSetTarget(assignment.column, table);
2507
+ const value = this.services.compileOperand(assignment.value, ctx);
2508
+ return `${target} = ${value}`;
2509
+ }).join(", ");
2510
+ }
2511
+ compileFromClause(ast, ctx) {
2512
+ if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2513
+ if (!ast.from) {
2514
+ throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2515
+ }
2516
+ const from = this.sources.compileFrom(ast.from, ctx);
2361
2517
  const joins = JoinCompiler.compileJoins(
2362
2518
  ast.joins,
2363
2519
  ctx,
2364
- this.compileFrom.bind(this),
2365
- this.compileExpression.bind(this)
2520
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2521
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2366
2522
  );
2367
- const whereClause = this.compileWhere(ast.where, ctx);
2368
- const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
2369
- const having = this.compileHaving(ast, ctx);
2370
- const orderBy = OrderByCompiler.compileOrderBy(
2371
- ast,
2372
- (term) => this.compileOrderingTerm(term, ctx),
2373
- this.renderOrderByNulls.bind(this),
2374
- this.renderOrderByCollation.bind(this)
2523
+ return ` FROM ${from}${joins}`;
2524
+ }
2525
+ };
2526
+
2527
+ // src/core/dialect/base/standard-delete-compiler.ts
2528
+ var StandardDeleteCompiler = class {
2529
+ constructor(services, sources) {
2530
+ this.services = services;
2531
+ this.sources = sources;
2532
+ }
2533
+ compile(ast, ctx) {
2534
+ const target = this.sources.compileTableReference(ast.from);
2535
+ const using = this.compileUsingClause(ast, ctx);
2536
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2537
+ const returning = this.services.compileReturning(ast.returning, ctx);
2538
+ return `DELETE FROM ${target}${using}${where}${returning}`;
2539
+ }
2540
+ compileUsingClause(ast, ctx) {
2541
+ if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2542
+ if (!ast.using) {
2543
+ throw new Error("DELETE with JOINs requires a USING clause.");
2544
+ }
2545
+ const usingTable = this.sources.compileFrom(ast.using, ctx);
2546
+ const joins = JoinCompiler.compileJoins(
2547
+ ast.joins,
2548
+ ctx,
2549
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2550
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2375
2551
  );
2376
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
2377
- return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
2552
+ return ` USING ${usingTable}${joins}`;
2553
+ }
2554
+ };
2555
+
2556
+ // src/core/dialect/base/sql-dialect.ts
2557
+ var SqlDialectBase = class extends DialectBase {
2558
+ paginationStrategy;
2559
+ returningStrategy;
2560
+ upsertStrategy;
2561
+ dmlReturningSupported;
2562
+ sourceCompiler;
2563
+ standardUpdateCompiler;
2564
+ compilerSet;
2565
+ constructor(options = {}) {
2566
+ super(options.functionStrategy, options.tableFunctionStrategy);
2567
+ this.paginationStrategy = options.paginationStrategy ?? new StandardLimitOffsetPagination();
2568
+ this.returningStrategy = options.returningStrategy ?? new NoReturningStrategy();
2569
+ this.upsertStrategy = options.upsertStrategy ?? new NoUpsertStrategy();
2570
+ this.dmlReturningSupported = options.supportsDmlReturning ?? false;
2571
+ const services = {
2572
+ getDialectName: () => this.dialect,
2573
+ getPaginationStrategy: () => this.paginationStrategy,
2574
+ getTableFunctionStrategy: () => this.tableFunctionStrategy,
2575
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2576
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx),
2577
+ compileExpression: (node, ctx) => this.compileExpression(node, ctx),
2578
+ compileOrderingTerm: (term, ctx) => this.compileOrderingTerm(term, ctx),
2579
+ normalizeSelectAst: (ast) => this.normalizeSelectAst(ast),
2580
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
2581
+ compileReturning: (returning, ctx) => this.compileReturning(returning, ctx),
2582
+ compileUpsertClause: (ast, ctx) => this.compileUpsertClause(ast, ctx),
2583
+ compileSetTarget: (column, table) => this.compileSetTarget(column, table),
2584
+ renderOrderByNulls: (order) => this.renderOrderByNulls(order),
2585
+ renderOrderByCollation: (order) => this.renderOrderByCollation(order)
2586
+ };
2587
+ this.sourceCompiler = new StandardSqlSourceCompiler(services);
2588
+ const standardSelect = new StandardSelectCompiler(services, this.sourceCompiler);
2589
+ const standardInsert = new StandardInsertCompiler(services, this.sourceCompiler);
2590
+ this.standardUpdateCompiler = new StandardUpdateCompiler(services, this.sourceCompiler);
2591
+ const standardDelete = new StandardDeleteCompiler(services, this.sourceCompiler);
2592
+ const overrides = options.compilerFactory?.({
2593
+ services,
2594
+ sources: this.sourceCompiler
2595
+ }) ?? {};
2596
+ this.compilerSet = {
2597
+ select: overrides.select ?? standardSelect,
2598
+ insert: overrides.insert ?? standardInsert,
2599
+ update: overrides.update ?? this.standardUpdateCompiler,
2600
+ delete: overrides.delete ?? standardDelete
2601
+ };
2602
+ }
2603
+ supportsDmlReturningClause() {
2604
+ return this.dmlReturningSupported;
2605
+ }
2606
+ compileSelectAst(ast, ctx) {
2607
+ return this.compilerSet.select.compile(ast, ctx);
2608
+ }
2609
+ compileInsertAst(ast, ctx) {
2610
+ return this.compilerSet.insert.compile(ast, ctx);
2378
2611
  }
2379
2612
  compileUpdateAst(ast, ctx) {
2380
- const target = this.compileTableReference(ast.table);
2381
- const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
2382
- const fromClause = this.compileUpdateFromClause(ast, ctx);
2383
- const whereClause = this.compileWhere(ast.where, ctx);
2384
- const returning = this.compileReturning(ast.returning, ctx);
2385
- return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
2613
+ return this.compilerSet.update.compile(ast, ctx);
2614
+ }
2615
+ compileDeleteAst(ast, ctx) {
2616
+ return this.compilerSet.delete.compile(ast, ctx);
2617
+ }
2618
+ compileUpsertClause(ast, ctx) {
2619
+ return this.upsertStrategy.compile(ast, ctx, {
2620
+ getDialectName: () => this.dialect,
2621
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2622
+ compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext),
2623
+ compileExpression: (node, compilerContext) => this.compileExpression(node, compilerContext),
2624
+ compileUpdateAssignments: (assignments, table, compilerContext) => this.standardUpdateCompiler.compileAssignments(assignments, table, compilerContext)
2625
+ });
2626
+ }
2627
+ compileReturning(returning, ctx) {
2628
+ return this.returningStrategy.compileReturning(
2629
+ returning,
2630
+ ctx,
2631
+ (id) => this.quoteIdentifier(id)
2632
+ );
2633
+ }
2634
+ ensureConflictColumns(clause, message) {
2635
+ if (!clause.target.columns.length) throw new Error(message);
2386
2636
  }
2387
2637
  compileUpdateAssignments(assignments, table, ctx) {
2388
- return assignments.map((assignment) => {
2389
- const target = this.compileSetTarget(assignment.column, table);
2390
- const value = this.compileOperand(assignment.value, ctx);
2391
- return `${target} = ${value}`;
2392
- }).join(", ");
2638
+ return this.standardUpdateCompiler.compileAssignments(assignments, table, ctx);
2393
2639
  }
2394
2640
  compileSetTarget(column, table) {
2395
2641
  return this.compileQualifiedColumn(column, table);
@@ -2402,112 +2648,35 @@ var SqlDialectBase = class extends DialectBase {
2402
2648
  if (!tableQualifier) return this.quoteIdentifier(column.name);
2403
2649
  return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
2404
2650
  }
2405
- compileDeleteAst(ast, ctx) {
2406
- const target = this.compileTableReference(ast.from);
2407
- const usingClause = this.compileDeleteUsingClause(ast, ctx);
2408
- const whereClause = this.compileWhere(ast.where, ctx);
2409
- const returning = this.compileReturning(ast.returning, ctx);
2410
- return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
2411
- }
2412
2651
  formatReturningColumns(returning) {
2413
- return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
2414
- }
2415
- compileDistinct(ast) {
2416
- return ast.distinct ? "DISTINCT " : "";
2417
- }
2418
- compileSelectColumns(ast, ctx) {
2419
- if (!ast.columns || ast.columns.length === 0) return "*";
2420
- return ast.columns.map((column) => {
2421
- const expr = this.compileOperand(column, ctx);
2422
- if (column.alias) {
2423
- if (column.alias.includes("(")) return column.alias;
2424
- return `${expr} AS ${this.quoteIdentifier(column.alias)}`;
2425
- }
2426
- return expr;
2427
- }).join(", ");
2652
+ return this.returningStrategy.formatReturningColumns(
2653
+ returning,
2654
+ (id) => this.quoteIdentifier(id)
2655
+ );
2428
2656
  }
2429
- compileFrom(ast, ctx) {
2430
- if (ast.type === "FunctionTable") return this.compileFunctionTable(ast, ctx);
2431
- if (ast.type === "DerivedTable") return this.compileDerivedTable(ast, ctx);
2432
- return this.compileTableSource(ast);
2657
+ compileFrom(source, ctx) {
2658
+ return this.sourceCompiler.compileFrom(source, ctx);
2433
2659
  }
2434
2660
  compileFunctionTable(fn9, ctx) {
2435
- const key = fn9.key ?? fn9.name;
2436
- if (ctx) {
2437
- const renderer = this.tableFunctionStrategy.getRenderer(key);
2438
- if (renderer) {
2439
- const compiledArgs = (fn9.args ?? []).map((arg) => this.compileOperand(arg, ctx));
2440
- return renderer({
2441
- node: fn9,
2442
- compiledArgs,
2443
- compileOperand: (operand) => this.compileOperand(operand, ctx),
2444
- quoteIdentifier: this.quoteIdentifier.bind(this)
2445
- });
2446
- }
2447
- if (fn9.key) {
2448
- throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
2449
- }
2450
- }
2451
- return FunctionTableFormatter.format(fn9, ctx, {
2452
- quoteIdentifier: (id) => this.quoteIdentifier(id),
2453
- compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext)
2454
- });
2661
+ return this.sourceCompiler.compileFunctionTable(fn9, ctx);
2455
2662
  }
2456
2663
  compileDerivedTable(table, ctx) {
2457
- if (!table.alias) throw new Error("Derived tables must have an alias.");
2458
- const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2459
- const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2460
- return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
2664
+ return this.sourceCompiler.compileDerivedTable(table, ctx);
2461
2665
  }
2462
2666
  compileTableSource(table) {
2463
- if (table.type === "FunctionTable") return this.compileFunctionTable(table);
2464
- if (table.type === "DerivedTable") return this.compileDerivedTable(table);
2465
- const base = this.compileTableName(table);
2466
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2667
+ return this.sourceCompiler.compileTableSource(table);
2467
2668
  }
2468
2669
  compileTableName(table) {
2469
- if (table.schema) {
2470
- return `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`;
2471
- }
2472
- return this.quoteIdentifier(table.name);
2670
+ return this.sourceCompiler.compileTableName(table);
2473
2671
  }
2474
2672
  compileTableReference(table) {
2475
- const base = this.compileTableName(table);
2476
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2477
- }
2478
- compileUpdateFromClause(ast, ctx) {
2479
- if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2480
- if (!ast.from) throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2481
- const from = this.compileFrom(ast.from, ctx);
2482
- const joins = JoinCompiler.compileJoins(
2483
- ast.joins,
2484
- ctx,
2485
- this.compileFrom.bind(this),
2486
- this.compileExpression.bind(this)
2487
- );
2488
- return ` FROM ${from}${joins}`;
2489
- }
2490
- compileDeleteUsingClause(ast, ctx) {
2491
- if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2492
- if (!ast.using) throw new Error("DELETE with JOINs requires a USING clause.");
2493
- const usingTable = this.compileFrom(ast.using, ctx);
2494
- const joins = JoinCompiler.compileJoins(
2495
- ast.joins,
2496
- ctx,
2497
- this.compileFrom.bind(this),
2498
- this.compileExpression.bind(this)
2499
- );
2500
- return ` USING ${usingTable}${joins}`;
2501
- }
2502
- compileHaving(ast, ctx) {
2503
- if (!ast.having) return "";
2504
- return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
2673
+ return this.sourceCompiler.compileTableReference(table);
2505
2674
  }
2506
2675
  stripTrailingSemicolon(sql) {
2507
- return sql.trim().replace(/;$/, "");
2676
+ return this.sourceCompiler.stripTrailingSemicolon(sql);
2508
2677
  }
2509
2678
  wrapSetOperand(sql) {
2510
- return `(${this.stripTrailingSemicolon(sql)})`;
2679
+ return this.sourceCompiler.wrapSetOperand(sql);
2511
2680
  }
2512
2681
  renderOrderByNulls(order) {
2513
2682
  return order.nulls ? ` NULLS ${order.nulls}` : "";
@@ -2692,105 +2861,112 @@ var PostgresTableFunctionStrategy = class extends StandardTableFunctionStrategy
2692
2861
  }
2693
2862
  };
2694
2863
 
2864
+ // src/core/dialect/postgres/procedure-compiler.ts
2865
+ var PostgresProcedureCompiler = class {
2866
+ constructor(services) {
2867
+ this.services = services;
2868
+ }
2869
+ compileProcedureCall(ast) {
2870
+ const ctx = this.services.createCompilerContext();
2871
+ const qualifiedName = ast.ref.schema ? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}` : this.services.quoteIdentifier(ast.ref.name);
2872
+ const args = [];
2873
+ for (const param of ast.params) {
2874
+ if (param.direction === "out") continue;
2875
+ if (!param.value) {
2876
+ throw new Error(
2877
+ `Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`
2878
+ );
2879
+ }
2880
+ args.push(this.services.compileOperand(param.value, ctx));
2881
+ }
2882
+ const outNames = ast.params.filter((param) => param.direction === "out" || param.direction === "inout").map((param) => param.name);
2883
+ return {
2884
+ sql: `CALL ${qualifiedName}(${args.join(", ")});`,
2885
+ params: [...ctx.params],
2886
+ outParams: {
2887
+ source: outNames.length ? "firstResultSet" : "none",
2888
+ names: outNames
2889
+ }
2890
+ };
2891
+ }
2892
+ };
2893
+
2894
+ // src/core/dialect/postgres/returning.ts
2895
+ var PostgresReturningStrategy = class extends StandardReturningStrategy {
2896
+ };
2897
+
2898
+ // src/core/dialect/postgres/upsert.ts
2899
+ var PostgresUpsertStrategy = class {
2900
+ compile(ast, ctx, services) {
2901
+ if (!ast.onConflict) return "";
2902
+ const clause = ast.onConflict;
2903
+ const target = clause.target.constraint ? ` ON CONFLICT ON CONSTRAINT ${services.quoteIdentifier(clause.target.constraint)}` : (() => {
2904
+ if (!clause.target.columns.length) {
2905
+ throw new Error("PostgreSQL ON CONFLICT requires conflict columns or a constraint name.");
2906
+ }
2907
+ const columns = clause.target.columns.map((column) => services.quoteIdentifier(column.name)).join(", ");
2908
+ return ` ON CONFLICT (${columns})`;
2909
+ })();
2910
+ if (clause.action.type === "DoNothing") {
2911
+ return `${target} DO NOTHING`;
2912
+ }
2913
+ if (!clause.action.set.length) {
2914
+ throw new Error("PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.");
2915
+ }
2916
+ const assignments = services.compileUpdateAssignments(clause.action.set, ast.into, ctx);
2917
+ const where = clause.action.where ? ` WHERE ${services.compileExpression(clause.action.where, ctx)}` : "";
2918
+ return `${target} DO UPDATE SET ${assignments}${where}`;
2919
+ }
2920
+ };
2921
+
2695
2922
  // src/core/dialect/postgres/index.ts
2696
2923
  var PostgresDialect = class extends SqlDialectBase {
2697
2924
  dialect = "postgres";
2698
- /**
2699
- * Creates a new PostgresDialect instance
2700
- */
2925
+ procedureCompiler;
2701
2926
  constructor() {
2702
- super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
2927
+ super({
2928
+ functionStrategy: new PostgresFunctionStrategy(),
2929
+ tableFunctionStrategy: new PostgresTableFunctionStrategy(),
2930
+ returningStrategy: new PostgresReturningStrategy(),
2931
+ upsertStrategy: new PostgresUpsertStrategy(),
2932
+ supportsDmlReturning: true
2933
+ });
2934
+ this.procedureCompiler = new PostgresProcedureCompiler({
2935
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2936
+ createCompilerContext: () => this.createCompilerContext(),
2937
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx)
2938
+ });
2703
2939
  this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
2704
2940
  const left2 = this.compileOperand(node.left, ctx);
2705
2941
  const right2 = this.compileOperand(node.right, ctx);
2706
- const op = node.operator === "^" ? "#" : node.operator;
2707
- return `${left2} ${op} ${right2}`;
2942
+ const operator = node.operator === "^" ? "#" : node.operator;
2943
+ return `${left2} ${operator} ${right2}`;
2708
2944
  });
2709
2945
  this.registerOperandCompiler("BitwiseExpression", (node, ctx) => {
2710
2946
  const left2 = this.compileOperand(node.left, ctx);
2711
2947
  const right2 = this.compileOperand(node.right, ctx);
2712
- const op = node.operator === "^" ? "#" : node.operator;
2713
- return `(${left2} ${op} ${right2})`;
2948
+ const operator = node.operator === "^" ? "#" : node.operator;
2949
+ return `(${left2} ${operator} ${right2})`;
2714
2950
  });
2715
2951
  }
2716
- /**
2717
- * Quotes an identifier using PostgreSQL double-quote syntax
2718
- * @param id - Identifier to quote
2719
- * @returns Quoted identifier
2720
- */
2721
2952
  quoteIdentifier(id) {
2722
2953
  return `"${id}"`;
2723
2954
  }
2724
2955
  formatPlaceholder(index) {
2725
2956
  return `$${index}`;
2726
2957
  }
2727
- /**
2728
- * Compiles JSON path expression using PostgreSQL syntax
2729
- * @param node - JSON path node
2730
- * @returns PostgreSQL JSON path expression
2731
- */
2732
2958
  compileJsonPath(node) {
2733
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2734
- return `${col2}->>'${node.path}'`;
2735
- }
2736
- compileReturning(returning, ctx) {
2737
- void ctx;
2738
- if (!returning || returning.length === 0) return "";
2739
- const columns = this.formatReturningColumns(returning);
2740
- return ` RETURNING ${columns}`;
2741
- }
2742
- compileUpsertClause(ast, ctx) {
2743
- if (!ast.onConflict) return "";
2744
- const clause = ast.onConflict;
2745
- const target = clause.target.constraint ? ` ON CONFLICT ON CONSTRAINT ${this.quoteIdentifier(clause.target.constraint)}` : (() => {
2746
- this.ensureConflictColumns(
2747
- clause,
2748
- "PostgreSQL ON CONFLICT requires conflict columns or a constraint name."
2749
- );
2750
- const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
2751
- return ` ON CONFLICT (${cols})`;
2752
- })();
2753
- if (clause.action.type === "DoNothing") {
2754
- return `${target} DO NOTHING`;
2755
- }
2756
- if (!clause.action.set.length) {
2757
- throw new Error("PostgreSQL ON CONFLICT DO UPDATE requires at least one assignment.");
2758
- }
2759
- const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
2760
- const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
2761
- return `${target} DO UPDATE SET ${assignments}${where}`;
2762
- }
2763
- supportsDmlReturningClause() {
2764
- return true;
2765
- }
2766
- compileProcedureCall(ast) {
2767
- const ctx = this.createCompilerContext();
2768
- const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
2769
- const args = [];
2770
- for (const param of ast.params) {
2771
- if (param.direction === "out") continue;
2772
- if (!param.value) {
2773
- throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
2774
- }
2775
- args.push(this.compileOperand(param.value, ctx));
2776
- }
2777
- const outNames = ast.params.filter((param) => param.direction === "out" || param.direction === "inout").map((param) => param.name);
2778
- const rawSql = `CALL ${qualifiedName}(${args.join(", ")})`;
2779
- return {
2780
- sql: `${rawSql};`,
2781
- params: [...ctx.params],
2782
- outParams: {
2783
- source: outNames.length ? "firstResultSet" : "none",
2784
- names: outNames
2785
- }
2786
- };
2959
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2960
+ return `${column}->>'${node.path}'`;
2787
2961
  }
2788
- /**
2789
- * PostgreSQL requires unqualified column names in SET clause
2790
- */
2962
+ /** PostgreSQL requires unqualified column names in SET clauses. */
2791
2963
  compileSetTarget(column, _table) {
2964
+ void _table;
2792
2965
  return this.quoteIdentifier(column.name);
2793
2966
  }
2967
+ compileProcedureCall(ast) {
2968
+ return this.procedureCompiler.compileProcedureCall(ast);
2969
+ }
2794
2970
  };
2795
2971
 
2796
2972
  // src/core/dialect/mysql/functions.ts
@@ -2891,72 +3067,15 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
2891
3067
  }
2892
3068
  };
2893
3069
 
2894
- // src/core/dialect/mysql/index.ts
3070
+ // src/core/dialect/mysql/procedure-compiler.ts
2895
3071
  var sanitizeVariableSuffix = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
2896
- var MySqlDialect = class extends SqlDialectBase {
2897
- dialect = "mysql";
2898
- /**
2899
- * Creates a new MySqlDialect instance
2900
- */
2901
- constructor() {
2902
- super(new MysqlFunctionStrategy());
2903
- this.registerExpressionCompiler(
2904
- "IsDistinctExpression",
2905
- (node, ctx) => {
2906
- const left2 = this.compileOperand(node.left, ctx);
2907
- const right2 = this.compileOperand(node.right, ctx);
2908
- const spaceship = `${left2} <=> ${right2}`;
2909
- if (node.operator === "IS NOT DISTINCT FROM") {
2910
- return spaceship;
2911
- }
2912
- return `NOT (${spaceship})`;
2913
- }
2914
- );
2915
- }
2916
- /**
2917
- * Quotes an identifier using MySQL backtick syntax
2918
- * @param id - Identifier to quote
2919
- * @returns Quoted identifier
2920
- */
2921
- quoteIdentifier(id) {
2922
- return `\`${id}\``;
2923
- }
2924
- /**
2925
- * Compiles JSON path expression using MySQL syntax
2926
- * @param node - JSON path node
2927
- * @returns MySQL JSON path expression
2928
- */
2929
- compileJsonPath(node) {
2930
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
2931
- return `${col2}->'${node.path}'`;
2932
- }
2933
- compileUpsertClause(ast, ctx) {
2934
- if (!ast.onConflict) return "";
2935
- const clause = ast.onConflict;
2936
- if (clause.action.type === "DoNothing") {
2937
- const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
2938
- if (!noOpColumn) {
2939
- throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one target column.");
2940
- }
2941
- const col2 = this.quoteIdentifier(noOpColumn.name);
2942
- return ` ON DUPLICATE KEY UPDATE ${col2} = ${col2}`;
2943
- }
2944
- if (clause.action.where) {
2945
- throw new Error("MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.");
2946
- }
2947
- if (!clause.action.set.length) {
2948
- throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.");
2949
- }
2950
- const assignments = clause.action.set.map((assignment) => {
2951
- const target = this.quoteIdentifier(assignment.column.name);
2952
- const value = this.compileOperand(assignment.value, ctx);
2953
- return `${target} = ${value}`;
2954
- }).join(", ");
2955
- return ` ON DUPLICATE KEY UPDATE ${assignments}`;
3072
+ var MySqlProcedureCompiler = class {
3073
+ constructor(services) {
3074
+ this.services = services;
2956
3075
  }
2957
3076
  compileProcedureCall(ast) {
2958
- const ctx = this.createCompilerContext();
2959
- const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
3077
+ const ctx = this.services.createCompilerContext();
3078
+ const qualifiedName = ast.ref.schema ? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}` : this.services.quoteIdentifier(ast.ref.name);
2960
3079
  const prelude = [];
2961
3080
  const callArgs = [];
2962
3081
  const outVars = [];
@@ -2967,35 +3086,97 @@ var MySqlDialect = class extends SqlDialectBase {
2967
3086
  if (!param.value) {
2968
3087
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
2969
3088
  }
2970
- callArgs.push(this.compileOperand(param.value, ctx));
3089
+ callArgs.push(this.services.compileOperand(param.value, ctx));
2971
3090
  return;
2972
3091
  }
2973
3092
  if (param.direction === "inout") {
2974
3093
  if (!param.value) {
2975
3094
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
2976
3095
  }
2977
- prelude.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
3096
+ prelude.push(`SET ${variable} = ${this.services.compileOperand(param.value, ctx)};`);
2978
3097
  }
2979
3098
  callArgs.push(variable);
2980
3099
  outVars.push({ variable, name: param.name });
2981
3100
  });
2982
3101
  const statements = [];
2983
- if (prelude.length) {
2984
- statements.push(...prelude);
3102
+ if (prelude.length) statements.push(...prelude);
3103
+ statements.push(`CALL ${qualifiedName}(${callArgs.join(", ")});`);
3104
+ if (outVars.length) {
3105
+ const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.services.quoteIdentifier(name)}`).join(", ");
3106
+ statements.push(`SELECT ${selectOut};`);
3107
+ }
3108
+ return {
3109
+ sql: statements.join(" "),
3110
+ params: [...ctx.params],
3111
+ outParams: {
3112
+ source: outVars.length ? "lastResultSet" : "none",
3113
+ names: outVars.map((item) => item.name)
3114
+ }
3115
+ };
3116
+ }
3117
+ };
3118
+
3119
+ // src/core/dialect/mysql/upsert.ts
3120
+ var MySqlUpsertStrategy = class {
3121
+ compile(ast, ctx, services) {
3122
+ if (!ast.onConflict) return "";
3123
+ const clause = ast.onConflict;
3124
+ if (clause.action.type === "DoNothing") {
3125
+ const noOpColumn = clause.target.columns[0] ?? ast.columns[0];
3126
+ if (!noOpColumn) {
3127
+ throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one target column.");
3128
+ }
3129
+ const col2 = services.quoteIdentifier(noOpColumn.name);
3130
+ return ` ON DUPLICATE KEY UPDATE ${col2} = ${col2}`;
3131
+ }
3132
+ if (clause.action.where) {
3133
+ throw new Error("MySQL ON DUPLICATE KEY UPDATE does not support a WHERE clause.");
2985
3134
  }
2986
- statements.push(`CALL ${qualifiedName}(${callArgs.join(", ")});`);
2987
- if (outVars.length) {
2988
- const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
2989
- statements.push(`SELECT ${selectOut};`);
3135
+ if (!clause.action.set.length) {
3136
+ throw new Error("MySQL ON DUPLICATE KEY UPDATE requires at least one assignment.");
2990
3137
  }
2991
- return {
2992
- sql: statements.join(" "),
2993
- params: [...ctx.params],
2994
- outParams: {
2995
- source: outVars.length ? "lastResultSet" : "none",
2996
- names: outVars.map((item) => item.name)
3138
+ const assignments = clause.action.set.map((assignment) => {
3139
+ const target = services.quoteIdentifier(assignment.column.name);
3140
+ const value = services.compileOperand(assignment.value, ctx);
3141
+ return `${target} = ${value}`;
3142
+ }).join(", ");
3143
+ return ` ON DUPLICATE KEY UPDATE ${assignments}`;
3144
+ }
3145
+ };
3146
+
3147
+ // src/core/dialect/mysql/index.ts
3148
+ var MySqlDialect = class extends SqlDialectBase {
3149
+ dialect = "mysql";
3150
+ procedureCompiler;
3151
+ constructor() {
3152
+ super({
3153
+ functionStrategy: new MysqlFunctionStrategy(),
3154
+ upsertStrategy: new MySqlUpsertStrategy()
3155
+ });
3156
+ this.procedureCompiler = new MySqlProcedureCompiler({
3157
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
3158
+ createCompilerContext: () => this.createCompilerContext(),
3159
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx)
3160
+ });
3161
+ this.registerExpressionCompiler(
3162
+ "IsDistinctExpression",
3163
+ (node, ctx) => {
3164
+ const left2 = this.compileOperand(node.left, ctx);
3165
+ const right2 = this.compileOperand(node.right, ctx);
3166
+ const spaceship = `${left2} <=> ${right2}`;
3167
+ return node.operator === "IS NOT DISTINCT FROM" ? spaceship : `NOT (${spaceship})`;
2997
3168
  }
2998
- };
3169
+ );
3170
+ }
3171
+ quoteIdentifier(id) {
3172
+ return `\`${id}\``;
3173
+ }
3174
+ compileJsonPath(node) {
3175
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
3176
+ return `${column}->'${node.path}'`;
3177
+ }
3178
+ compileProcedureCall(ast) {
3179
+ return this.procedureCompiler.compileProcedureCall(ast);
2999
3180
  }
3000
3181
  };
3001
3182
 
@@ -3136,14 +3317,56 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
3136
3317
  }
3137
3318
  };
3138
3319
 
3320
+ // src/core/dialect/sqlite/returning.ts
3321
+ var SqliteReturningStrategy = class {
3322
+ compileReturning(returning, _ctx, quoteIdentifier) {
3323
+ void _ctx;
3324
+ if (!returning || returning.length === 0) return "";
3325
+ return ` RETURNING ${this.formatReturningColumns(returning, quoteIdentifier)}`;
3326
+ }
3327
+ formatReturningColumns(returning, quoteIdentifier) {
3328
+ return returning.map((column) => {
3329
+ const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
3330
+ return `${quoteIdentifier(column.name)}${alias}`;
3331
+ }).join(", ");
3332
+ }
3333
+ };
3334
+
3335
+ // src/core/dialect/sqlite/upsert.ts
3336
+ var SqliteUpsertStrategy = class {
3337
+ compile(ast, ctx, services) {
3338
+ if (!ast.onConflict) return "";
3339
+ const clause = ast.onConflict;
3340
+ if (clause.target.constraint) {
3341
+ throw new Error("SQLite ON CONFLICT does not support named constraints.");
3342
+ }
3343
+ if (!clause.target.columns.length) {
3344
+ throw new Error("SQLite ON CONFLICT requires conflict columns.");
3345
+ }
3346
+ const columns = clause.target.columns.map((column) => services.quoteIdentifier(column.name)).join(", ");
3347
+ const target = ` ON CONFLICT (${columns})`;
3348
+ if (clause.action.type === "DoNothing") {
3349
+ return `${target} DO NOTHING`;
3350
+ }
3351
+ if (!clause.action.set.length) {
3352
+ throw new Error("SQLite ON CONFLICT DO UPDATE requires at least one assignment.");
3353
+ }
3354
+ const assignments = services.compileUpdateAssignments(clause.action.set, ast.into, ctx);
3355
+ const where = clause.action.where ? ` WHERE ${services.compileExpression(clause.action.where, ctx)}` : "";
3356
+ return `${target} DO UPDATE SET ${assignments}${where}`;
3357
+ }
3358
+ };
3359
+
3139
3360
  // src/core/dialect/sqlite/index.ts
3140
3361
  var SqliteDialect = class extends SqlDialectBase {
3141
3362
  dialect = "sqlite";
3142
- /**
3143
- * Creates a new SqliteDialect instance
3144
- */
3145
3363
  constructor() {
3146
- super(new SqliteFunctionStrategy());
3364
+ super({
3365
+ functionStrategy: new SqliteFunctionStrategy(),
3366
+ returningStrategy: new SqliteReturningStrategy(),
3367
+ upsertStrategy: new SqliteUpsertStrategy(),
3368
+ supportsDmlReturning: true
3369
+ });
3147
3370
  this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
3148
3371
  const left2 = this.compileOperand(node.left, ctx);
3149
3372
  const right2 = this.compileOperand(node.right, ctx);
@@ -3161,61 +3384,17 @@ var SqliteDialect = class extends SqlDialectBase {
3161
3384
  return `(${left2} ${node.operator} ${right2})`;
3162
3385
  });
3163
3386
  }
3164
- /**
3165
- * Quotes an identifier using SQLite double-quote syntax
3166
- * @param id - Identifier to quote
3167
- * @returns Quoted identifier
3168
- */
3169
3387
  quoteIdentifier(id) {
3170
3388
  return `"${id}"`;
3171
3389
  }
3172
- /**
3173
- * Compiles JSON path expression using SQLite syntax
3174
- * @param node - JSON path node
3175
- * @returns SQLite JSON path expression
3176
- */
3177
3390
  compileJsonPath(node) {
3178
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
3179
- return `json_extract(${col2}, '${node.path}')`;
3391
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
3392
+ return `json_extract(${column}, '${node.path}')`;
3180
3393
  }
3181
3394
  compileQualifiedColumn(column, _table) {
3182
3395
  void _table;
3183
3396
  return this.quoteIdentifier(column.name);
3184
3397
  }
3185
- compileReturning(returning, ctx) {
3186
- void ctx;
3187
- if (!returning || returning.length === 0) return "";
3188
- const columns = this.formatReturningColumns(returning);
3189
- return ` RETURNING ${columns}`;
3190
- }
3191
- formatReturningColumns(returning) {
3192
- return returning.map((column) => {
3193
- const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
3194
- return `${this.quoteIdentifier(column.name)}${alias}`;
3195
- }).join(", ");
3196
- }
3197
- compileUpsertClause(ast, ctx) {
3198
- if (!ast.onConflict) return "";
3199
- const clause = ast.onConflict;
3200
- if (clause.target.constraint) {
3201
- throw new Error("SQLite ON CONFLICT does not support named constraints.");
3202
- }
3203
- this.ensureConflictColumns(clause, "SQLite ON CONFLICT requires conflict columns.");
3204
- const cols = clause.target.columns.map((col2) => this.quoteIdentifier(col2.name)).join(", ");
3205
- const target = ` ON CONFLICT (${cols})`;
3206
- if (clause.action.type === "DoNothing") {
3207
- return `${target} DO NOTHING`;
3208
- }
3209
- if (!clause.action.set.length) {
3210
- throw new Error("SQLite ON CONFLICT DO UPDATE requires at least one assignment.");
3211
- }
3212
- const assignments = this.compileUpdateAssignments(clause.action.set, ast.into, ctx);
3213
- const where = clause.action.where ? ` WHERE ${this.compileExpression(clause.action.where, ctx)}` : "";
3214
- return `${target} DO UPDATE SET ${assignments}${where}`;
3215
- }
3216
- supportsDmlReturningClause() {
3217
- return true;
3218
- }
3219
3398
  };
3220
3399
 
3221
3400
  // src/core/dialect/mssql/functions.ts
@@ -3342,202 +3521,107 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
3342
3521
  }
3343
3522
  };
3344
3523
 
3345
- // src/core/dialect/mssql/index.ts
3346
- var sanitizeVariableSuffix2 = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
3347
- var toProcedureParamReference = (value) => value.startsWith("@") ? value : `@${value}`;
3348
- var SqlServerDialect = class extends SqlDialectBase {
3349
- dialect = "mssql";
3350
- /**
3351
- * Creates a new SqlServerDialect instance
3352
- */
3353
- constructor() {
3354
- super(new MssqlFunctionStrategy());
3355
- }
3356
- /**
3357
- * Quotes an identifier using SQL Server bracket syntax
3358
- * @param id - Identifier to quote
3359
- * @returns Quoted identifier
3360
- */
3361
- quoteIdentifier(id) {
3362
- return `[${id}]`;
3363
- }
3364
- /**
3365
- * Compiles JSON path expression using SQL Server syntax
3366
- * @param node - JSON path node
3367
- * @returns SQL Server JSON path expression
3368
- */
3369
- compileJsonPath(node) {
3370
- const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
3371
- return `JSON_VALUE(${col2}, '${node.path}')`;
3524
+ // src/core/dialect/mssql/output.ts
3525
+ var MssqlOutputStrategy = class {
3526
+ compileReturning(returning, _ctx, quoteIdentifier) {
3527
+ void _ctx;
3528
+ return this.compileOutput(returning, "inserted", quoteIdentifier);
3372
3529
  }
3373
- /**
3374
- * Formats parameter placeholders using SQL Server named parameter syntax
3375
- * @param index - Parameter index
3376
- * @returns Named parameter placeholder
3377
- */
3378
- formatPlaceholder(index) {
3379
- return `@p${index}`;
3530
+ compileOutput(returning, prefix, quoteIdentifier) {
3531
+ if (!returning || returning.length === 0) return "";
3532
+ const columns = returning.map((column) => {
3533
+ const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
3534
+ return `${prefix}.${quoteIdentifier(column.name)}${alias}`;
3535
+ }).join(", ");
3536
+ return ` OUTPUT ${columns}`;
3380
3537
  }
3381
- /**
3382
- * Compiles SELECT query AST to SQL Server SQL
3383
- * @param ast - Query AST
3384
- * @param ctx - Compiler context
3385
- * @returns SQL Server SQL string
3386
- */
3387
- compileSelectAst(ast, ctx) {
3388
- const hasSetOps = !!(ast.setOps && ast.setOps.length);
3389
- const ctes = this.compileCtes(ast, ctx);
3390
- const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
3391
- const baseSelect = this.compileSelectCoreForMssql(baseAst, ctx);
3392
- if (!hasSetOps) {
3393
- return `${ctes}${baseSelect}`;
3394
- }
3395
- const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
3396
- const orderBy = this.compileOrderBy(ast, ctx);
3397
- const pagination = this.compilePagination(ast, orderBy);
3398
- const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
3399
- const tail = pagination || orderBy;
3400
- return `${ctes}${combined}${tail}`;
3538
+ formatReturningColumns(returning, quoteIdentifier) {
3539
+ return returning.map((column) => {
3540
+ const alias = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
3541
+ return `${quoteIdentifier(column.name)}${alias}`;
3542
+ }).join(", ");
3401
3543
  }
3402
- compileDeleteAst(ast, ctx) {
3544
+ };
3545
+
3546
+ // src/core/dialect/mssql/delete-compiler.ts
3547
+ var MssqlDeleteCompiler = class {
3548
+ constructor(services, sources) {
3549
+ this.services = services;
3550
+ this.sources = sources;
3551
+ }
3552
+ output = new MssqlOutputStrategy();
3553
+ compile(ast, ctx) {
3403
3554
  if (ast.using) {
3404
3555
  throw new Error("DELETE ... USING is not supported in the MSSQL dialect; use join() instead.");
3405
3556
  }
3406
- if (ast.from.type !== "Table") {
3407
- throw new Error("DELETE only supports base tables in the MSSQL dialect.");
3408
- }
3409
3557
  const alias = ast.from.alias ?? ast.from.name;
3410
- const target = this.compileTableReference(ast.from);
3558
+ const target = this.sources.compileTableReference(ast.from);
3411
3559
  const joins = JoinCompiler.compileJoins(
3412
3560
  ast.joins,
3413
3561
  ctx,
3414
- this.compileFrom.bind(this),
3415
- this.compileExpression.bind(this)
3562
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
3563
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
3416
3564
  );
3417
- const whereClause = this.compileWhere(ast.where, ctx);
3418
- const returning = this.compileOutputClause(ast.returning, "deleted");
3419
- return `DELETE ${this.quoteIdentifier(alias)}${returning} FROM ${target}${joins}${whereClause}`;
3420
- }
3421
- compileUpdateAst(ast, ctx) {
3422
- const target = this.compileTableReference(ast.table);
3423
- const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
3424
- const output = this.compileReturning(ast.returning, ctx);
3425
- const fromClause = ast.from ? ` FROM ${this.compileFrom(ast.from, ctx)}` : "";
3426
- const joins = ast.joins ? ast.joins.map((j) => {
3427
- const table = this.compileFrom(j.table, ctx);
3428
- const cond = this.compileExpression(j.condition, ctx);
3429
- return ` ${j.kind} JOIN ${table} ON ${cond}`;
3430
- }).join("") : "";
3431
- const whereClause = this.compileWhere(ast.where, ctx);
3432
- return `UPDATE ${target} SET ${assignments}${output}${fromClause}${joins}${whereClause}`;
3433
- }
3434
- compileSelectCoreForMssql(ast, ctx) {
3435
- const columns = ast.columns.map((c) => {
3436
- const expr = c.type === "Column" ? `${this.quoteIdentifier(c.table)}.${this.quoteIdentifier(c.name)}` : this.compileOperand(c, ctx);
3437
- if (c.alias) {
3438
- if (c.alias.includes("(")) return c.alias;
3439
- return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
3440
- }
3441
- return expr;
3442
- }).join(", ");
3443
- const distinct = ast.distinct ? "DISTINCT " : "";
3444
- const from = this.compileFrom(ast.from, ctx);
3445
- const joins = ast.joins.map((j) => {
3446
- const table = this.compileFrom(j.table, ctx);
3447
- const cond = this.compileExpression(j.condition, ctx);
3448
- return `${j.kind} JOIN ${table} ON ${cond}`;
3449
- }).join(" ");
3450
- const whereClause = this.compileWhere(ast.where, ctx);
3451
- const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((term) => this.compileOrderingTerm(term, ctx)).join(", ") : "";
3452
- const having = ast.having ? ` HAVING ${this.compileExpression(ast.having, ctx)}` : "";
3453
- const orderBy = this.compileOrderBy(ast, ctx);
3454
- const pagination = this.compilePagination(ast, orderBy);
3455
- if (pagination) {
3456
- return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${pagination}`;
3457
- }
3458
- return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${orderBy}`;
3459
- }
3460
- compileOrderBy(ast, ctx) {
3461
- return OrderByCompiler.compileOrderBy(
3462
- ast,
3463
- (term) => this.compileOrderingTerm(term, ctx),
3464
- this.renderOrderByNulls.bind(this),
3465
- this.renderOrderByCollation.bind(this)
3565
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
3566
+ const returning = this.output.compileOutput(
3567
+ ast.returning,
3568
+ "deleted",
3569
+ (id) => this.services.quoteIdentifier(id)
3466
3570
  );
3571
+ return `DELETE ${this.services.quoteIdentifier(alias)}${returning} FROM ${target}${joins}${where}`;
3467
3572
  }
3468
- compilePagination(ast, orderBy) {
3469
- const hasLimit = ast.limit !== void 0;
3470
- const hasOffset = ast.offset !== void 0;
3471
- if (!hasLimit && !hasOffset) return "";
3472
- const off = ast.offset ?? 0;
3473
- let orderClause = orderBy;
3474
- if (!orderClause) {
3475
- orderClause = ast.distinct && ast.distinct.length > 0 ? " ORDER BY 1" : " ORDER BY (SELECT NULL)";
3476
- }
3477
- let pagination = `${orderClause} OFFSET ${off} ROWS`;
3478
- if (hasLimit) {
3479
- pagination += ` FETCH NEXT ${ast.limit} ROWS ONLY`;
3480
- }
3481
- return pagination;
3482
- }
3483
- supportsDmlReturningClause() {
3484
- return true;
3485
- }
3486
- compileReturning(returning, _ctx) {
3487
- void _ctx;
3488
- return this.compileOutputClause(returning, "inserted");
3489
- }
3490
- compileOutputClause(returning, prefix) {
3491
- if (!returning || returning.length === 0) return "";
3492
- const columns = returning.map((column) => {
3493
- const colName = this.quoteIdentifier(column.name);
3494
- const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
3495
- return `${prefix}.${colName}${alias}`;
3496
- }).join(", ");
3497
- return ` OUTPUT ${columns}`;
3573
+ };
3574
+
3575
+ // src/core/dialect/mssql/insert-compiler.ts
3576
+ var MssqlInsertCompiler = class {
3577
+ constructor(services, sources) {
3578
+ this.services = services;
3579
+ this.sources = sources;
3498
3580
  }
3499
- compileInsertAst(ast, ctx) {
3581
+ compile(ast, ctx) {
3500
3582
  if (!ast.columns.length) {
3501
3583
  throw new Error("INSERT queries must specify columns.");
3502
3584
  }
3503
- if (ast.onConflict) {
3504
- return this.compileMergeInsert(ast, ctx);
3505
- }
3506
- const table = this.compileTableName(ast.into);
3507
- const columnList = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
3508
- const output = this.compileReturning(ast.returning, ctx);
3509
- const source = this.compileInsertValues(ast, ctx);
3510
- return `INSERT INTO ${table} (${columnList})${output} ${source}`;
3585
+ if (ast.onConflict) return this.compileMerge(ast, ctx);
3586
+ const table = this.sources.compileTableName(ast.into);
3587
+ const columns = ast.columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
3588
+ const output = this.services.compileReturning(ast.returning, ctx);
3589
+ const source = this.compileInsertSource(ast, ctx);
3590
+ return `INSERT INTO ${table} (${columns})${output} ${source}`;
3511
3591
  }
3512
- compileMergeInsert(ast, ctx) {
3592
+ compileMerge(ast, ctx) {
3513
3593
  const clause = ast.onConflict;
3514
3594
  if (clause.target.constraint) {
3515
3595
  throw new Error("MSSQL MERGE does not support conflict target by constraint name.");
3516
3596
  }
3517
- this.ensureConflictColumns(clause, "MSSQL MERGE requires conflict columns for the ON clause.");
3518
- const table = this.compileTableName(ast.into);
3519
- const targetRef = this.quoteIdentifier(ast.into.alias ?? ast.into.name);
3520
- const sourceAlias = this.quoteIdentifier("src");
3521
- const sourceColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
3597
+ if (!clause.target.columns.length) {
3598
+ throw new Error("MSSQL MERGE requires conflict columns for the ON clause.");
3599
+ }
3600
+ const table = this.sources.compileTableName(ast.into);
3601
+ const targetRef = this.services.quoteIdentifier(ast.into.alias ?? ast.into.name);
3602
+ const sourceAlias = this.services.quoteIdentifier("src");
3603
+ const sourceColumns = ast.columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
3522
3604
  const usingSource = this.compileMergeUsingSource(ast, ctx);
3523
- const onClause = clause.target.columns.map((column) => `${targetRef}.${this.quoteIdentifier(column.name)} = ${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(" AND ");
3605
+ const onClause = clause.target.columns.map(
3606
+ (column) => `${targetRef}.${this.services.quoteIdentifier(column.name)} = ${sourceAlias}.${this.services.quoteIdentifier(column.name)}`
3607
+ ).join(" AND ");
3524
3608
  const branches = [];
3525
3609
  if (clause.action.type === "DoUpdate") {
3526
3610
  if (!clause.action.set.length) {
3527
3611
  throw new Error("MSSQL MERGE WHEN MATCHED UPDATE requires at least one assignment.");
3528
3612
  }
3529
3613
  const assignments = clause.action.set.map((assignment) => {
3530
- const target = `${targetRef}.${this.quoteIdentifier(assignment.column.name)}`;
3531
- const value = this.compileOperand(assignment.value, ctx);
3614
+ const target = `${targetRef}.${this.services.quoteIdentifier(assignment.column.name)}`;
3615
+ const value = this.services.compileOperand(assignment.value, ctx);
3532
3616
  return `${target} = ${value}`;
3533
3617
  }).join(", ");
3534
- const guard = clause.action.where ? ` AND ${this.compileExpression(clause.action.where, ctx)}` : "";
3618
+ const guard = clause.action.where ? ` AND ${this.services.compileExpression(clause.action.where, ctx)}` : "";
3535
3619
  branches.push(`WHEN MATCHED${guard} THEN UPDATE SET ${assignments}`);
3536
3620
  }
3537
- const insertColumns = ast.columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
3538
- const insertValues = ast.columns.map((column) => `${sourceAlias}.${this.quoteIdentifier(column.name)}`).join(", ");
3621
+ const insertColumns = ast.columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
3622
+ const insertValues = ast.columns.map((column) => `${sourceAlias}.${this.services.quoteIdentifier(column.name)}`).join(", ");
3539
3623
  branches.push(`WHEN NOT MATCHED THEN INSERT (${insertColumns}) VALUES (${insertValues})`);
3540
- const output = this.compileReturning(ast.returning, ctx);
3624
+ const output = this.services.compileReturning(ast.returning, ctx);
3541
3625
  return `MERGE INTO ${table} USING ${usingSource} AS ${sourceAlias} (${sourceColumns}) ON ${onClause} ${branches.join(" ")}${output}`;
3542
3626
  }
3543
3627
  compileMergeUsingSource(ast, ctx) {
@@ -3545,38 +3629,146 @@ var SqlServerDialect = class extends SqlDialectBase {
3545
3629
  if (!ast.source.rows.length) {
3546
3630
  throw new Error("INSERT ... VALUES requires at least one row.");
3547
3631
  }
3548
- const rows = ast.source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
3632
+ const rows = ast.source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
3549
3633
  return `(VALUES ${rows})`;
3550
3634
  }
3551
- const normalized = this.normalizeSelectAst(ast.source.query);
3552
- const selectSql = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
3635
+ const normalized = this.services.normalizeSelectAst(ast.source.query);
3636
+ const selectSql = this.sources.stripTrailingSemicolon(
3637
+ this.services.compileSelectAst(normalized, ctx)
3638
+ );
3553
3639
  return `(${selectSql})`;
3554
3640
  }
3555
- compileInsertValues(ast, ctx) {
3556
- const source = ast.source;
3557
- if (source.type === "InsertValues") {
3558
- if (!source.rows.length) {
3641
+ compileInsertSource(ast, ctx) {
3642
+ if (ast.source.type === "InsertValues") {
3643
+ if (!ast.source.rows.length) {
3559
3644
  throw new Error("INSERT ... VALUES requires at least one row.");
3560
3645
  }
3561
- const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
3646
+ const values = ast.source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
3562
3647
  return `VALUES ${values}`;
3563
3648
  }
3564
- const normalized = this.normalizeSelectAst(source.query);
3565
- return this.compileSelectAst(normalized, ctx).trim();
3649
+ const normalized = this.services.normalizeSelectAst(ast.source.query);
3650
+ return this.services.compileSelectAst(normalized, ctx).trim();
3651
+ }
3652
+ };
3653
+
3654
+ // src/core/dialect/mssql/select-compiler.ts
3655
+ var MssqlSelectCompiler = class {
3656
+ constructor(services, sources) {
3657
+ this.services = services;
3658
+ this.sources = sources;
3659
+ }
3660
+ compile(ast, ctx) {
3661
+ const hasSetOps = !!(ast.setOps && ast.setOps.length);
3662
+ const ctes = this.compileCtes(ast, ctx);
3663
+ const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
3664
+ const baseSelect = this.compileCore(baseAst, ctx);
3665
+ if (!hasSetOps) return `${ctes}${baseSelect}`;
3666
+ const compound = ast.setOps.map((op) => `${op.operator} ${this.sources.wrapSetOperand(this.services.compileSelectAst(op.query, ctx))}`).join(" ");
3667
+ const orderBy = this.compileOrderBy(ast, ctx);
3668
+ const pagination = this.compilePagination(ast, orderBy);
3669
+ const combined = `${this.sources.wrapSetOperand(baseSelect)} ${compound}`;
3670
+ return `${ctes}${combined}${pagination || orderBy}`;
3671
+ }
3672
+ compileCore(ast, ctx) {
3673
+ const columns = ast.columns.map((column) => {
3674
+ const expr = column.type === "Column" ? `${this.services.quoteIdentifier(column.table)}.${this.services.quoteIdentifier(column.name)}` : this.services.compileOperand(column, ctx);
3675
+ if (!column.alias) return expr;
3676
+ if (column.alias.includes("(")) return column.alias;
3677
+ return `${expr} AS ${this.services.quoteIdentifier(column.alias)}`;
3678
+ }).join(", ");
3679
+ const distinct = ast.distinct ? "DISTINCT " : "";
3680
+ const from = this.sources.compileFrom(ast.from, ctx);
3681
+ const joins = ast.joins.map((join) => {
3682
+ const table = this.sources.compileFrom(join.table, ctx);
3683
+ const condition = this.services.compileExpression(join.condition, ctx);
3684
+ return `${join.kind} JOIN ${table} ON ${condition}`;
3685
+ }).join(" ");
3686
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
3687
+ const groupBy = ast.groupBy && ast.groupBy.length > 0 ? ` GROUP BY ${ast.groupBy.map((term) => this.services.compileOrderingTerm(term, ctx)).join(", ")}` : "";
3688
+ const having = ast.having ? ` HAVING ${this.services.compileExpression(ast.having, ctx)}` : "";
3689
+ const orderBy = this.compileOrderBy(ast, ctx);
3690
+ const pagination = this.compilePagination(ast, orderBy);
3691
+ if (pagination) {
3692
+ return `SELECT ${distinct}${columns} FROM ${from}${joins ? ` ${joins}` : ""}${where}${groupBy}${having}${pagination}`;
3693
+ }
3694
+ return `SELECT ${distinct}${columns} FROM ${from}${joins ? ` ${joins}` : ""}${where}${groupBy}${having}${orderBy}`;
3695
+ }
3696
+ compileOrderBy(ast, ctx) {
3697
+ return OrderByCompiler.compileOrderBy(
3698
+ ast,
3699
+ (term) => this.services.compileOrderingTerm(term, ctx),
3700
+ (order) => this.services.renderOrderByNulls(order),
3701
+ (order) => this.services.renderOrderByCollation(order)
3702
+ );
3703
+ }
3704
+ compilePagination(ast, orderBy) {
3705
+ const hasLimit = ast.limit !== void 0;
3706
+ const hasOffset = ast.offset !== void 0;
3707
+ if (!hasLimit && !hasOffset) return "";
3708
+ const offset = ast.offset ?? 0;
3709
+ let orderClause = orderBy;
3710
+ if (!orderClause) {
3711
+ orderClause = ast.distinct && ast.distinct.length > 0 ? " ORDER BY 1" : " ORDER BY (SELECT NULL)";
3712
+ }
3713
+ let pagination = `${orderClause} OFFSET ${offset} ROWS`;
3714
+ if (hasLimit) pagination += ` FETCH NEXT ${ast.limit} ROWS ONLY`;
3715
+ return pagination;
3566
3716
  }
3567
3717
  compileCtes(ast, ctx) {
3568
3718
  if (!ast.ctes || ast.ctes.length === 0) return "";
3569
- const defs = ast.ctes.map((cte) => {
3570
- const name = this.quoteIdentifier(cte.name);
3571
- const cols = cte.columns ? `(${cte.columns.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
3572
- const query = this.compileSelectAst(this.normalizeSelectAst(cte.query), ctx).trim().replace(/;$/, "");
3573
- return `${name}${cols} AS (${query})`;
3719
+ const definitions = ast.ctes.map((cte) => {
3720
+ const name = this.services.quoteIdentifier(cte.name);
3721
+ const columns = cte.columns ? `(${cte.columns.map((column) => this.services.quoteIdentifier(column)).join(", ")})` : "";
3722
+ const query = this.sources.stripTrailingSemicolon(
3723
+ this.services.compileSelectAst(this.services.normalizeSelectAst(cte.query), ctx)
3724
+ );
3725
+ return `${name}${columns} AS (${query})`;
3574
3726
  }).join(", ");
3575
- return `WITH ${defs} `;
3727
+ return `WITH ${definitions} `;
3728
+ }
3729
+ };
3730
+
3731
+ // src/core/dialect/mssql/update-compiler.ts
3732
+ var MssqlUpdateCompiler = class {
3733
+ constructor(services, sources) {
3734
+ this.services = services;
3735
+ this.sources = sources;
3736
+ this.standardUpdate = new StandardUpdateCompiler(services, sources);
3737
+ }
3738
+ standardUpdate;
3739
+ compile(ast, ctx) {
3740
+ const target = this.sources.compileTableReference(ast.table);
3741
+ const assignments = this.standardUpdate.compileAssignments(ast.set, ast.table, ctx);
3742
+ const output = this.services.compileReturning(ast.returning, ctx);
3743
+ const from = ast.from ? ` FROM ${this.sources.compileFrom(ast.from, ctx)}` : "";
3744
+ const joins = ast.joins ? ast.joins.map((join) => {
3745
+ const table = this.sources.compileFrom(join.table, ctx);
3746
+ const condition = this.services.compileExpression(join.condition, ctx);
3747
+ return ` ${join.kind} JOIN ${table} ON ${condition}`;
3748
+ }).join("") : "";
3749
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
3750
+ return `UPDATE ${target} SET ${assignments}${output}${from}${joins}${where}`;
3751
+ }
3752
+ };
3753
+
3754
+ // src/core/dialect/mssql/compiler-factory.ts
3755
+ var createMssqlCompilerSet = ({ services, sources }) => ({
3756
+ select: new MssqlSelectCompiler(services, sources),
3757
+ insert: new MssqlInsertCompiler(services, sources),
3758
+ update: new MssqlUpdateCompiler(services, sources),
3759
+ delete: new MssqlDeleteCompiler(services, sources)
3760
+ });
3761
+
3762
+ // src/core/dialect/mssql/procedure-compiler.ts
3763
+ var sanitizeVariableSuffix2 = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
3764
+ var toProcedureParamReference = (value) => value.startsWith("@") ? value : `@${value}`;
3765
+ var MssqlProcedureCompiler = class {
3766
+ constructor(services) {
3767
+ this.services = services;
3576
3768
  }
3577
3769
  compileProcedureCall(ast) {
3578
- const ctx = this.createCompilerContext();
3579
- const qualifiedName = ast.ref.schema ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}` : this.quoteIdentifier(ast.ref.name);
3770
+ const ctx = this.services.createCompilerContext();
3771
+ const qualifiedName = ast.ref.schema ? `${this.services.quoteIdentifier(ast.ref.schema)}.${this.services.quoteIdentifier(ast.ref.name)}` : this.services.quoteIdentifier(ast.ref.name);
3580
3772
  const declarations = [];
3581
3773
  const assignments = [];
3582
3774
  const execArgs = [];
@@ -3587,7 +3779,7 @@ var SqlServerDialect = class extends SqlDialectBase {
3587
3779
  if (!param.value) {
3588
3780
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "in".`);
3589
3781
  }
3590
- execArgs.push(`${targetParam} = ${this.compileOperand(param.value, ctx)}`);
3782
+ execArgs.push(`${targetParam} = ${this.services.compileOperand(param.value, ctx)}`);
3591
3783
  return;
3592
3784
  }
3593
3785
  if (!param.dbType) {
@@ -3602,7 +3794,7 @@ var SqlServerDialect = class extends SqlDialectBase {
3602
3794
  if (!param.value) {
3603
3795
  throw new Error(`Procedure parameter "${param.name}" requires a value for direction "inout".`);
3604
3796
  }
3605
- assignments.push(`SET ${variable} = ${this.compileOperand(param.value, ctx)};`);
3797
+ assignments.push(`SET ${variable} = ${this.services.compileOperand(param.value, ctx)};`);
3606
3798
  }
3607
3799
  execArgs.push(`${targetParam} = ${variable} OUTPUT`);
3608
3800
  outVars.push({ variable, name: param.name });
@@ -3613,7 +3805,7 @@ var SqlServerDialect = class extends SqlDialectBase {
3613
3805
  const argsSql = execArgs.length ? ` ${execArgs.join(", ")}` : "";
3614
3806
  statements.push(`EXEC ${qualifiedName}${argsSql};`);
3615
3807
  if (outVars.length) {
3616
- const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.quoteIdentifier(name)}`).join(", ");
3808
+ const selectOut = outVars.map(({ variable, name }) => `${variable} AS ${this.services.quoteIdentifier(name)}`).join(", ");
3617
3809
  statements.push(`SELECT ${selectOut};`);
3618
3810
  }
3619
3811
  return {
@@ -3627,6 +3819,38 @@ var SqlServerDialect = class extends SqlDialectBase {
3627
3819
  }
3628
3820
  };
3629
3821
 
3822
+ // src/core/dialect/mssql/index.ts
3823
+ var SqlServerDialect = class extends SqlDialectBase {
3824
+ dialect = "mssql";
3825
+ procedureCompiler;
3826
+ constructor() {
3827
+ super({
3828
+ functionStrategy: new MssqlFunctionStrategy(),
3829
+ returningStrategy: new MssqlOutputStrategy(),
3830
+ compilerFactory: createMssqlCompilerSet,
3831
+ supportsDmlReturning: true
3832
+ });
3833
+ this.procedureCompiler = new MssqlProcedureCompiler({
3834
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
3835
+ createCompilerContext: () => this.createCompilerContext(),
3836
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx)
3837
+ });
3838
+ }
3839
+ quoteIdentifier(id) {
3840
+ return `[${id}]`;
3841
+ }
3842
+ compileJsonPath(node) {
3843
+ const column = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
3844
+ return `JSON_VALUE(${column}, '${node.path}')`;
3845
+ }
3846
+ formatPlaceholder(index) {
3847
+ return `@p${index}`;
3848
+ }
3849
+ compileProcedureCall(ast) {
3850
+ return this.procedureCompiler.compileProcedureCall(ast);
3851
+ }
3852
+ };
3853
+
3630
3854
  // src/core/dialect/dialect-factory.ts
3631
3855
  var DialectFactory = class {
3632
3856
  static registry = /* @__PURE__ */ new Map();
@@ -22105,13 +22329,26 @@ async function bulkUpsert(session, table, rows, options = {}) {
22105
22329
  MorphMany,
22106
22330
  MorphOne,
22107
22331
  MorphTo,
22332
+ MssqlDeleteCompiler,
22333
+ MssqlInsertCompiler,
22334
+ MssqlOutputStrategy,
22335
+ MssqlProcedureCompiler,
22336
+ MssqlSelectCompiler,
22337
+ MssqlUpdateCompiler,
22108
22338
  MySqlDialect,
22339
+ MySqlProcedureCompiler,
22340
+ MySqlUpsertStrategy,
22109
22341
  NestedSetStrategy,
22342
+ NoReturningStrategy,
22343
+ NoUpsertStrategy,
22110
22344
  Orm,
22111
22345
  OrmSession,
22112
22346
  Pattern,
22113
22347
  Pool,
22114
22348
  PostgresDialect,
22349
+ PostgresProcedureCompiler,
22350
+ PostgresReturningStrategy,
22351
+ PostgresUpsertStrategy,
22115
22352
  PrimaryKey,
22116
22353
  ProcedureCallBuilder,
22117
22354
  PrototypeMaterializationStrategy,
@@ -22120,8 +22357,19 @@ async function bulkUpsert(session, table, rows, options = {}) {
22120
22357
  RelationKinds,
22121
22358
  STANDARD_COLUMN_TYPES,
22122
22359
  SelectQueryBuilder,
22360
+ SqlDialectBase,
22123
22361
  SqlServerDialect,
22124
22362
  SqliteDialect,
22363
+ SqliteReturningStrategy,
22364
+ SqliteUpsertStrategy,
22365
+ StandardDeleteCompiler,
22366
+ StandardInsertCompiler,
22367
+ StandardLimitOffsetPagination,
22368
+ StandardReturningStrategy,
22369
+ StandardSelectCompiler,
22370
+ StandardSqlSourceCompiler,
22371
+ StandardTableFunctionStrategy,
22372
+ StandardUpdateCompiler,
22125
22373
  StringTypeStrategy,
22126
22374
  TagIndex,
22127
22375
  Title,
@@ -22208,6 +22456,7 @@ async function bulkUpsert(session, table, rows, options = {}) {
22208
22456
  createEntityFromRow,
22209
22457
  createEntityProxy,
22210
22458
  createExecutorFromQueryRunner,
22459
+ createMssqlCompilerSet,
22211
22460
  createMssqlExecutor,
22212
22461
  createMysqlExecutor,
22213
22462
  createPooledExecutorFactory,