metal-orm 1.0.17 → 1.0.18

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 (39) hide show
  1. package/README.md +4 -3
  2. package/dist/decorators/index.cjs +192 -46
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +1 -1
  5. package/dist/decorators/index.d.ts +1 -1
  6. package/dist/decorators/index.js +192 -46
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +245 -66
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +16 -29
  11. package/dist/index.d.ts +16 -29
  12. package/dist/index.js +243 -66
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-BPCn6MOH.d.cts → select-BuMpVcVt.d.cts} +83 -11
  15. package/dist/{select-BPCn6MOH.d.ts → select-BuMpVcVt.d.ts} +83 -11
  16. package/package.json +4 -1
  17. package/src/codegen/naming-strategy.ts +15 -10
  18. package/src/core/ast/builders.ts +23 -3
  19. package/src/core/ast/expression-builders.ts +14 -1
  20. package/src/core/ast/expression-nodes.ts +11 -9
  21. package/src/core/ast/join-node.ts +5 -3
  22. package/src/core/ast/join.ts +16 -16
  23. package/src/core/ast/query.ts +44 -29
  24. package/src/core/ddl/dialects/mssql-schema-dialect.ts +18 -0
  25. package/src/core/ddl/dialects/mysql-schema-dialect.ts +11 -0
  26. package/src/core/ddl/dialects/postgres-schema-dialect.ts +9 -0
  27. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -0
  28. package/src/core/dialect/base/sql-dialect.ts +58 -46
  29. package/src/core/dialect/mssql/index.ts +53 -28
  30. package/src/core/dialect/sqlite/index.ts +22 -13
  31. package/src/query-builder/column-selector.ts +9 -7
  32. package/src/query-builder/query-ast-service.ts +59 -38
  33. package/src/query-builder/relation-conditions.ts +38 -34
  34. package/src/query-builder/relation-manager.ts +8 -3
  35. package/src/query-builder/relation-service.ts +59 -46
  36. package/src/query-builder/select-query-state.ts +19 -7
  37. package/src/query-builder/select.ts +215 -135
  38. package/src/schema/column.ts +75 -39
  39. package/src/schema/types.ts +1 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Supported column data types for database schema definitions
3
3
  */
4
- type ColumnType = 'INT' | 'INTEGER' | 'BIGINT' | 'VARCHAR' | 'TEXT' | 'JSON' | 'ENUM' | 'DECIMAL' | 'FLOAT' | 'DOUBLE' | 'UUID' | 'DATE' | 'DATETIME' | 'TIMESTAMP' | 'TIMESTAMPTZ' | 'BOOLEAN' | 'int' | 'integer' | 'bigint' | 'varchar' | 'text' | 'json' | 'enum' | 'decimal' | 'float' | 'double' | 'uuid' | 'date' | 'datetime' | 'timestamp' | 'timestamptz' | 'boolean';
4
+ type ColumnType = 'INT' | 'INTEGER' | 'BIGINT' | 'VARCHAR' | 'TEXT' | 'JSON' | 'ENUM' | 'DECIMAL' | 'FLOAT' | 'DOUBLE' | 'UUID' | 'BINARY' | 'VARBINARY' | 'BLOB' | 'BYTEA' | 'DATE' | 'DATETIME' | 'TIMESTAMP' | 'TIMESTAMPTZ' | 'BOOLEAN' | 'int' | 'integer' | 'bigint' | 'varchar' | 'text' | 'json' | 'enum' | 'decimal' | 'float' | 'double' | 'uuid' | 'binary' | 'varbinary' | 'blob' | 'bytea' | 'date' | 'datetime' | 'timestamp' | 'timestamptz' | 'boolean';
5
5
  type ReferentialAction = 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT';
6
6
  interface RawDefaultValue {
7
7
  raw: string;
@@ -83,6 +83,22 @@ declare const col: {
83
83
  * Creates a UUID column definition
84
84
  */
85
85
  uuid: () => ColumnDef<"UUID">;
86
+ /**
87
+ * Creates a binary large object column definition
88
+ */
89
+ blob: () => ColumnDef<"BLOB">;
90
+ /**
91
+ * Creates a fixed-length binary column definition
92
+ */
93
+ binary: (length?: number) => ColumnDef<"BINARY">;
94
+ /**
95
+ * Creates a variable-length binary column definition
96
+ */
97
+ varbinary: (length?: number) => ColumnDef<"VARBINARY">;
98
+ /**
99
+ * Creates a Postgres bytea column definition
100
+ */
101
+ bytea: () => ColumnDef<"BYTEA">;
86
102
  /**
87
103
  * Creates a timestamp column definition
88
104
  */
@@ -355,7 +371,7 @@ type RelationTargetTable<TRel extends RelationDef> = TRel extends HasManyRelatio
355
371
  /**
356
372
  * Maps a ColumnDef to its TypeScript type representation
357
373
  */
358
- type ColumnToTs<T extends ColumnDef> = T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number : T['type'] extends 'BIGINT' | 'bigint' ? number | bigint : T['type'] extends 'DECIMAL' | 'decimal' | 'FLOAT' | 'float' | 'DOUBLE' | 'double' ? number : T['type'] extends 'BOOLEAN' | 'boolean' ? boolean : T['type'] extends 'JSON' | 'json' ? unknown : T['type'] extends 'DATE' | 'date' | 'DATETIME' | 'datetime' | 'TIMESTAMP' | 'timestamp' | 'TIMESTAMPTZ' | 'timestamptz' ? string : string;
374
+ type ColumnToTs<T extends ColumnDef> = T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number : T['type'] extends 'BIGINT' | 'bigint' ? number | bigint : T['type'] extends 'DECIMAL' | 'decimal' | 'FLOAT' | 'float' | 'DOUBLE' | 'double' ? number : T['type'] extends 'BOOLEAN' | 'boolean' ? boolean : T['type'] extends 'JSON' | 'json' ? unknown : T['type'] extends 'BLOB' | 'blob' | 'BINARY' | 'binary' | 'VARBINARY' | 'varbinary' | 'BYTEA' | 'bytea' ? Buffer : T['type'] extends 'DATE' | 'date' | 'DATETIME' | 'datetime' | 'TIMESTAMP' | 'timestamp' | 'TIMESTAMPTZ' | 'timestamptz' ? string : string;
359
375
  /**
360
376
  * Infers a row shape from a table definition
361
377
  */
@@ -534,6 +550,8 @@ interface ColumnNode {
534
550
  name: string;
535
551
  /** Optional alias for the column */
536
552
  alias?: string;
553
+ /** Optional scope marker (e.g., 'outer' for correlated references) */
554
+ scope?: 'outer' | 'default';
537
555
  }
538
556
  /**
539
557
  * AST node representing a function call
@@ -700,7 +718,7 @@ interface JoinNode {
700
718
  /** Type of join (INNER, LEFT, RIGHT, etc.) */
701
719
  kind: JoinKind;
702
720
  /** Table to join */
703
- table: TableNode | FunctionTableNode;
721
+ table: TableSourceNode;
704
722
  /** Join condition expression */
705
723
  condition: ExpressionNode;
706
724
  /** Optional metadata for non-SQL concerns (e.g., relation name) */
@@ -739,6 +757,19 @@ interface FunctionTableNode {
739
757
  /** Optional column aliases */
740
758
  columnAliases?: string[];
741
759
  }
760
+ /**
761
+ * AST node representing a derived table (subquery with an alias)
762
+ */
763
+ interface DerivedTableNode {
764
+ type: 'DerivedTable';
765
+ /** Subquery providing the rows */
766
+ query: SelectQueryNode;
767
+ /** Required alias for the derived table */
768
+ alias: string;
769
+ /** Optional column aliases */
770
+ columnAliases?: string[];
771
+ }
772
+ type TableSourceNode = TableNode | FunctionTableNode | DerivedTableNode;
742
773
  /**
743
774
  * AST node representing an ORDER BY clause
744
775
  */
@@ -785,7 +816,7 @@ interface SelectQueryNode {
785
816
  /** Optional CTEs (WITH clauses) */
786
817
  ctes?: CommonTableExpressionNode[];
787
818
  /** FROM clause table (either a Table or a FunctionTable) */
788
- from: TableNode | FunctionTableNode;
819
+ from: TableSourceNode;
789
820
  /** SELECT clause columns */
790
821
  columns: (ColumnNode | FunctionNode | ScalarSubqueryNode | CaseExpressionNode | WindowFunctionNode)[];
791
822
  /** JOIN clauses */
@@ -1118,6 +1149,12 @@ declare class SelectQueryState {
1118
1149
  * @returns New SelectQueryState with added join
1119
1150
  */
1120
1151
  withJoin(join: JoinNode): SelectQueryState;
1152
+ /**
1153
+ * Replaces the FROM clause.
1154
+ * @param from - Table source for the FROM clause
1155
+ * @returns New SelectQueryState with updated FROM
1156
+ */
1157
+ withFrom(from: TableSourceNode): SelectQueryState;
1121
1158
  /**
1122
1159
  * Adds a WHERE clause to the query
1123
1160
  * @param predicate - WHERE predicate expression
@@ -1354,6 +1391,12 @@ declare class QueryAstService {
1354
1391
  * @returns Updated query state with set operation
1355
1392
  */
1356
1393
  withSetOperation(operator: SetOperationKind, query: SelectQueryNode): SelectQueryState;
1394
+ /**
1395
+ * Replaces the FROM clause for the current query.
1396
+ * @param from - Table source to use in the FROM clause
1397
+ * @returns Updated query state with new FROM
1398
+ */
1399
+ withFrom(from: TableSourceNode): SelectQueryState;
1357
1400
  /**
1358
1401
  * Selects a subquery as a column
1359
1402
  * @param alias - Alias for the subquery
@@ -1495,7 +1538,7 @@ declare class RelationService {
1495
1538
  * @param ast - Query AST to modify
1496
1539
  * @returns Modified query AST with relation correlation
1497
1540
  */
1498
- applyRelationCorrelation(relationName: string, ast: SelectQueryNode): SelectQueryNode;
1541
+ applyRelationCorrelation(relationName: string, ast: SelectQueryNode, additionalCorrelation?: ExpressionNode): SelectQueryNode;
1499
1542
  /**
1500
1543
  * Creates a join node for a relation
1501
1544
  * @param state - Current query state
@@ -1526,6 +1569,7 @@ declare class RelationService {
1526
1569
  * @returns QueryAstService instance
1527
1570
  */
1528
1571
  private astService;
1572
+ private rootTableName;
1529
1573
  }
1530
1574
 
1531
1575
  /**
@@ -1703,7 +1747,7 @@ interface NamingStrategy {
1703
1747
  * @param table - Table node, function table node, or name
1704
1748
  * @returns Valid TypeScript identifier
1705
1749
  */
1706
- tableToSymbol(table: TableNode | FunctionTableNode | string): string;
1750
+ tableToSymbol(table: TableSourceNode | string): string;
1707
1751
  /**
1708
1752
  * Converts a column reference to a property name
1709
1753
  * @param column - Column node
@@ -1942,6 +1986,10 @@ type DeepSelectConfig<TTable extends TableDef> = {
1942
1986
  } & {
1943
1987
  [K in keyof TTable['relations'] & string]?: (keyof RelationTargetTable<TTable['relations'][K]>['columns'] & string)[];
1944
1988
  };
1989
+ type WhereHasOptions = {
1990
+ correlate?: ExpressionNode;
1991
+ };
1992
+ type RelationCallback = <TChildTable extends TableDef>(qb: SelectQueryBuilder<any, TChildTable>) => SelectQueryBuilder<any, TChildTable>;
1945
1993
  /**
1946
1994
 
1947
1995
  * Main query builder class for constructing SQL SELECT queries
@@ -1972,7 +2020,13 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
1972
2020
  */
1973
2021
  constructor(table: TTable, state?: SelectQueryState, hydration?: HydrationManager, dependencies?: Partial<SelectQueryBuilderDependencies>, lazyRelations?: Set<string>);
1974
2022
  private clone;
2023
+ /**
2024
+ * Applies an alias to the root FROM table.
2025
+ * @param alias - Alias to apply
2026
+ */
2027
+ as(alias: string): SelectQueryBuilder<T, TTable>;
1975
2028
  private resolveQueryNode;
2029
+ private applyCorrelation;
1976
2030
  private createChildBuilder;
1977
2031
  private applyAst;
1978
2032
  private applyJoin;
@@ -2030,6 +2084,14 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2030
2084
 
2031
2085
  */
2032
2086
  withRecursive(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable>;
2087
+ /**
2088
+ * Replaces the FROM clause with a derived table (subquery with alias)
2089
+ * @param subquery - Subquery to use as the FROM source
2090
+ * @param alias - Alias for the derived table
2091
+ * @param columnAliases - Optional column alias list
2092
+ * @returns New query builder instance with updated FROM
2093
+ */
2094
+ fromSubquery(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, alias: string, columnAliases?: string[]): SelectQueryBuilder<T, TTable>;
2033
2095
  /**
2034
2096
 
2035
2097
  * Selects a subquery as a column
@@ -2042,6 +2104,16 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2042
2104
 
2043
2105
  */
2044
2106
  selectSubquery(alias: string, sub: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable>;
2107
+ /**
2108
+ * Adds a JOIN against a derived table (subquery with alias)
2109
+ * @param subquery - Subquery to join
2110
+ * @param alias - Alias for the derived table
2111
+ * @param condition - Join condition expression
2112
+ * @param joinKind - Join kind (defaults to INNER)
2113
+ * @param columnAliases - Optional column alias list for the derived table
2114
+ * @returns New query builder instance with the derived-table join
2115
+ */
2116
+ joinSubquery(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, alias: string, condition: BinaryExpressionNode, joinKind?: JoinKind, columnAliases?: string[]): SelectQueryBuilder<T, TTable>;
2045
2117
  /**
2046
2118
 
2047
2119
  * Adds an INNER JOIN to the query
@@ -2254,7 +2326,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2254
2326
  * @returns New query builder instance with the WHERE EXISTS condition
2255
2327
 
2256
2328
  */
2257
- whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable>;
2329
+ whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, correlate?: ExpressionNode): SelectQueryBuilder<T, TTable>;
2258
2330
  /**
2259
2331
 
2260
2332
  * Adds a WHERE NOT EXISTS condition to the query
@@ -2264,7 +2336,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2264
2336
  * @returns New query builder instance with the WHERE NOT EXISTS condition
2265
2337
 
2266
2338
  */
2267
- whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable>;
2339
+ whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, correlate?: ExpressionNode): SelectQueryBuilder<T, TTable>;
2268
2340
  /**
2269
2341
 
2270
2342
  * Adds a WHERE EXISTS condition based on a relationship
@@ -2276,7 +2348,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2276
2348
  * @returns New query builder instance with the relationship existence check
2277
2349
 
2278
2350
  */
2279
- whereHas(relationName: string, callback?: <TChildTable extends TableDef>(qb: SelectQueryBuilder<any, TChildTable>) => SelectQueryBuilder<any, TChildTable>): SelectQueryBuilder<T, TTable>;
2351
+ whereHas(relationName: string, callbackOrOptions?: RelationCallback | WhereHasOptions, maybeOptions?: WhereHasOptions): SelectQueryBuilder<T, TTable>;
2280
2352
  /**
2281
2353
 
2282
2354
  * Adds a WHERE NOT EXISTS condition based on a relationship
@@ -2288,7 +2360,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2288
2360
  * @returns New query builder instance with the relationship non-existence check
2289
2361
 
2290
2362
  */
2291
- whereHasNot(relationName: string, callback?: <TChildTable extends TableDef>(qb: SelectQueryBuilder<any, TChildTable>) => SelectQueryBuilder<any, TChildTable>): SelectQueryBuilder<T, TTable>;
2363
+ whereHasNot(relationName: string, callbackOrOptions?: RelationCallback | WhereHasOptions, maybeOptions?: WhereHasOptions): SelectQueryBuilder<T, TTable>;
2292
2364
  /**
2293
2365
 
2294
2366
  * Compiles the query to SQL for a specific dialect
@@ -2349,4 +2421,4 @@ declare const createColumn: (table: string, name: string) => ColumnNode;
2349
2421
  */
2350
2422
  declare const createLiteral: (val: string | number) => LiteralNode;
2351
2423
 
2352
- export { type TableHooks as $, type BelongsToRelation as A, type BinaryExpressionNode as B, type ColumnRef as C, Dialect as D, type ExpressionNode as E, type FunctionNode as F, type BelongsToManyRelation as G, type HydrationPlan as H, type InExpressionNode as I, type JsonPathNode as J, type HasManyCollection as K, type LiteralNode as L, type BelongsToReference as M, type NullExpressionNode as N, type OperandNode as O, type ManyToManyCollection as P, OrmSession as Q, type RelationMap as R, type SelectQueryNode as S, type TableRef as T, type UpdateQueryNode as U, SelectQueryBuilder as V, type WindowFunctionNode as W, type ExecutionContext as X, type HydrationContext as Y, type CheckConstraint as Z, type TableOptions as _, type ColumnNode as a, defineTable as a0, type ColumnType as a1, type ReferentialAction as a2, type RawDefaultValue as a3, type DefaultValue as a4, col as a5, RelationKinds as a6, type RelationType as a7, type CascadeMode as a8, type RelationDef as a9, DomainEventBus as aA, addDomainEvent as aB, EntityStatus as aC, type TrackedEntity as aD, type RelationKey as aE, type RelationChange as aF, type RelationChangeEntry as aG, type DomainEvent as aH, type AnyDomainEvent as aI, type OrmDomainEvent as aJ, type HasDomainEvents as aK, type QueryLogEntry as aL, type QueryLogger as aM, createQueryLoggingExecutor as aN, type QueryResult as aO, rowsToQueryResult as aP, type SimpleQueryRunner as aQ, createExecutorFromQueryRunner as aR, type EntityOrTableTargetResolver as aS, type EntityConstructor as aT, hasMany as aa, hasOne as ab, belongsTo as ac, belongsToMany as ad, type RelationTargetTable as ae, type ColumnToTs as af, type InferRow as ag, type HasOneReference as ah, createColumn as ai, createLiteral as aj, isOperandNode as ak, isFunctionNode as al, isCaseExpressionNode as am, isWindowFunctionNode as an, isExpressionSelectionNode as ao, type HydrationPivotPlan as ap, type HydrationRelationPlan as aq, type HydrationMetadata as ar, type OrmInterceptor as as, type OrmSessionOptions as at, type OrmOptions as au, type DbExecutorFactory as av, type ExternalTransaction as aw, Orm as ax, type DomainEventHandler as ay, type InitialHandlers as az, type LogicalExpressionNode as b, type BetweenExpressionNode as c, type CaseExpressionNode as d, type ExistsExpressionNode as e, type OrderDirection as f, type ScalarSubqueryNode as g, type ColumnDef as h, type TableDef as i, type InsertQueryNode as j, type InsertCompiler as k, type CompiledQuery as l, type DialectKey as m, type UpdateCompiler as n, type DeleteQueryNode as o, type DeleteCompiler as p, type CompilerContext as q, type ForeignKeyReference as r, type IndexColumn as s, type IndexDef as t, type DbExecutor as u, type NamingStrategy as v, type EntityContext as w, type Entity as x, type HasManyRelation as y, type HasOneRelation as z };
2424
+ export { type HydrationContext as $, type Entity as A, type BinaryExpressionNode as B, type ColumnRef as C, Dialect as D, type ExpressionNode as E, type FunctionNode as F, type HasManyRelation as G, type HydrationPlan as H, type InExpressionNode as I, type JsonPathNode as J, type HasOneRelation as K, type LiteralNode as L, type BelongsToRelation as M, type NullExpressionNode as N, type OperandNode as O, type BelongsToManyRelation as P, type HasManyCollection as Q, type RelationMap as R, type SelectQueryNode as S, type TableRef as T, type UpdateQueryNode as U, type BelongsToReference as V, type WindowFunctionNode as W, type ManyToManyCollection as X, OrmSession as Y, SelectQueryBuilder as Z, type ExecutionContext as _, type ColumnNode as a, type CheckConstraint as a0, type TableOptions as a1, type TableHooks as a2, defineTable as a3, type ColumnType as a4, type ReferentialAction as a5, type RawDefaultValue as a6, type DefaultValue as a7, col as a8, RelationKinds as a9, Orm as aA, type DomainEventHandler as aB, type InitialHandlers as aC, DomainEventBus as aD, addDomainEvent as aE, EntityStatus as aF, type TrackedEntity as aG, type RelationKey as aH, type RelationChange as aI, type RelationChangeEntry as aJ, type DomainEvent as aK, type AnyDomainEvent as aL, type OrmDomainEvent as aM, type HasDomainEvents as aN, type QueryLogEntry as aO, type QueryLogger as aP, createQueryLoggingExecutor as aQ, type QueryResult as aR, rowsToQueryResult as aS, type SimpleQueryRunner as aT, createExecutorFromQueryRunner as aU, type EntityOrTableTargetResolver as aV, type EntityConstructor as aW, type RelationType as aa, type CascadeMode as ab, type RelationDef as ac, hasMany as ad, hasOne as ae, belongsTo as af, belongsToMany as ag, type RelationTargetTable as ah, type ColumnToTs as ai, type InferRow as aj, type HasOneReference as ak, createColumn as al, createLiteral as am, isOperandNode as an, isFunctionNode as ao, isCaseExpressionNode as ap, isWindowFunctionNode as aq, isExpressionSelectionNode as ar, type HydrationPivotPlan as as, type HydrationRelationPlan as at, type HydrationMetadata as au, type OrmInterceptor as av, type OrmSessionOptions as aw, type OrmOptions as ax, type DbExecutorFactory as ay, type ExternalTransaction as az, type LogicalExpressionNode as b, type BetweenExpressionNode as c, type CaseExpressionNode as d, type ExistsExpressionNode as e, type OrderDirection as f, type ScalarSubqueryNode as g, type ColumnDef as h, type TableDef as i, type InsertQueryNode as j, type InsertCompiler as k, type CompiledQuery as l, type DialectKey as m, type UpdateCompiler as n, type DeleteQueryNode as o, type DeleteCompiler as p, type CompilerContext as q, type FunctionTableNode as r, type DerivedTableNode as s, type TableSourceNode as t, type ForeignKeyReference as u, type IndexColumn as v, type IndexDef as w, type DbExecutor as x, type NamingStrategy as y, type EntityContext as z };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Supported column data types for database schema definitions
3
3
  */
4
- type ColumnType = 'INT' | 'INTEGER' | 'BIGINT' | 'VARCHAR' | 'TEXT' | 'JSON' | 'ENUM' | 'DECIMAL' | 'FLOAT' | 'DOUBLE' | 'UUID' | 'DATE' | 'DATETIME' | 'TIMESTAMP' | 'TIMESTAMPTZ' | 'BOOLEAN' | 'int' | 'integer' | 'bigint' | 'varchar' | 'text' | 'json' | 'enum' | 'decimal' | 'float' | 'double' | 'uuid' | 'date' | 'datetime' | 'timestamp' | 'timestamptz' | 'boolean';
4
+ type ColumnType = 'INT' | 'INTEGER' | 'BIGINT' | 'VARCHAR' | 'TEXT' | 'JSON' | 'ENUM' | 'DECIMAL' | 'FLOAT' | 'DOUBLE' | 'UUID' | 'BINARY' | 'VARBINARY' | 'BLOB' | 'BYTEA' | 'DATE' | 'DATETIME' | 'TIMESTAMP' | 'TIMESTAMPTZ' | 'BOOLEAN' | 'int' | 'integer' | 'bigint' | 'varchar' | 'text' | 'json' | 'enum' | 'decimal' | 'float' | 'double' | 'uuid' | 'binary' | 'varbinary' | 'blob' | 'bytea' | 'date' | 'datetime' | 'timestamp' | 'timestamptz' | 'boolean';
5
5
  type ReferentialAction = 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT';
6
6
  interface RawDefaultValue {
7
7
  raw: string;
@@ -83,6 +83,22 @@ declare const col: {
83
83
  * Creates a UUID column definition
84
84
  */
85
85
  uuid: () => ColumnDef<"UUID">;
86
+ /**
87
+ * Creates a binary large object column definition
88
+ */
89
+ blob: () => ColumnDef<"BLOB">;
90
+ /**
91
+ * Creates a fixed-length binary column definition
92
+ */
93
+ binary: (length?: number) => ColumnDef<"BINARY">;
94
+ /**
95
+ * Creates a variable-length binary column definition
96
+ */
97
+ varbinary: (length?: number) => ColumnDef<"VARBINARY">;
98
+ /**
99
+ * Creates a Postgres bytea column definition
100
+ */
101
+ bytea: () => ColumnDef<"BYTEA">;
86
102
  /**
87
103
  * Creates a timestamp column definition
88
104
  */
@@ -355,7 +371,7 @@ type RelationTargetTable<TRel extends RelationDef> = TRel extends HasManyRelatio
355
371
  /**
356
372
  * Maps a ColumnDef to its TypeScript type representation
357
373
  */
358
- type ColumnToTs<T extends ColumnDef> = T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number : T['type'] extends 'BIGINT' | 'bigint' ? number | bigint : T['type'] extends 'DECIMAL' | 'decimal' | 'FLOAT' | 'float' | 'DOUBLE' | 'double' ? number : T['type'] extends 'BOOLEAN' | 'boolean' ? boolean : T['type'] extends 'JSON' | 'json' ? unknown : T['type'] extends 'DATE' | 'date' | 'DATETIME' | 'datetime' | 'TIMESTAMP' | 'timestamp' | 'TIMESTAMPTZ' | 'timestamptz' ? string : string;
374
+ type ColumnToTs<T extends ColumnDef> = T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number : T['type'] extends 'BIGINT' | 'bigint' ? number | bigint : T['type'] extends 'DECIMAL' | 'decimal' | 'FLOAT' | 'float' | 'DOUBLE' | 'double' ? number : T['type'] extends 'BOOLEAN' | 'boolean' ? boolean : T['type'] extends 'JSON' | 'json' ? unknown : T['type'] extends 'BLOB' | 'blob' | 'BINARY' | 'binary' | 'VARBINARY' | 'varbinary' | 'BYTEA' | 'bytea' ? Buffer : T['type'] extends 'DATE' | 'date' | 'DATETIME' | 'datetime' | 'TIMESTAMP' | 'timestamp' | 'TIMESTAMPTZ' | 'timestamptz' ? string : string;
359
375
  /**
360
376
  * Infers a row shape from a table definition
361
377
  */
@@ -534,6 +550,8 @@ interface ColumnNode {
534
550
  name: string;
535
551
  /** Optional alias for the column */
536
552
  alias?: string;
553
+ /** Optional scope marker (e.g., 'outer' for correlated references) */
554
+ scope?: 'outer' | 'default';
537
555
  }
538
556
  /**
539
557
  * AST node representing a function call
@@ -700,7 +718,7 @@ interface JoinNode {
700
718
  /** Type of join (INNER, LEFT, RIGHT, etc.) */
701
719
  kind: JoinKind;
702
720
  /** Table to join */
703
- table: TableNode | FunctionTableNode;
721
+ table: TableSourceNode;
704
722
  /** Join condition expression */
705
723
  condition: ExpressionNode;
706
724
  /** Optional metadata for non-SQL concerns (e.g., relation name) */
@@ -739,6 +757,19 @@ interface FunctionTableNode {
739
757
  /** Optional column aliases */
740
758
  columnAliases?: string[];
741
759
  }
760
+ /**
761
+ * AST node representing a derived table (subquery with an alias)
762
+ */
763
+ interface DerivedTableNode {
764
+ type: 'DerivedTable';
765
+ /** Subquery providing the rows */
766
+ query: SelectQueryNode;
767
+ /** Required alias for the derived table */
768
+ alias: string;
769
+ /** Optional column aliases */
770
+ columnAliases?: string[];
771
+ }
772
+ type TableSourceNode = TableNode | FunctionTableNode | DerivedTableNode;
742
773
  /**
743
774
  * AST node representing an ORDER BY clause
744
775
  */
@@ -785,7 +816,7 @@ interface SelectQueryNode {
785
816
  /** Optional CTEs (WITH clauses) */
786
817
  ctes?: CommonTableExpressionNode[];
787
818
  /** FROM clause table (either a Table or a FunctionTable) */
788
- from: TableNode | FunctionTableNode;
819
+ from: TableSourceNode;
789
820
  /** SELECT clause columns */
790
821
  columns: (ColumnNode | FunctionNode | ScalarSubqueryNode | CaseExpressionNode | WindowFunctionNode)[];
791
822
  /** JOIN clauses */
@@ -1118,6 +1149,12 @@ declare class SelectQueryState {
1118
1149
  * @returns New SelectQueryState with added join
1119
1150
  */
1120
1151
  withJoin(join: JoinNode): SelectQueryState;
1152
+ /**
1153
+ * Replaces the FROM clause.
1154
+ * @param from - Table source for the FROM clause
1155
+ * @returns New SelectQueryState with updated FROM
1156
+ */
1157
+ withFrom(from: TableSourceNode): SelectQueryState;
1121
1158
  /**
1122
1159
  * Adds a WHERE clause to the query
1123
1160
  * @param predicate - WHERE predicate expression
@@ -1354,6 +1391,12 @@ declare class QueryAstService {
1354
1391
  * @returns Updated query state with set operation
1355
1392
  */
1356
1393
  withSetOperation(operator: SetOperationKind, query: SelectQueryNode): SelectQueryState;
1394
+ /**
1395
+ * Replaces the FROM clause for the current query.
1396
+ * @param from - Table source to use in the FROM clause
1397
+ * @returns Updated query state with new FROM
1398
+ */
1399
+ withFrom(from: TableSourceNode): SelectQueryState;
1357
1400
  /**
1358
1401
  * Selects a subquery as a column
1359
1402
  * @param alias - Alias for the subquery
@@ -1495,7 +1538,7 @@ declare class RelationService {
1495
1538
  * @param ast - Query AST to modify
1496
1539
  * @returns Modified query AST with relation correlation
1497
1540
  */
1498
- applyRelationCorrelation(relationName: string, ast: SelectQueryNode): SelectQueryNode;
1541
+ applyRelationCorrelation(relationName: string, ast: SelectQueryNode, additionalCorrelation?: ExpressionNode): SelectQueryNode;
1499
1542
  /**
1500
1543
  * Creates a join node for a relation
1501
1544
  * @param state - Current query state
@@ -1526,6 +1569,7 @@ declare class RelationService {
1526
1569
  * @returns QueryAstService instance
1527
1570
  */
1528
1571
  private astService;
1572
+ private rootTableName;
1529
1573
  }
1530
1574
 
1531
1575
  /**
@@ -1703,7 +1747,7 @@ interface NamingStrategy {
1703
1747
  * @param table - Table node, function table node, or name
1704
1748
  * @returns Valid TypeScript identifier
1705
1749
  */
1706
- tableToSymbol(table: TableNode | FunctionTableNode | string): string;
1750
+ tableToSymbol(table: TableSourceNode | string): string;
1707
1751
  /**
1708
1752
  * Converts a column reference to a property name
1709
1753
  * @param column - Column node
@@ -1942,6 +1986,10 @@ type DeepSelectConfig<TTable extends TableDef> = {
1942
1986
  } & {
1943
1987
  [K in keyof TTable['relations'] & string]?: (keyof RelationTargetTable<TTable['relations'][K]>['columns'] & string)[];
1944
1988
  };
1989
+ type WhereHasOptions = {
1990
+ correlate?: ExpressionNode;
1991
+ };
1992
+ type RelationCallback = <TChildTable extends TableDef>(qb: SelectQueryBuilder<any, TChildTable>) => SelectQueryBuilder<any, TChildTable>;
1945
1993
  /**
1946
1994
 
1947
1995
  * Main query builder class for constructing SQL SELECT queries
@@ -1972,7 +2020,13 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
1972
2020
  */
1973
2021
  constructor(table: TTable, state?: SelectQueryState, hydration?: HydrationManager, dependencies?: Partial<SelectQueryBuilderDependencies>, lazyRelations?: Set<string>);
1974
2022
  private clone;
2023
+ /**
2024
+ * Applies an alias to the root FROM table.
2025
+ * @param alias - Alias to apply
2026
+ */
2027
+ as(alias: string): SelectQueryBuilder<T, TTable>;
1975
2028
  private resolveQueryNode;
2029
+ private applyCorrelation;
1976
2030
  private createChildBuilder;
1977
2031
  private applyAst;
1978
2032
  private applyJoin;
@@ -2030,6 +2084,14 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2030
2084
 
2031
2085
  */
2032
2086
  withRecursive(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable>;
2087
+ /**
2088
+ * Replaces the FROM clause with a derived table (subquery with alias)
2089
+ * @param subquery - Subquery to use as the FROM source
2090
+ * @param alias - Alias for the derived table
2091
+ * @param columnAliases - Optional column alias list
2092
+ * @returns New query builder instance with updated FROM
2093
+ */
2094
+ fromSubquery(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, alias: string, columnAliases?: string[]): SelectQueryBuilder<T, TTable>;
2033
2095
  /**
2034
2096
 
2035
2097
  * Selects a subquery as a column
@@ -2042,6 +2104,16 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2042
2104
 
2043
2105
  */
2044
2106
  selectSubquery(alias: string, sub: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable>;
2107
+ /**
2108
+ * Adds a JOIN against a derived table (subquery with alias)
2109
+ * @param subquery - Subquery to join
2110
+ * @param alias - Alias for the derived table
2111
+ * @param condition - Join condition expression
2112
+ * @param joinKind - Join kind (defaults to INNER)
2113
+ * @param columnAliases - Optional column alias list for the derived table
2114
+ * @returns New query builder instance with the derived-table join
2115
+ */
2116
+ joinSubquery(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, alias: string, condition: BinaryExpressionNode, joinKind?: JoinKind, columnAliases?: string[]): SelectQueryBuilder<T, TTable>;
2045
2117
  /**
2046
2118
 
2047
2119
  * Adds an INNER JOIN to the query
@@ -2254,7 +2326,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2254
2326
  * @returns New query builder instance with the WHERE EXISTS condition
2255
2327
 
2256
2328
  */
2257
- whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable>;
2329
+ whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, correlate?: ExpressionNode): SelectQueryBuilder<T, TTable>;
2258
2330
  /**
2259
2331
 
2260
2332
  * Adds a WHERE NOT EXISTS condition to the query
@@ -2264,7 +2336,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2264
2336
  * @returns New query builder instance with the WHERE NOT EXISTS condition
2265
2337
 
2266
2338
  */
2267
- whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable>;
2339
+ whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, correlate?: ExpressionNode): SelectQueryBuilder<T, TTable>;
2268
2340
  /**
2269
2341
 
2270
2342
  * Adds a WHERE EXISTS condition based on a relationship
@@ -2276,7 +2348,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2276
2348
  * @returns New query builder instance with the relationship existence check
2277
2349
 
2278
2350
  */
2279
- whereHas(relationName: string, callback?: <TChildTable extends TableDef>(qb: SelectQueryBuilder<any, TChildTable>) => SelectQueryBuilder<any, TChildTable>): SelectQueryBuilder<T, TTable>;
2351
+ whereHas(relationName: string, callbackOrOptions?: RelationCallback | WhereHasOptions, maybeOptions?: WhereHasOptions): SelectQueryBuilder<T, TTable>;
2280
2352
  /**
2281
2353
 
2282
2354
  * Adds a WHERE NOT EXISTS condition based on a relationship
@@ -2288,7 +2360,7 @@ declare class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
2288
2360
  * @returns New query builder instance with the relationship non-existence check
2289
2361
 
2290
2362
  */
2291
- whereHasNot(relationName: string, callback?: <TChildTable extends TableDef>(qb: SelectQueryBuilder<any, TChildTable>) => SelectQueryBuilder<any, TChildTable>): SelectQueryBuilder<T, TTable>;
2363
+ whereHasNot(relationName: string, callbackOrOptions?: RelationCallback | WhereHasOptions, maybeOptions?: WhereHasOptions): SelectQueryBuilder<T, TTable>;
2292
2364
  /**
2293
2365
 
2294
2366
  * Compiles the query to SQL for a specific dialect
@@ -2349,4 +2421,4 @@ declare const createColumn: (table: string, name: string) => ColumnNode;
2349
2421
  */
2350
2422
  declare const createLiteral: (val: string | number) => LiteralNode;
2351
2423
 
2352
- export { type TableHooks as $, type BelongsToRelation as A, type BinaryExpressionNode as B, type ColumnRef as C, Dialect as D, type ExpressionNode as E, type FunctionNode as F, type BelongsToManyRelation as G, type HydrationPlan as H, type InExpressionNode as I, type JsonPathNode as J, type HasManyCollection as K, type LiteralNode as L, type BelongsToReference as M, type NullExpressionNode as N, type OperandNode as O, type ManyToManyCollection as P, OrmSession as Q, type RelationMap as R, type SelectQueryNode as S, type TableRef as T, type UpdateQueryNode as U, SelectQueryBuilder as V, type WindowFunctionNode as W, type ExecutionContext as X, type HydrationContext as Y, type CheckConstraint as Z, type TableOptions as _, type ColumnNode as a, defineTable as a0, type ColumnType as a1, type ReferentialAction as a2, type RawDefaultValue as a3, type DefaultValue as a4, col as a5, RelationKinds as a6, type RelationType as a7, type CascadeMode as a8, type RelationDef as a9, DomainEventBus as aA, addDomainEvent as aB, EntityStatus as aC, type TrackedEntity as aD, type RelationKey as aE, type RelationChange as aF, type RelationChangeEntry as aG, type DomainEvent as aH, type AnyDomainEvent as aI, type OrmDomainEvent as aJ, type HasDomainEvents as aK, type QueryLogEntry as aL, type QueryLogger as aM, createQueryLoggingExecutor as aN, type QueryResult as aO, rowsToQueryResult as aP, type SimpleQueryRunner as aQ, createExecutorFromQueryRunner as aR, type EntityOrTableTargetResolver as aS, type EntityConstructor as aT, hasMany as aa, hasOne as ab, belongsTo as ac, belongsToMany as ad, type RelationTargetTable as ae, type ColumnToTs as af, type InferRow as ag, type HasOneReference as ah, createColumn as ai, createLiteral as aj, isOperandNode as ak, isFunctionNode as al, isCaseExpressionNode as am, isWindowFunctionNode as an, isExpressionSelectionNode as ao, type HydrationPivotPlan as ap, type HydrationRelationPlan as aq, type HydrationMetadata as ar, type OrmInterceptor as as, type OrmSessionOptions as at, type OrmOptions as au, type DbExecutorFactory as av, type ExternalTransaction as aw, Orm as ax, type DomainEventHandler as ay, type InitialHandlers as az, type LogicalExpressionNode as b, type BetweenExpressionNode as c, type CaseExpressionNode as d, type ExistsExpressionNode as e, type OrderDirection as f, type ScalarSubqueryNode as g, type ColumnDef as h, type TableDef as i, type InsertQueryNode as j, type InsertCompiler as k, type CompiledQuery as l, type DialectKey as m, type UpdateCompiler as n, type DeleteQueryNode as o, type DeleteCompiler as p, type CompilerContext as q, type ForeignKeyReference as r, type IndexColumn as s, type IndexDef as t, type DbExecutor as u, type NamingStrategy as v, type EntityContext as w, type Entity as x, type HasManyRelation as y, type HasOneRelation as z };
2424
+ export { type HydrationContext as $, type Entity as A, type BinaryExpressionNode as B, type ColumnRef as C, Dialect as D, type ExpressionNode as E, type FunctionNode as F, type HasManyRelation as G, type HydrationPlan as H, type InExpressionNode as I, type JsonPathNode as J, type HasOneRelation as K, type LiteralNode as L, type BelongsToRelation as M, type NullExpressionNode as N, type OperandNode as O, type BelongsToManyRelation as P, type HasManyCollection as Q, type RelationMap as R, type SelectQueryNode as S, type TableRef as T, type UpdateQueryNode as U, type BelongsToReference as V, type WindowFunctionNode as W, type ManyToManyCollection as X, OrmSession as Y, SelectQueryBuilder as Z, type ExecutionContext as _, type ColumnNode as a, type CheckConstraint as a0, type TableOptions as a1, type TableHooks as a2, defineTable as a3, type ColumnType as a4, type ReferentialAction as a5, type RawDefaultValue as a6, type DefaultValue as a7, col as a8, RelationKinds as a9, Orm as aA, type DomainEventHandler as aB, type InitialHandlers as aC, DomainEventBus as aD, addDomainEvent as aE, EntityStatus as aF, type TrackedEntity as aG, type RelationKey as aH, type RelationChange as aI, type RelationChangeEntry as aJ, type DomainEvent as aK, type AnyDomainEvent as aL, type OrmDomainEvent as aM, type HasDomainEvents as aN, type QueryLogEntry as aO, type QueryLogger as aP, createQueryLoggingExecutor as aQ, type QueryResult as aR, rowsToQueryResult as aS, type SimpleQueryRunner as aT, createExecutorFromQueryRunner as aU, type EntityOrTableTargetResolver as aV, type EntityConstructor as aW, type RelationType as aa, type CascadeMode as ab, type RelationDef as ac, hasMany as ad, hasOne as ae, belongsTo as af, belongsToMany as ag, type RelationTargetTable as ah, type ColumnToTs as ai, type InferRow as aj, type HasOneReference as ak, createColumn as al, createLiteral as am, isOperandNode as an, isFunctionNode as ao, isCaseExpressionNode as ap, isWindowFunctionNode as aq, isExpressionSelectionNode as ar, type HydrationPivotPlan as as, type HydrationRelationPlan as at, type HydrationMetadata as au, type OrmInterceptor as av, type OrmSessionOptions as aw, type OrmOptions as ax, type DbExecutorFactory as ay, type ExternalTransaction as az, type LogicalExpressionNode as b, type BetweenExpressionNode as c, type CaseExpressionNode as d, type ExistsExpressionNode as e, type OrderDirection as f, type ScalarSubqueryNode as g, type ColumnDef as h, type TableDef as i, type InsertQueryNode as j, type InsertCompiler as k, type CompiledQuery as l, type DialectKey as m, type UpdateCompiler as n, type DeleteQueryNode as o, type DeleteCompiler as p, type CompilerContext as q, type FunctionTableNode as r, type DerivedTableNode as s, type TableSourceNode as t, type ForeignKeyReference as u, type IndexColumn as v, type IndexDef as w, type DbExecutor as x, type NamingStrategy as y, type EntityContext as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metal-orm",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -46,7 +46,10 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@vitest/ui": "^4.0.14",
49
+ "mysql2": "^3.15.3",
50
+ "pg": "^8.16.3",
49
51
  "sqlite3": "^5.1.7",
52
+ "tedious": "^19.1.3",
50
53
  "tsup": "^8.0.0",
51
54
  "typescript": "^5.5.0",
52
55
  "vitest": "^4.0.14"
@@ -1,4 +1,4 @@
1
- import type { TableNode, FunctionTableNode } from '../core/ast/query.js';
1
+ import type { TableNode, FunctionTableNode, DerivedTableNode, TableSourceNode } from '../core/ast/query.js';
2
2
  import type { ColumnNode } from '../core/ast/expression.js';
3
3
 
4
4
  /**
@@ -7,10 +7,10 @@ import type { ColumnNode } from '../core/ast/expression.js';
7
7
  export interface NamingStrategy {
8
8
  /**
9
9
  * Converts a table name to a TypeScript symbol name
10
- * @param table - Table node, function table node, or name
11
- * @returns Valid TypeScript identifier
12
- */
13
- tableToSymbol(table: TableNode | FunctionTableNode | string): string;
10
+ * @param table - Table node, function table node, or name
11
+ * @returns Valid TypeScript identifier
12
+ */
13
+ tableToSymbol(table: TableSourceNode | string): string;
14
14
 
15
15
  /**
16
16
  * Converts a column reference to a property name
@@ -27,11 +27,16 @@ export interface NamingStrategy {
27
27
  export class DefaultNamingStrategy implements NamingStrategy {
28
28
  /**
29
29
  * Converts table names to TypeScript symbols
30
- * @param table - Table node, function table node, or string name
31
- * @returns Capitalized table name (handles schema-qualified names)
32
- */
33
- tableToSymbol(table: TableNode | FunctionTableNode | string): string {
34
- const tableName = typeof table === 'string' ? table : table.name;
30
+ * @param table - Table node, function table node, or string name
31
+ * @returns Capitalized table name (handles schema-qualified names)
32
+ */
33
+ tableToSymbol(table: TableNode | FunctionTableNode | DerivedTableNode | string): string {
34
+ const tableName =
35
+ typeof table === 'string'
36
+ ? table
37
+ : table.type === 'DerivedTable'
38
+ ? table.alias
39
+ : table.name;
35
40
 
36
41
  // Handle schema-qualified names (e.g., "auth.user" → "AuthUser")
37
42
  if (tableName.includes('.')) {
@@ -1,5 +1,5 @@
1
1
  import { ColumnNode } from './expression-nodes.js';
2
- import { TableNode, FunctionTableNode } from './query.js';
2
+ import { TableNode, FunctionTableNode, DerivedTableNode } from './query.js';
3
3
  import { ColumnRef, TableRef } from './types.js';
4
4
 
5
5
  /**
@@ -13,9 +13,15 @@ export const buildColumnNode = (table: TableRef, column: ColumnRef | ColumnNode)
13
13
  }
14
14
 
15
15
  const def = column as ColumnRef;
16
+ const baseTable = def.table
17
+ ? table.alias && def.table === table.name
18
+ ? table.alias
19
+ : def.table
20
+ : table.alias || table.name;
21
+
16
22
  return {
17
23
  type: 'Column',
18
- table: def.table || table.name,
24
+ table: baseTable,
19
25
  name: def.name
20
26
  };
21
27
  };
@@ -28,7 +34,7 @@ export const buildColumnNode = (table: TableRef, column: ColumnRef | ColumnNode)
28
34
  export const buildColumnNodes = (table: TableRef, names: string[]): ColumnNode[] =>
29
35
  names.map(name => ({
30
36
  type: 'Column',
31
- table: table.name,
37
+ table: table.alias || table.name,
32
38
  name
33
39
  }));
34
40
 
@@ -54,3 +60,17 @@ export const fnTable = (name: string, args: any[] = [], alias?: string, opts?: {
54
60
  columnAliases: opts?.columnAliases,
55
61
  schema: opts?.schema
56
62
  });
63
+
64
+ /**
65
+ * Creates a derived table node wrapping a subquery.
66
+ */
67
+ export const derivedTable = (
68
+ query: import('./query.js').SelectQueryNode,
69
+ alias: string,
70
+ columnAliases?: string[]
71
+ ): DerivedTableNode => ({
72
+ type: 'DerivedTable',
73
+ query,
74
+ alias,
75
+ columnAliases
76
+ });
@@ -63,7 +63,20 @@ const toOperand = (val: OperandNode | ColumnRef | LiteralValue): OperandNode =>
63
63
  return toNode(val);
64
64
  };
65
65
 
66
- export const columnOperand = (col: ColumnRef | ColumnNode): ColumnNode => toNode(col) as ColumnNode;
66
+ export const columnOperand = (col: ColumnRef | ColumnNode): ColumnNode => toNode(col) as ColumnNode;
67
+ /**
68
+ * Marks a column reference as an outer-scope reference for correlated subqueries.
69
+ * Primarily semantic; SQL rendering still uses the provided table/alias name.
70
+ */
71
+ export const outerRef = (col: ColumnRef | ColumnNode): ColumnNode => ({
72
+ ...columnOperand(col),
73
+ scope: 'outer'
74
+ });
75
+
76
+ /**
77
+ * Creates an outer-scoped column reference using a specific table or alias name.
78
+ */
79
+ export const correlateBy = (table: string, column: string): ColumnNode => outerRef({ name: column, table });
67
80
 
68
81
  const createBinaryExpression = (
69
82
  operator: SqlOperator,