metal-orm 1.1.22 → 1.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1314,268 +1314,40 @@ var StandardTableFunctionStrategy = class {
1314
1314
  }
1315
1315
  };
1316
1316
 
1317
- // src/core/dialect/abstract.ts
1318
- var Dialect = class _Dialect {
1319
- /**
1320
- * Compiles a SELECT query AST to SQL
1321
- * @param ast - Query AST to compile
1322
- * @returns Compiled query with SQL and parameters
1323
- */
1324
- compileSelect(ast) {
1325
- const ctx = this.createCompilerContext();
1326
- const normalized = this.normalizeSelectAst(ast);
1327
- const rawSql = this.compileSelectAst(normalized, ctx).trim();
1328
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1329
- return {
1330
- sql,
1331
- params: [...ctx.params]
1332
- };
1333
- }
1334
- compileInsert(ast) {
1335
- const ctx = this.createCompilerContext();
1336
- const rawSql = this.compileInsertAst(ast, ctx).trim();
1337
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1338
- return {
1339
- sql,
1340
- params: [...ctx.params]
1341
- };
1342
- }
1343
- compileUpdate(ast) {
1344
- const ctx = this.createCompilerContext();
1345
- const rawSql = this.compileUpdateAst(ast, ctx).trim();
1346
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1347
- return {
1348
- sql,
1349
- params: [...ctx.params]
1350
- };
1351
- }
1352
- compileDelete(ast) {
1353
- const ctx = this.createCompilerContext();
1354
- const rawSql = this.compileDeleteAst(ast, ctx).trim();
1355
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1356
- return {
1357
- sql,
1358
- params: [...ctx.params]
1359
- };
1360
- }
1361
- supportsDmlReturningClause() {
1362
- return false;
1363
- }
1364
- /**
1365
- * Compiles a WHERE clause
1366
- * @param where - WHERE expression
1367
- * @param ctx - Compiler context
1368
- * @returns SQL WHERE clause or empty string
1369
- */
1370
- compileWhere(where, ctx) {
1371
- if (!where) return "";
1372
- return ` WHERE ${this.compileExpression(where, ctx)}`;
1373
- }
1374
- compileReturning(returning, _ctx) {
1375
- void _ctx;
1376
- if (!returning || returning.length === 0) return "";
1377
- throw new Error("RETURNING is not supported by this dialect.");
1378
- }
1379
- /**
1380
- * Generates subquery for EXISTS expressions
1381
- * Rule: Always forces SELECT 1, ignoring column list
1382
- * Maintains FROM, JOINs, WHERE, GROUP BY, ORDER BY, LIMIT/OFFSET
1383
- * Does not add ';' at the end
1384
- * @param ast - Query AST
1385
- * @param ctx - Compiler context
1386
- * @returns SQL for EXISTS subquery
1387
- */
1388
- compileSelectForExists(ast, ctx) {
1389
- const normalized = this.normalizeSelectAst(ast);
1390
- const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1391
- if (normalized.setOps && normalized.setOps.length > 0) {
1392
- return `SELECT 1 FROM (${full}) AS _exists`;
1393
- }
1394
- const upper2 = full.toUpperCase();
1395
- const fromIndex = upper2.indexOf(" FROM ");
1396
- if (fromIndex === -1) {
1397
- return full;
1398
- }
1399
- const tail = full.slice(fromIndex);
1400
- return `SELECT 1${tail}`;
1401
- }
1402
- /**
1403
- * Creates a new compiler context
1404
- * @returns Compiler context with parameter management
1405
- */
1406
- createCompilerContext() {
1407
- const params = [];
1408
- let counter = 0;
1409
- return {
1410
- params,
1411
- addParameter: (value) => {
1412
- counter += 1;
1413
- params.push(value);
1414
- return this.formatPlaceholder(counter);
1415
- }
1416
- };
1417
- }
1418
- /**
1419
- * Formats a parameter placeholder
1420
- * @param index - Parameter index
1421
- * @returns Formatted placeholder string
1422
- */
1423
- formatPlaceholder(_index) {
1424
- void _index;
1425
- return "?";
1426
- }
1427
- /**
1428
- * Whether the current dialect supports a given set operation.
1429
- * Override in concrete dialects to restrict support.
1430
- */
1431
- supportsSetOperation(_kind) {
1432
- void _kind;
1433
- return true;
1434
- }
1435
- /**
1436
- * Validates set-operation semantics:
1437
- * - Ensures the dialect supports requested operators.
1438
- * - Enforces that only the outermost compound query may have ORDER/LIMIT/OFFSET.
1439
- * @param ast - Query to validate
1440
- * @param isOutermost - Whether this node is the outermost compound query
1441
- */
1442
- validateSetOperations(ast, isOutermost = true) {
1443
- const hasSetOps = !!(ast.setOps && ast.setOps.length);
1444
- if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
1445
- throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
1446
- }
1447
- if (hasSetOps) {
1448
- for (const op of ast.setOps) {
1449
- if (!this.supportsSetOperation(op.operator)) {
1450
- throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
1451
- }
1452
- this.validateSetOperations(op.query, false);
1453
- }
1454
- }
1455
- }
1456
- /**
1457
- * Hoists CTEs from set-operation operands to the outermost query so WITH appears once.
1458
- * @param ast - Query AST
1459
- * @returns Normalized AST without inner CTEs and a list of hoisted CTEs
1460
- */
1461
- hoistCtes(ast) {
1462
- let hoisted = [];
1463
- const normalizedSetOps = ast.setOps?.map((op) => {
1464
- const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
1465
- const childCtes = child.ctes ?? [];
1466
- if (childCtes.length) {
1467
- hoisted = hoisted.concat(childCtes);
1468
- }
1469
- hoisted = hoisted.concat(childHoisted);
1470
- const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
1471
- return { ...op, query: queryWithoutCtes };
1472
- });
1473
- const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
1474
- return { normalized, hoistedCtes: hoisted };
1475
- }
1476
- /**
1477
- * Normalizes a SELECT AST before compilation (validation + CTE hoisting).
1478
- * @param ast - Query AST
1479
- * @returns Normalized query AST
1480
- */
1481
- normalizeSelectAst(ast) {
1482
- this.validateSetOperations(ast, true);
1483
- const { normalized, hoistedCtes } = this.hoistCtes(ast);
1484
- const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
1485
- return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
1486
- }
1487
- expressionCompilers;
1488
- operandCompilers;
1489
- functionStrategy;
1490
- tableFunctionStrategy;
1491
- constructor(functionStrategy, tableFunctionStrategy) {
1492
- this.expressionCompilers = /* @__PURE__ */ new Map();
1493
- this.operandCompilers = /* @__PURE__ */ new Map();
1494
- this.functionStrategy = functionStrategy || new StandardFunctionStrategy();
1495
- this.tableFunctionStrategy = tableFunctionStrategy || new StandardTableFunctionStrategy();
1317
+ // src/core/dialect/base/expression-compiler-registry.ts
1318
+ var ExpressionCompilerRegistry = class {
1319
+ constructor(host) {
1320
+ this.host = host;
1496
1321
  this.registerDefaultOperandCompilers();
1497
1322
  this.registerDefaultExpressionCompilers();
1498
1323
  }
1499
- /**
1500
- * Creates a new Dialect instance (for testing purposes)
1501
- * @param functionStrategy - Optional function strategy
1502
- * @returns New Dialect instance
1503
- */
1504
- static create(functionStrategy, tableFunctionStrategy) {
1505
- class TestDialect extends _Dialect {
1506
- dialect = "sqlite";
1507
- quoteIdentifier(id) {
1508
- return `"${id}"`;
1509
- }
1510
- compileSelectAst() {
1511
- throw new Error("Not implemented");
1512
- }
1513
- compileInsertAst() {
1514
- throw new Error("Not implemented");
1515
- }
1516
- compileUpdateAst() {
1517
- throw new Error("Not implemented");
1518
- }
1519
- compileDeleteAst() {
1520
- throw new Error("Not implemented");
1521
- }
1522
- compileProcedureCall() {
1523
- throw new Error("Not implemented");
1524
- }
1525
- }
1526
- return new TestDialect(functionStrategy, tableFunctionStrategy);
1527
- }
1528
- /**
1529
- * Registers an expression compiler for a specific node type
1530
- * @param type - Expression node type
1531
- * @param compiler - Compiler function
1532
- */
1324
+ expressionCompilers = /* @__PURE__ */ new Map();
1325
+ operandCompilers = /* @__PURE__ */ new Map();
1533
1326
  registerExpressionCompiler(type, compiler) {
1534
1327
  this.expressionCompilers.set(type, compiler);
1535
1328
  }
1536
- /**
1537
- * Registers an operand compiler for a specific node type
1538
- * @param type - Operand node type
1539
- * @param compiler - Compiler function
1540
- */
1541
1329
  registerOperandCompiler(type, compiler) {
1542
1330
  this.operandCompilers.set(type, compiler);
1543
1331
  }
1544
- /**
1545
- * Compiles an expression node
1546
- * @param node - Expression node to compile
1547
- * @param ctx - Compiler context
1548
- * @returns Compiled SQL expression
1549
- */
1550
1332
  compileExpression(node, ctx) {
1551
1333
  const compiler = this.expressionCompilers.get(node.type);
1552
1334
  if (!compiler) {
1553
- throw new Error(`Unsupported expression node type "${node.type}" for ${this.constructor.name}`);
1335
+ throw new Error(`Unsupported expression node type "${node.type}" for ${this.host.describe()}`);
1554
1336
  }
1555
1337
  return compiler(node, ctx);
1556
1338
  }
1557
- /**
1558
- * Compiles an operand node
1559
- * @param node - Operand node to compile
1560
- * @param ctx - Compiler context
1561
- * @returns Compiled SQL operand
1562
- */
1563
1339
  compileOperand(node, ctx) {
1564
1340
  const compiler = this.operandCompilers.get(node.type);
1565
1341
  if (!compiler) {
1566
- throw new Error(`Unsupported operand node type "${node.type}" for ${this.constructor.name}`);
1342
+ throw new Error(`Unsupported operand node type "${node.type}" for ${this.host.describe()}`);
1567
1343
  }
1568
1344
  return compiler(node, ctx);
1569
1345
  }
1570
- /**
1571
- * Compiles an ordering term (operand, expression, or alias reference).
1572
- */
1573
1346
  compileOrderingTerm(term, ctx) {
1574
1347
  if (isOperandNode(term)) {
1575
1348
  return this.compileOperand(term, ctx);
1576
1349
  }
1577
- const expr = this.compileExpression(term, ctx);
1578
- return `(${expr})`;
1350
+ return `(${this.compileExpression(term, ctx)})`;
1579
1351
  }
1580
1352
  registerDefaultExpressionCompilers() {
1581
1353
  this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
@@ -1610,11 +1382,11 @@ var Dialect = class _Dialect {
1610
1382
  const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
1611
1383
  return `${left2} ${inExpr.operator} (${values})`;
1612
1384
  }
1613
- const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1385
+ const subquerySql = this.host.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1614
1386
  return `${left2} ${inExpr.operator} (${subquerySql})`;
1615
1387
  });
1616
1388
  this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
1617
- const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
1389
+ const subquerySql = this.host.compileSelectForExists(existsExpr.subquery, ctx);
1618
1390
  return `${existsExpr.operator} (${subquerySql})`;
1619
1391
  });
1620
1392
  this.registerExpressionCompiler("BetweenExpression", (betweenExpr, ctx) => {
@@ -1640,25 +1412,28 @@ var Dialect = class _Dialect {
1640
1412
  });
1641
1413
  }
1642
1414
  registerDefaultOperandCompilers() {
1643
- this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1644
- this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1645
- void _ctx;
1646
- return this.quoteIdentifier(alias.name);
1647
- });
1648
- this.registerOperandCompiler("Column", (column, _ctx) => {
1649
- void _ctx;
1650
- return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
1651
- });
1415
+ this.registerOperandCompiler(
1416
+ "Literal",
1417
+ (literal, ctx) => ctx.addParameter(literal.value)
1418
+ );
1419
+ this.registerOperandCompiler(
1420
+ "AliasRef",
1421
+ (alias) => this.host.quoteIdentifier(alias.name)
1422
+ );
1423
+ this.registerOperandCompiler(
1424
+ "Column",
1425
+ (column) => `${this.host.quoteIdentifier(column.table)}.${this.host.quoteIdentifier(column.name)}`
1426
+ );
1652
1427
  this.registerOperandCompiler(
1653
1428
  "Function",
1654
- (fnNode, ctx) => this.compileFunctionOperand(fnNode, ctx)
1429
+ (fnNode, ctx) => this.host.compileFunctionOperand(fnNode, ctx)
1430
+ );
1431
+ this.registerOperandCompiler(
1432
+ "JsonPath",
1433
+ (path) => this.host.compileJsonPath(path)
1655
1434
  );
1656
- this.registerOperandCompiler("JsonPath", (path, _ctx) => {
1657
- void _ctx;
1658
- return this.compileJsonPath(path);
1659
- });
1660
1435
  this.registerOperandCompiler("ScalarSubquery", (node, ctx) => {
1661
- const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
1436
+ const sql = this.host.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
1662
1437
  return `(${sql})`;
1663
1438
  });
1664
1439
  this.registerOperandCompiler("CaseExpression", (node, ctx) => {
@@ -1685,7 +1460,7 @@ var Dialect = class _Dialect {
1685
1460
  const parts = [];
1686
1461
  if (node.partitionBy && node.partitionBy.length > 0) {
1687
1462
  const partitionClause = "PARTITION BY " + node.partitionBy.map(
1688
- (col2) => `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`
1463
+ (col2) => `${this.host.quoteIdentifier(col2.table)}.${this.host.quoteIdentifier(col2.name)}`
1689
1464
  ).join(", ");
1690
1465
  parts.push(partitionClause);
1691
1466
  }
@@ -1717,14 +1492,164 @@ var Dialect = class _Dialect {
1717
1492
  return `${expr} COLLATE ${node.collation}`;
1718
1493
  });
1719
1494
  }
1720
- // Default fallback, should be overridden by dialects if supported
1495
+ };
1496
+
1497
+ // src/core/dialect/base/select-ast-normalizer.ts
1498
+ var SelectAstNormalizer = class {
1499
+ constructor(supportsSetOperation) {
1500
+ this.supportsSetOperation = supportsSetOperation;
1501
+ }
1502
+ normalize(ast) {
1503
+ this.validateSetOperations(ast, true);
1504
+ const { normalized, hoistedCtes } = this.hoistCtes(ast);
1505
+ const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
1506
+ return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
1507
+ }
1508
+ validateSetOperations(ast, isOutermost) {
1509
+ const hasSetOps = !!(ast.setOps && ast.setOps.length);
1510
+ if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
1511
+ throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
1512
+ }
1513
+ if (!hasSetOps) return;
1514
+ for (const op of ast.setOps) {
1515
+ if (!this.supportsSetOperation(op.operator)) {
1516
+ throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
1517
+ }
1518
+ this.validateSetOperations(op.query, false);
1519
+ }
1520
+ }
1521
+ hoistCtes(ast) {
1522
+ let hoisted = [];
1523
+ const normalizedSetOps = ast.setOps?.map((op) => {
1524
+ const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
1525
+ const childCtes = child.ctes ?? [];
1526
+ if (childCtes.length) hoisted = hoisted.concat(childCtes);
1527
+ hoisted = hoisted.concat(childHoisted);
1528
+ const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
1529
+ return { ...op, query: queryWithoutCtes };
1530
+ });
1531
+ const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
1532
+ return { normalized, hoistedCtes: hoisted };
1533
+ }
1534
+ };
1535
+
1536
+ // src/core/dialect/abstract.ts
1537
+ var DialectBase = class _DialectBase {
1538
+ expressionCompilerRegistry;
1539
+ selectAstNormalizer;
1540
+ functionStrategy;
1541
+ tableFunctionStrategy;
1542
+ constructor(functionStrategy, tableFunctionStrategy) {
1543
+ this.functionStrategy = functionStrategy ?? new StandardFunctionStrategy();
1544
+ this.tableFunctionStrategy = tableFunctionStrategy ?? new StandardTableFunctionStrategy();
1545
+ this.selectAstNormalizer = new SelectAstNormalizer((kind) => this.supportsSetOperation(kind));
1546
+ this.expressionCompilerRegistry = new ExpressionCompilerRegistry({
1547
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
1548
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
1549
+ compileSelectForExists: (ast, ctx) => this.compileSelectForExists(ast, ctx),
1550
+ compileJsonPath: (node) => this.compileJsonPath(node),
1551
+ compileFunctionOperand: (node, ctx) => this.compileFunctionOperand(node, ctx),
1552
+ describe: () => this.constructor.name
1553
+ });
1554
+ }
1555
+ compileSelect(ast) {
1556
+ const ctx = this.createCompilerContext();
1557
+ const normalized = this.normalizeSelectAst(ast);
1558
+ const rawSql = this.compileSelectAst(normalized, ctx).trim();
1559
+ return {
1560
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1561
+ params: [...ctx.params]
1562
+ };
1563
+ }
1564
+ compileInsert(ast) {
1565
+ const ctx = this.createCompilerContext();
1566
+ const rawSql = this.compileInsertAst(ast, ctx).trim();
1567
+ return {
1568
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1569
+ params: [...ctx.params]
1570
+ };
1571
+ }
1572
+ compileUpdate(ast) {
1573
+ const ctx = this.createCompilerContext();
1574
+ const rawSql = this.compileUpdateAst(ast, ctx).trim();
1575
+ return {
1576
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1577
+ params: [...ctx.params]
1578
+ };
1579
+ }
1580
+ compileDelete(ast) {
1581
+ const ctx = this.createCompilerContext();
1582
+ const rawSql = this.compileDeleteAst(ast, ctx).trim();
1583
+ return {
1584
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1585
+ params: [...ctx.params]
1586
+ };
1587
+ }
1588
+ supportsDmlReturningClause() {
1589
+ return false;
1590
+ }
1591
+ compileWhere(where, ctx) {
1592
+ if (!where) return "";
1593
+ return ` WHERE ${this.compileExpression(where, ctx)}`;
1594
+ }
1595
+ compileReturning(returning, _ctx) {
1596
+ void _ctx;
1597
+ if (!returning || returning.length === 0) return "";
1598
+ throw new Error("RETURNING is not supported by this dialect.");
1599
+ }
1600
+ compileSelectForExists(ast, ctx) {
1601
+ const normalized = this.normalizeSelectAst(ast);
1602
+ const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1603
+ if (normalized.setOps && normalized.setOps.length > 0) {
1604
+ return `SELECT 1 FROM (${full}) AS _exists`;
1605
+ }
1606
+ const upper2 = full.toUpperCase();
1607
+ const fromIndex = upper2.indexOf(" FROM ");
1608
+ if (fromIndex === -1) return full;
1609
+ return `SELECT 1${full.slice(fromIndex)}`;
1610
+ }
1611
+ createCompilerContext() {
1612
+ const params = [];
1613
+ let counter = 0;
1614
+ return {
1615
+ params,
1616
+ addParameter: (value) => {
1617
+ counter += 1;
1618
+ params.push(value);
1619
+ return this.formatPlaceholder(counter);
1620
+ }
1621
+ };
1622
+ }
1623
+ formatPlaceholder(_index) {
1624
+ void _index;
1625
+ return "?";
1626
+ }
1627
+ supportsSetOperation(_kind) {
1628
+ void _kind;
1629
+ return true;
1630
+ }
1631
+ normalizeSelectAst(ast) {
1632
+ return this.selectAstNormalizer.normalize(ast);
1633
+ }
1634
+ registerExpressionCompiler(type, compiler) {
1635
+ this.expressionCompilerRegistry.registerExpressionCompiler(type, compiler);
1636
+ }
1637
+ registerOperandCompiler(type, compiler) {
1638
+ this.expressionCompilerRegistry.registerOperandCompiler(type, compiler);
1639
+ }
1640
+ compileExpression(node, ctx) {
1641
+ return this.expressionCompilerRegistry.compileExpression(node, ctx);
1642
+ }
1643
+ compileOperand(node, ctx) {
1644
+ return this.expressionCompilerRegistry.compileOperand(node, ctx);
1645
+ }
1646
+ compileOrderingTerm(term, ctx) {
1647
+ return this.expressionCompilerRegistry.compileOrderingTerm(term, ctx);
1648
+ }
1721
1649
  compileJsonPath(_node) {
1722
1650
  void _node;
1723
1651
  throw new Error("JSON Path not supported by this dialect");
1724
1652
  }
1725
- /**
1726
- * Compiles a function operand, using the dialect's function strategy.
1727
- */
1728
1653
  compileFunctionOperand(fnNode, ctx) {
1729
1654
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
1730
1655
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
@@ -1737,115 +1662,175 @@ var Dialect = class _Dialect {
1737
1662
  }
1738
1663
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
1739
1664
  }
1665
+ /** Creates a minimal dialect implementation for isolated compiler tests. */
1666
+ static create(functionStrategy, tableFunctionStrategy) {
1667
+ class TestDialect extends _DialectBase {
1668
+ dialect = "sqlite";
1669
+ quoteIdentifier(id) {
1670
+ return `"${id}"`;
1671
+ }
1672
+ compileSelectAst() {
1673
+ throw new Error("Not implemented");
1674
+ }
1675
+ compileInsertAst() {
1676
+ throw new Error("Not implemented");
1677
+ }
1678
+ compileUpdateAst() {
1679
+ throw new Error("Not implemented");
1680
+ }
1681
+ compileDeleteAst() {
1682
+ throw new Error("Not implemented");
1683
+ }
1684
+ }
1685
+ return new TestDialect(functionStrategy, tableFunctionStrategy);
1686
+ }
1740
1687
  };
1741
1688
 
1742
- // src/core/dialect/base/function-table-formatter.ts
1743
- var FunctionTableFormatter = class {
1689
+ // src/core/dialect/base/pagination-strategy.ts
1690
+ var StandardLimitOffsetPagination = class {
1744
1691
  /**
1745
- * Formats a function table node into SQL syntax.
1746
- * @param fn - The function table node containing schema, name, args, and aliases.
1747
- * @param ctx - Optional compiler context for operand compilation.
1748
- * @param dialect - The dialect instance for compiling operands.
1749
- * @returns SQL function table expression (e.g., "LATERAL schema.func(args) WITH ORDINALITY AS alias(col1, col2)").
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.
1750
1696
  */
1751
- static format(fn9, ctx, dialect) {
1752
- const schemaPart = this.formatSchema(fn9, dialect);
1753
- const args = this.formatArgs(fn9, ctx, dialect);
1754
- const base = this.formatBase(fn9, schemaPart, args);
1755
- const lateral = this.formatLateral(fn9);
1756
- const alias = this.formatAlias(fn9, dialect);
1757
- const colAliases = this.formatColumnAliases(fn9, dialect);
1758
- return `${lateral}${base}${alias}${colAliases}`;
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(" ")}` : "";
1759
1702
  }
1703
+ };
1704
+
1705
+ // src/core/dialect/base/returning-strategy.ts
1706
+ var NoReturningStrategy = class {
1760
1707
  /**
1761
- * Formats the schema prefix for the function name.
1762
- * @param fn - The function table node.
1763
- * @param dialect - The dialect instance for quoting identifiers.
1764
- * @returns Schema prefix (e.g., "schema.") or empty string.
1765
- * @internal
1708
+ * Throws an error as RETURNING is not supported.
1709
+ * @param returning - Columns to return (causes error if non-empty).
1710
+ * @param _ctx - Compiler context (unused).
1711
+ * @throws Error indicating RETURNING is not supported.
1766
1712
  */
1767
- static formatSchema(fn9, dialect) {
1768
- if (!fn9.schema) return "";
1769
- const quoted = dialect ? dialect.quoteIdentifier(fn9.schema) : fn9.schema;
1770
- return `${quoted}.`;
1713
+ compileReturning(returning, _ctx) {
1714
+ void _ctx;
1715
+ if (!returning || returning.length === 0) return "";
1716
+ throw new Error("RETURNING is not supported by this dialect.");
1771
1717
  }
1772
1718
  /**
1773
- * Formats function arguments into SQL syntax.
1774
- * @param fn - The function table node containing arguments.
1775
- * @param ctx - Optional compiler context for operand compilation.
1776
- * @param dialect - The dialect instance for compiling operands.
1777
- * @returns Comma-separated function arguments.
1778
- * @internal
1719
+ * Formats column names for RETURNING clause.
1720
+ * @param returning - Columns to format.
1721
+ * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
1722
+ * @returns Simple comma-separated column names.
1779
1723
  */
1780
- static formatArgs(fn9, ctx, dialect) {
1781
- return (fn9.args || []).map((a) => {
1782
- if (ctx && dialect) {
1783
- return dialect.compileOperand(a, ctx);
1784
- }
1785
- return String(a);
1724
+ formatReturningColumns(returning, quoteIdentifier) {
1725
+ return returning.map((column) => {
1726
+ const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
1727
+ const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
1728
+ return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
1786
1729
  }).join(", ");
1787
1730
  }
1788
- /**
1789
- * Formats the base function call with WITH ORDINALITY if present.
1790
- * @param fn - The function table node.
1791
- * @param schemaPart - Formatted schema prefix.
1792
- * @param args - Formatted function arguments.
1793
- * @param dialect - The dialect instance for quoting identifiers.
1794
- * @returns Base function call expression (e.g., "schema.func(args) WITH ORDINALITY").
1795
- * @internal
1796
- */
1731
+ };
1732
+
1733
+ // src/core/dialect/base/function-table-formatter.ts
1734
+ var FunctionTableFormatter = class {
1735
+ static format(fn9, ctx, formatter) {
1736
+ const schemaPart = this.formatSchema(fn9, formatter);
1737
+ const args = this.formatArgs(fn9, ctx, formatter);
1738
+ const base = this.formatBase(fn9, schemaPart, args);
1739
+ const lateral = this.formatLateral(fn9);
1740
+ const alias = this.formatAlias(fn9, formatter);
1741
+ const colAliases = this.formatColumnAliases(fn9, formatter);
1742
+ return `${lateral}${base}${alias}${colAliases}`;
1743
+ }
1744
+ static formatSchema(fn9, formatter) {
1745
+ if (!fn9.schema) return "";
1746
+ return `${formatter.quoteIdentifier(fn9.schema)}.`;
1747
+ }
1748
+ static formatArgs(fn9, ctx, formatter) {
1749
+ return (fn9.args || []).map((arg) => ctx ? formatter.compileOperand(arg, ctx) : String(arg)).join(", ");
1750
+ }
1797
1751
  static formatBase(fn9, schemaPart, args) {
1798
1752
  const ordinality = fn9.withOrdinality ? " WITH ORDINALITY" : "";
1799
1753
  return `${schemaPart}${fn9.name}(${args})${ordinality}`;
1800
1754
  }
1801
- /**
1802
- * Formats the LATERAL keyword if present.
1803
- * @param fn - The function table node.
1804
- * @returns "LATERAL " or empty string.
1805
- * @internal
1806
- */
1807
1755
  static formatLateral(fn9) {
1808
1756
  return fn9.lateral ? "LATERAL " : "";
1809
1757
  }
1810
- /**
1811
- * Formats the table alias for the function table.
1812
- * @param fn - The function table node.
1813
- * @param dialect - The dialect instance for quoting identifiers.
1814
- * @returns " AS alias" or empty string.
1815
- * @internal
1816
- */
1817
- static formatAlias(fn9, dialect) {
1758
+ static formatAlias(fn9, formatter) {
1818
1759
  if (!fn9.alias) return "";
1819
- const quoted = dialect ? dialect.quoteIdentifier(fn9.alias) : fn9.alias;
1820
- return ` AS ${quoted}`;
1821
- }
1822
- /**
1823
- * Formats column aliases for the function table result columns.
1824
- * @param fn - The function table node containing column aliases.
1825
- * @param dialect - The dialect instance for quoting identifiers.
1826
- * @returns "(col1, col2, ...)" or empty string.
1827
- * @internal
1828
- */
1829
- static formatColumnAliases(fn9, dialect) {
1760
+ return ` AS ${formatter.quoteIdentifier(fn9.alias)}`;
1761
+ }
1762
+ static formatColumnAliases(fn9, formatter) {
1830
1763
  if (!fn9.columnAliases || !fn9.columnAliases.length) return "";
1831
- const aliases = fn9.columnAliases.map((col2) => dialect ? dialect.quoteIdentifier(col2) : col2).join(", ");
1764
+ const aliases = fn9.columnAliases.map((col2) => formatter.quoteIdentifier(col2)).join(", ");
1832
1765
  return `(${aliases})`;
1833
1766
  }
1834
1767
  };
1835
1768
 
1836
- // src/core/dialect/base/pagination-strategy.ts
1837
- var StandardLimitOffsetPagination = class {
1838
- /**
1839
- * Compiles LIMIT/OFFSET pagination clause.
1840
- * @param limit - The maximum number of rows to return.
1841
- * @param offset - The number of rows to skip.
1842
- * @returns SQL pagination clause with LIMIT and/or OFFSET.
1843
- */
1844
- compilePagination(limit, offset) {
1845
- const parts = [];
1846
- if (limit !== void 0) parts.push(`LIMIT ${limit}`);
1847
- if (offset !== void 0) parts.push(`OFFSET ${offset}`);
1848
- return parts.length ? ` ${parts.join(" ")}` : "";
1769
+ // src/core/dialect/base/standard-sql-source-compiler.ts
1770
+ var StandardSqlSourceCompiler = class {
1771
+ constructor(services) {
1772
+ this.services = services;
1773
+ }
1774
+ compileFrom(source, ctx) {
1775
+ if (source.type === "FunctionTable") return this.compileFunctionTable(source, ctx);
1776
+ if (source.type === "DerivedTable") return this.compileDerivedTable(source, ctx);
1777
+ return this.compileTableSource(source);
1778
+ }
1779
+ compileFunctionTable(fn9, ctx) {
1780
+ const key = fn9.key ?? fn9.name;
1781
+ if (ctx) {
1782
+ const renderer = this.services.getTableFunctionStrategy().getRenderer(key);
1783
+ if (renderer) {
1784
+ const compiledArgs = (fn9.args ?? []).map((arg) => this.services.compileOperand(arg, ctx));
1785
+ return renderer({
1786
+ node: fn9,
1787
+ compiledArgs,
1788
+ compileOperand: (operand) => this.services.compileOperand(operand, ctx),
1789
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id)
1790
+ });
1791
+ }
1792
+ if (fn9.key) {
1793
+ throw new Error(
1794
+ `Table function "${key}" is not supported by dialect "${this.services.getDialectName()}".`
1795
+ );
1796
+ }
1797
+ }
1798
+ return FunctionTableFormatter.format(fn9, ctx, {
1799
+ quoteIdentifier: (id) => this.services.quoteIdentifier(id),
1800
+ compileOperand: (node, compilerContext) => this.services.compileOperand(node, compilerContext)
1801
+ });
1802
+ }
1803
+ compileDerivedTable(table, ctx) {
1804
+ if (!table.alias) throw new Error("Derived tables must have an alias.");
1805
+ if (!ctx) throw new Error("Derived table compilation requires a compiler context.");
1806
+ const normalized = this.services.normalizeSelectAst(table.query);
1807
+ const subquery = this.services.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1808
+ const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((column) => this.services.quoteIdentifier(column)).join(", ")})` : "";
1809
+ return `(${subquery}) AS ${this.services.quoteIdentifier(table.alias)}${columns}`;
1810
+ }
1811
+ compileTableSource(table) {
1812
+ if (table.type === "FunctionTable") return this.compileFunctionTable(table);
1813
+ if (table.type === "DerivedTable") {
1814
+ throw new Error("Derived table compilation requires a compiler context.");
1815
+ }
1816
+ const base = this.compileTableName(table);
1817
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
1818
+ }
1819
+ compileTableName(table) {
1820
+ if (table.schema) {
1821
+ return `${this.services.quoteIdentifier(table.schema)}.${this.services.quoteIdentifier(table.name)}`;
1822
+ }
1823
+ return this.services.quoteIdentifier(table.name);
1824
+ }
1825
+ compileTableReference(table) {
1826
+ const base = this.compileTableName(table);
1827
+ return table.alias ? `${base} AS ${this.services.quoteIdentifier(table.alias)}` : base;
1828
+ }
1829
+ stripTrailingSemicolon(sql) {
1830
+ return sql.trim().replace(/;$/, "");
1831
+ }
1832
+ wrapSetOperand(sql) {
1833
+ return `(${this.stripTrailingSemicolon(sql)})`;
1849
1834
  }
1850
1835
  };
1851
1836
 
@@ -1875,34 +1860,6 @@ var CteCompiler = class {
1875
1860
  }
1876
1861
  };
1877
1862
 
1878
- // src/core/dialect/base/returning-strategy.ts
1879
- var NoReturningStrategy = class {
1880
- /**
1881
- * Throws an error as RETURNING is not supported.
1882
- * @param returning - Columns to return (causes error if non-empty).
1883
- * @param _ctx - Compiler context (unused).
1884
- * @throws Error indicating RETURNING is not supported.
1885
- */
1886
- compileReturning(returning, _ctx) {
1887
- void _ctx;
1888
- if (!returning || returning.length === 0) return "";
1889
- throw new Error("RETURNING is not supported by this dialect.");
1890
- }
1891
- /**
1892
- * Formats column names for RETURNING clause.
1893
- * @param returning - Columns to format.
1894
- * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
1895
- * @returns Simple comma-separated column names.
1896
- */
1897
- formatReturningColumns(returning, quoteIdentifier) {
1898
- return returning.map((column) => {
1899
- const tablePart = column.table ? `${quoteIdentifier(column.table)}.` : "";
1900
- const aliasPart = column.alias ? ` AS ${quoteIdentifier(column.alias)}` : "";
1901
- return `${tablePart}${quoteIdentifier(column.name)}${aliasPart}`;
1902
- }).join(", ");
1903
- }
1904
- };
1905
-
1906
1863
  // src/core/dialect/base/join-compiler.ts
1907
1864
  var JoinCompiler = class {
1908
1865
  static compileJoins(joins, ctx, compileFrom, compileExpression) {
@@ -1953,113 +1910,229 @@ var OrderByCompiler = class {
1953
1910
  }
1954
1911
  };
1955
1912
 
1956
- // src/core/dialect/base/sql-dialect.ts
1957
- var SqlDialectBase = class extends Dialect {
1958
- paginationStrategy = new StandardLimitOffsetPagination();
1959
- returningStrategy = new NoReturningStrategy();
1960
- compileSelectAst(ast, ctx) {
1913
+ // src/core/dialect/base/standard-select-compiler.ts
1914
+ var StandardSelectCompiler = class {
1915
+ constructor(services, sources) {
1916
+ this.services = services;
1917
+ this.sources = sources;
1918
+ }
1919
+ compile(ast, ctx) {
1961
1920
  const hasSetOps = !!(ast.setOps && ast.setOps.length);
1962
1921
  const ctes = CteCompiler.compileCtes(
1963
1922
  ast,
1964
1923
  ctx,
1965
- this.quoteIdentifier.bind(this),
1966
- this.compileSelectAst.bind(this),
1967
- this.normalizeSelectAst?.bind(this) ?? ((a) => a),
1968
- this.stripTrailingSemicolon.bind(this)
1924
+ (id) => this.services.quoteIdentifier(id),
1925
+ (query, compilerContext) => this.services.compileSelectAst(query, compilerContext),
1926
+ (query) => this.services.normalizeSelectAst(query),
1927
+ (sql) => this.sources.stripTrailingSemicolon(sql)
1969
1928
  );
1970
1929
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
1971
- const baseSelect = this.compileSelectCore(baseAst, ctx);
1972
- if (!hasSetOps) {
1973
- return `${ctes}${baseSelect}`;
1974
- }
1975
- return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
1930
+ const baseSelect = this.compileCore(baseAst, ctx);
1931
+ if (!hasSetOps) return `${ctes}${baseSelect}`;
1932
+ const compound = ast.setOps.map((op) => `${op.operator} ${this.sources.wrapSetOperand(this.services.compileSelectAst(op.query, ctx))}`).join(" ");
1933
+ const orderBy = this.compileOrderBy(ast, ctx);
1934
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
1935
+ const combined = `${this.sources.wrapSetOperand(baseSelect)} ${compound}`;
1936
+ return `${ctes}${combined}${orderBy}${pagination}`;
1976
1937
  }
1977
- compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
1978
- const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
1979
- const orderBy = OrderByCompiler.compileOrderBy(
1938
+ compileCore(ast, ctx) {
1939
+ const columns = this.compileColumns(ast, ctx);
1940
+ const from = this.sources.compileFrom(ast.from, ctx);
1941
+ const joins = JoinCompiler.compileJoins(
1942
+ ast.joins,
1943
+ ctx,
1944
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
1945
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
1946
+ );
1947
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
1948
+ const groupBy = GroupByCompiler.compileGroupBy(
1980
1949
  ast,
1981
- (term) => this.compileOrderingTerm(term, ctx),
1982
- this.renderOrderByNulls.bind(this),
1983
- this.renderOrderByCollation.bind(this)
1950
+ (term) => this.services.compileOrderingTerm(term, ctx)
1984
1951
  );
1985
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
1986
- const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
1987
- return `${ctes}${combined}${orderBy}${pagination}`;
1952
+ const having = ast.having ? ` HAVING ${this.services.compileExpression(ast.having, ctx)}` : "";
1953
+ const orderBy = this.compileOrderBy(ast, ctx);
1954
+ const pagination = this.services.getPaginationStrategy().compilePagination(ast.limit, ast.offset);
1955
+ return `SELECT ${ast.distinct ? "DISTINCT " : ""}${columns} FROM ${from}${joins}${where}${groupBy}${having}${orderBy}${pagination}`;
1956
+ }
1957
+ compileColumns(ast, ctx) {
1958
+ if (!ast.columns || ast.columns.length === 0) return "*";
1959
+ return ast.columns.map((column) => {
1960
+ const expr = this.services.compileOperand(column, ctx);
1961
+ if (!column.alias) return expr;
1962
+ if (column.alias.includes("(")) return column.alias;
1963
+ return `${expr} AS ${this.services.quoteIdentifier(column.alias)}`;
1964
+ }).join(", ");
1988
1965
  }
1989
- compileInsertAst(ast, ctx) {
1966
+ compileOrderBy(ast, ctx) {
1967
+ return OrderByCompiler.compileOrderBy(
1968
+ ast,
1969
+ (term) => this.services.compileOrderingTerm(term, ctx),
1970
+ (order) => this.services.renderOrderByNulls(order),
1971
+ (order) => this.services.renderOrderByCollation(order)
1972
+ );
1973
+ }
1974
+ };
1975
+
1976
+ // src/core/dialect/base/standard-insert-compiler.ts
1977
+ var StandardInsertCompiler = class {
1978
+ constructor(services, sources) {
1979
+ this.services = services;
1980
+ this.sources = sources;
1981
+ }
1982
+ compile(ast, ctx) {
1990
1983
  if (!ast.columns.length) {
1991
1984
  throw new Error("INSERT queries must specify columns.");
1992
1985
  }
1993
- const table = this.compileTableName(ast.into);
1994
- const columnList = this.compileInsertColumnList(ast.columns);
1995
- const source = this.compileInsertSource(ast.source, ctx);
1996
- const upsert = this.compileUpsertClause(ast, ctx);
1997
- const returning = this.compileReturning(ast.returning, ctx);
1986
+ const table = this.sources.compileTableName(ast.into);
1987
+ const columnList = this.compileColumnList(ast.columns);
1988
+ const source = this.compileSource(ast.source, ctx);
1989
+ const upsert = this.services.compileUpsertClause(ast, ctx);
1990
+ const returning = this.services.compileReturning(ast.returning, ctx);
1998
1991
  return `INSERT INTO ${table} (${columnList}) ${source}${upsert}${returning}`;
1999
1992
  }
2000
- compileUpsertClause(ast, _ctx) {
2001
- void _ctx;
2002
- if (!ast.onConflict) return "";
2003
- throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
2004
- }
2005
- compileReturning(returning, ctx) {
2006
- return this.returningStrategy.compileReturning(returning, ctx);
2007
- }
2008
- compileInsertSource(source, ctx) {
1993
+ compileSource(source, ctx) {
2009
1994
  if (source.type === "InsertValues") {
2010
1995
  if (!source.rows.length) {
2011
1996
  throw new Error("INSERT ... VALUES requires at least one row.");
2012
1997
  }
2013
- const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
1998
+ const values = source.rows.map((row) => `(${row.map((value) => this.services.compileOperand(value, ctx)).join(", ")})`).join(", ");
2014
1999
  return `VALUES ${values}`;
2015
2000
  }
2016
- const normalized = this.normalizeSelectAst(source.query);
2017
- return this.compileSelectAst(normalized, ctx).trim();
2001
+ const normalized = this.services.normalizeSelectAst(source.query);
2002
+ return this.services.compileSelectAst(normalized, ctx).trim();
2018
2003
  }
2019
- compileInsertColumnList(columns) {
2020
- return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
2004
+ compileColumnList(columns) {
2005
+ return columns.map((column) => this.services.quoteIdentifier(column.name)).join(", ");
2021
2006
  }
2022
2007
  ensureConflictColumns(clause, message) {
2023
- if (!clause.target.columns.length) {
2024
- throw new Error(message);
2025
- }
2008
+ if (!clause.target.columns.length) throw new Error(message);
2026
2009
  }
2027
- compileSelectCore(ast, ctx) {
2028
- const columns = this.compileSelectColumns(ast, ctx);
2029
- const from = this.compileFrom(ast.from, ctx);
2010
+ };
2011
+
2012
+ // src/core/dialect/base/standard-update-compiler.ts
2013
+ var StandardUpdateCompiler = class {
2014
+ constructor(services, sources) {
2015
+ this.services = services;
2016
+ this.sources = sources;
2017
+ }
2018
+ compile(ast, ctx) {
2019
+ const target = this.sources.compileTableReference(ast.table);
2020
+ const assignments = this.compileAssignments(ast.set, ast.table, ctx);
2021
+ const from = this.compileFromClause(ast, ctx);
2022
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2023
+ const returning = this.services.compileReturning(ast.returning, ctx);
2024
+ return `UPDATE ${target} SET ${assignments}${from}${where}${returning}`;
2025
+ }
2026
+ compileAssignments(assignments, table, ctx) {
2027
+ return assignments.map((assignment) => {
2028
+ const target = this.services.compileSetTarget(assignment.column, table);
2029
+ const value = this.services.compileOperand(assignment.value, ctx);
2030
+ return `${target} = ${value}`;
2031
+ }).join(", ");
2032
+ }
2033
+ compileFromClause(ast, ctx) {
2034
+ if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2035
+ if (!ast.from) {
2036
+ throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2037
+ }
2038
+ const from = this.sources.compileFrom(ast.from, ctx);
2030
2039
  const joins = JoinCompiler.compileJoins(
2031
2040
  ast.joins,
2032
2041
  ctx,
2033
- this.compileFrom.bind(this),
2034
- this.compileExpression.bind(this)
2042
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2043
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2035
2044
  );
2036
- const whereClause = this.compileWhere(ast.where, ctx);
2037
- const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
2038
- const having = this.compileHaving(ast, ctx);
2039
- const orderBy = OrderByCompiler.compileOrderBy(
2040
- ast,
2041
- (term) => this.compileOrderingTerm(term, ctx),
2042
- this.renderOrderByNulls.bind(this),
2043
- this.renderOrderByCollation.bind(this)
2045
+ return ` FROM ${from}${joins}`;
2046
+ }
2047
+ };
2048
+
2049
+ // src/core/dialect/base/standard-delete-compiler.ts
2050
+ var StandardDeleteCompiler = class {
2051
+ constructor(services, sources) {
2052
+ this.services = services;
2053
+ this.sources = sources;
2054
+ }
2055
+ compile(ast, ctx) {
2056
+ const target = this.sources.compileTableReference(ast.from);
2057
+ const using = this.compileUsingClause(ast, ctx);
2058
+ const where = ast.where ? ` WHERE ${this.services.compileExpression(ast.where, ctx)}` : "";
2059
+ const returning = this.services.compileReturning(ast.returning, ctx);
2060
+ return `DELETE FROM ${target}${using}${where}${returning}`;
2061
+ }
2062
+ compileUsingClause(ast, ctx) {
2063
+ if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2064
+ if (!ast.using) {
2065
+ throw new Error("DELETE with JOINs requires a USING clause.");
2066
+ }
2067
+ const usingTable = this.sources.compileFrom(ast.using, ctx);
2068
+ const joins = JoinCompiler.compileJoins(
2069
+ ast.joins,
2070
+ ctx,
2071
+ (source, compilerContext) => this.sources.compileFrom(source, compilerContext),
2072
+ (expression, compilerContext) => this.services.compileExpression(expression, compilerContext)
2044
2073
  );
2045
- const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
2046
- return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
2074
+ return ` USING ${usingTable}${joins}`;
2075
+ }
2076
+ };
2077
+
2078
+ // src/core/dialect/base/sql-dialect.ts
2079
+ var SqlDialectBase = class extends DialectBase {
2080
+ paginationStrategy = new StandardLimitOffsetPagination();
2081
+ returningStrategy = new NoReturningStrategy();
2082
+ sourceCompiler;
2083
+ selectCompiler;
2084
+ insertCompiler;
2085
+ updateCompiler;
2086
+ deleteCompiler;
2087
+ constructor(functionStrategy, tableFunctionStrategy) {
2088
+ super(functionStrategy, tableFunctionStrategy);
2089
+ const services = {
2090
+ getDialectName: () => this.dialect,
2091
+ getPaginationStrategy: () => this.paginationStrategy,
2092
+ getTableFunctionStrategy: () => this.tableFunctionStrategy,
2093
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2094
+ compileOperand: (node, ctx) => this.compileOperand(node, ctx),
2095
+ compileExpression: (node, ctx) => this.compileExpression(node, ctx),
2096
+ compileOrderingTerm: (term, ctx) => this.compileOrderingTerm(term, ctx),
2097
+ normalizeSelectAst: (ast) => this.normalizeSelectAst(ast),
2098
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
2099
+ compileReturning: (returning, ctx) => this.compileReturning(returning, ctx),
2100
+ compileUpsertClause: (ast, ctx) => this.compileUpsertClause(ast, ctx),
2101
+ compileSetTarget: (column, table) => this.compileSetTarget(column, table),
2102
+ renderOrderByNulls: (order) => this.renderOrderByNulls(order),
2103
+ renderOrderByCollation: (order) => this.renderOrderByCollation(order)
2104
+ };
2105
+ this.sourceCompiler = new StandardSqlSourceCompiler(services);
2106
+ this.selectCompiler = new StandardSelectCompiler(services, this.sourceCompiler);
2107
+ this.insertCompiler = new StandardInsertCompiler(services, this.sourceCompiler);
2108
+ this.updateCompiler = new StandardUpdateCompiler(services, this.sourceCompiler);
2109
+ this.deleteCompiler = new StandardDeleteCompiler(services, this.sourceCompiler);
2110
+ }
2111
+ compileSelectAst(ast, ctx) {
2112
+ return this.selectCompiler.compile(ast, ctx);
2113
+ }
2114
+ compileInsertAst(ast, ctx) {
2115
+ return this.insertCompiler.compile(ast, ctx);
2047
2116
  }
2048
2117
  compileUpdateAst(ast, ctx) {
2049
- const target = this.compileTableReference(ast.table);
2050
- const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
2051
- const fromClause = this.compileUpdateFromClause(ast, ctx);
2052
- const whereClause = this.compileWhere(ast.where, ctx);
2053
- const returning = this.compileReturning(ast.returning, ctx);
2054
- return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
2118
+ return this.updateCompiler.compile(ast, ctx);
2119
+ }
2120
+ compileDeleteAst(ast, ctx) {
2121
+ return this.deleteCompiler.compile(ast, ctx);
2122
+ }
2123
+ compileUpsertClause(ast, _ctx) {
2124
+ void _ctx;
2125
+ if (!ast.onConflict) return "";
2126
+ throw new Error(`UPSERT/ON CONFLICT is not supported by dialect "${this.dialect}".`);
2127
+ }
2128
+ compileReturning(returning, ctx) {
2129
+ return this.returningStrategy.compileReturning(returning, ctx);
2130
+ }
2131
+ ensureConflictColumns(clause, message) {
2132
+ this.insertCompiler.ensureConflictColumns(clause, message);
2055
2133
  }
2056
2134
  compileUpdateAssignments(assignments, table, ctx) {
2057
- return assignments.map((assignment) => {
2058
- const col2 = assignment.column;
2059
- const target = this.compileSetTarget(col2, table);
2060
- const value = this.compileOperand(assignment.value, ctx);
2061
- return `${target} = ${value}`;
2062
- }).join(", ");
2135
+ return this.updateCompiler.compileAssignments(assignments, table, ctx);
2063
2136
  }
2064
2137
  compileSetTarget(column, table) {
2065
2138
  return this.compileQualifiedColumn(column, table);
@@ -2069,132 +2142,38 @@ var SqlDialectBase = class extends Dialect {
2069
2142
  const alias = table.alias;
2070
2143
  const columnTable = column.table ?? alias ?? baseTableName;
2071
2144
  const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
2072
- if (!tableQualifier) {
2073
- return this.quoteIdentifier(column.name);
2074
- }
2145
+ if (!tableQualifier) return this.quoteIdentifier(column.name);
2075
2146
  return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
2076
2147
  }
2077
- compileDeleteAst(ast, ctx) {
2078
- const target = this.compileTableReference(ast.from);
2079
- const usingClause = this.compileDeleteUsingClause(ast, ctx);
2080
- const whereClause = this.compileWhere(ast.where, ctx);
2081
- const returning = this.compileReturning(ast.returning, ctx);
2082
- return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
2083
- }
2084
2148
  formatReturningColumns(returning) {
2085
- return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
2086
- }
2087
- compileDistinct(ast) {
2088
- return ast.distinct ? "DISTINCT " : "";
2089
- }
2090
- compileSelectColumns(ast, ctx) {
2091
- if (!ast.columns || ast.columns.length === 0) {
2092
- return "*";
2093
- }
2094
- return ast.columns.map((c) => {
2095
- const expr = this.compileOperand(c, ctx);
2096
- if (c.alias) {
2097
- if (c.alias.includes("(")) return c.alias;
2098
- return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
2099
- }
2100
- return expr;
2101
- }).join(", ");
2149
+ return this.returningStrategy.formatReturningColumns(
2150
+ returning,
2151
+ (id) => this.quoteIdentifier(id)
2152
+ );
2102
2153
  }
2103
- compileFrom(ast, ctx) {
2104
- const tableSource = ast;
2105
- if (tableSource.type === "FunctionTable") {
2106
- return this.compileFunctionTable(tableSource, ctx);
2107
- }
2108
- if (tableSource.type === "DerivedTable") {
2109
- return this.compileDerivedTable(tableSource, ctx);
2110
- }
2111
- return this.compileTableSource(tableSource);
2154
+ compileFrom(source, ctx) {
2155
+ return this.sourceCompiler.compileFrom(source, ctx);
2112
2156
  }
2113
2157
  compileFunctionTable(fn9, ctx) {
2114
- const key = fn9.key ?? fn9.name;
2115
- if (ctx) {
2116
- const renderer = this.tableFunctionStrategy.getRenderer(key);
2117
- if (renderer) {
2118
- const compiledArgs = (fn9.args ?? []).map((arg) => this.compileOperand(arg, ctx));
2119
- return renderer({
2120
- node: fn9,
2121
- compiledArgs,
2122
- compileOperand: (operand) => this.compileOperand(operand, ctx),
2123
- quoteIdentifier: this.quoteIdentifier.bind(this)
2124
- });
2125
- }
2126
- if (fn9.key) {
2127
- throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
2128
- }
2129
- }
2130
- return FunctionTableFormatter.format(fn9, ctx, this);
2158
+ return this.sourceCompiler.compileFunctionTable(fn9, ctx);
2131
2159
  }
2132
2160
  compileDerivedTable(table, ctx) {
2133
- if (!table.alias) {
2134
- throw new Error("Derived tables must have an alias.");
2135
- }
2136
- const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2137
- const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2138
- return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
2161
+ return this.sourceCompiler.compileDerivedTable(table, ctx);
2139
2162
  }
2140
2163
  compileTableSource(table) {
2141
- if (table.type === "FunctionTable") {
2142
- return this.compileFunctionTable(table);
2143
- }
2144
- if (table.type === "DerivedTable") {
2145
- return this.compileDerivedTable(table);
2146
- }
2147
- const base = this.compileTableName(table);
2148
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2164
+ return this.sourceCompiler.compileTableSource(table);
2149
2165
  }
2150
2166
  compileTableName(table) {
2151
- if (table.schema) {
2152
- return `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`;
2153
- }
2154
- return this.quoteIdentifier(table.name);
2167
+ return this.sourceCompiler.compileTableName(table);
2155
2168
  }
2156
2169
  compileTableReference(table) {
2157
- const base = this.compileTableName(table);
2158
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2159
- }
2160
- compileUpdateFromClause(ast, ctx) {
2161
- if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2162
- if (!ast.from) {
2163
- throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2164
- }
2165
- const from = this.compileFrom(ast.from, ctx);
2166
- const joins = JoinCompiler.compileJoins(
2167
- ast.joins,
2168
- ctx,
2169
- this.compileFrom.bind(this),
2170
- this.compileExpression.bind(this)
2171
- );
2172
- return ` FROM ${from}${joins}`;
2173
- }
2174
- compileDeleteUsingClause(ast, ctx) {
2175
- if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2176
- if (!ast.using) {
2177
- throw new Error("DELETE with JOINs requires a USING clause.");
2178
- }
2179
- const usingTable = this.compileFrom(ast.using, ctx);
2180
- const joins = JoinCompiler.compileJoins(
2181
- ast.joins,
2182
- ctx,
2183
- this.compileFrom.bind(this),
2184
- this.compileExpression.bind(this)
2185
- );
2186
- return ` USING ${usingTable}${joins}`;
2187
- }
2188
- compileHaving(ast, ctx) {
2189
- if (!ast.having) return "";
2190
- return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
2170
+ return this.sourceCompiler.compileTableReference(table);
2191
2171
  }
2192
2172
  stripTrailingSemicolon(sql) {
2193
- return sql.trim().replace(/;$/, "");
2173
+ return this.sourceCompiler.stripTrailingSemicolon(sql);
2194
2174
  }
2195
2175
  wrapSetOperand(sql) {
2196
- const trimmed = this.stripTrailingSemicolon(sql);
2197
- return `(${trimmed})`;
2176
+ return this.sourceCompiler.wrapSetOperand(sql);
2198
2177
  }
2199
2178
  renderOrderByNulls(order) {
2200
2179
  return order.nulls ? ` NULLS ${order.nulls}` : "";
@@ -2903,10 +2882,6 @@ var SqliteDialect = class extends SqlDialectBase {
2903
2882
  supportsDmlReturningClause() {
2904
2883
  return true;
2905
2884
  }
2906
- compileProcedureCall(_ast) {
2907
- void _ast;
2908
- throw new Error("Stored procedures are not supported by the SQLite dialect.");
2909
- }
2910
2885
  };
2911
2886
 
2912
2887
  // src/core/dialect/mssql/functions.ts
@@ -3341,9 +3316,8 @@ var DialectFactory = class {
3341
3316
  /**
3342
3317
  * Register (or override) a dialect factory for a key.
3343
3318
  *
3344
- * Examples:
3345
- * DialectFactory.register('sqlite', () => new SqliteDialect());
3346
- * DialectFactory.register('my-tenant-dialect', () => new CustomDialect());
3319
+ * Implementations are structural: extending DialectBase/SqlDialectBase is
3320
+ * optional. A composed object satisfying Dialect is a valid registration.
3347
3321
  */
3348
3322
  static register(key, factory) {
3349
3323
  this.registry.set(key, factory);
@@ -10916,6 +10890,15 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
10916
10890
  };
10917
10891
  var isTableSourceNode2 = (source) => typeof source.type === "string";
10918
10892
 
10893
+ // src/core/dialect/capabilities/procedure-compiler.ts
10894
+ var isProcedureCompiler = (value) => typeof value?.compileProcedureCall === "function";
10895
+ var requireProcedureCompiler = (value) => {
10896
+ if (!isProcedureCompiler(value)) {
10897
+ throw new Error("Stored procedures are not supported by this dialect.");
10898
+ }
10899
+ return value;
10900
+ };
10901
+
10919
10902
  // src/orm/execute-procedure.ts
10920
10903
  var resolveColumnIndex = (columns, expectedName) => {
10921
10904
  const exact = columns.findIndex((column) => column === expectedName);
@@ -10954,7 +10937,7 @@ var extractOutValues = (compiled, resultSets) => {
10954
10937
  };
10955
10938
  var executeProcedureAst = async (session, ast) => {
10956
10939
  const execCtx = session.getExecutionContext();
10957
- const compiled = execCtx.dialect.compileProcedureCall(ast);
10940
+ const compiled = requireProcedureCompiler(execCtx.dialect).compileProcedureCall(ast);
10958
10941
  const payload = await execCtx.interceptors.run(
10959
10942
  { sql: compiled.sql, params: compiled.params },
10960
10943
  execCtx.executor
@@ -11027,8 +11010,7 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
11027
11010
  }
11028
11011
  compile(dialect) {
11029
11012
  const resolved = resolveDialectInput(dialect);
11030
- this.validateMssqlOutDbType(resolved);
11031
- return resolved.compileProcedureCall(this.getAST());
11013
+ return requireProcedureCompiler(resolved).compileProcedureCall(this.getAST());
11032
11014
  }
11033
11015
  toSql(dialect) {
11034
11016
  return this.compile(dialect).sql;
@@ -11041,21 +11023,8 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
11041
11023
  };
11042
11024
  }
11043
11025
  async execute(session) {
11044
- this.validateMssqlOutDbType(session.getExecutionContext().dialect);
11045
11026
  return executeProcedureAst(session, this.getAST());
11046
11027
  }
11047
- validateMssqlOutDbType(dialect) {
11048
- const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
11049
- if (!isMssqlDialect) return;
11050
- for (const param of this.ast.params) {
11051
- const needsDbType = param.direction === "out" || param.direction === "inout";
11052
- if (needsDbType && !param.dbType) {
11053
- throw new Error(
11054
- `MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
11055
- );
11056
- }
11057
- }
11058
- }
11059
11028
  };
11060
11029
  var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
11061
11030
 
@@ -21783,6 +21752,8 @@ export {
21783
21752
  DefaultMorphToReference,
21784
21753
  DefaultTypeStrategy,
21785
21754
  DeleteQueryBuilder,
21755
+ DialectBase,
21756
+ DialectFactory,
21786
21757
  DomainEventBus,
21787
21758
  Email,
21788
21759
  Entity,
@@ -21816,6 +21787,11 @@ export {
21816
21787
  SelectQueryBuilder,
21817
21788
  SqlServerDialect,
21818
21789
  SqliteDialect,
21790
+ StandardDeleteCompiler,
21791
+ StandardInsertCompiler,
21792
+ StandardSelectCompiler,
21793
+ StandardSqlSourceCompiler,
21794
+ StandardUpdateCompiler,
21819
21795
  StringTypeStrategy,
21820
21796
  TagIndex,
21821
21797
  Title,
@@ -22010,6 +21986,7 @@ export {
22010
21986
  isNull,
22011
21987
  isNullableColumn,
22012
21988
  isOperandNode,
21989
+ isProcedureCompiler,
22013
21990
  isSingleTargetRelation,
22014
21991
  isTableDef2 as isTableDef,
22015
21992
  isTreeConfig,
@@ -22107,6 +22084,8 @@ export {
22107
22084
  repeat,
22108
22085
  replace,
22109
22086
  replaceWithRefs,
22087
+ requireProcedureCompiler,
22088
+ resolveDialectInput,
22110
22089
  resolveTreeConfig,
22111
22090
  resolveValidator,
22112
22091
  responseToRef,