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
@@ -14,15 +14,17 @@ export interface LiteralNode {
14
14
  /**
15
15
  * AST node representing a column reference
16
16
  */
17
- export interface ColumnNode {
18
- type: 'Column';
19
- /** Table name the column belongs to */
20
- table: string;
21
- /** Column name */
22
- name: string;
23
- /** Optional alias for the column */
24
- alias?: string;
25
- }
17
+ export interface ColumnNode {
18
+ type: 'Column';
19
+ /** Table name the column belongs to */
20
+ table: string;
21
+ /** Column name */
22
+ name: string;
23
+ /** Optional alias for the column */
24
+ alias?: string;
25
+ /** Optional scope marker (e.g., 'outer' for correlated references) */
26
+ scope?: 'outer' | 'default';
27
+ }
26
28
 
27
29
  /**
28
30
  * AST node representing a function call
@@ -2,7 +2,7 @@ import { JoinNode } from './join.js';
2
2
  import { ExpressionNode } from './expression.js';
3
3
  import { JoinKind } from '../sql/sql.js';
4
4
  import { JoinMetadata } from './join-metadata.js';
5
- import { TableNode, FunctionTableNode } from './query.js';
5
+ import { TableSourceNode, TableNode, FunctionTableNode } from './query.js';
6
6
 
7
7
  /**
8
8
  * Creates a JoinNode ready for AST insertion.
@@ -10,13 +10,15 @@ import { TableNode, FunctionTableNode } from './query.js';
10
10
  */
11
11
  export const createJoinNode = (
12
12
  kind: JoinKind,
13
- tableName: string | TableNode | FunctionTableNode,
13
+ tableName: string | TableSourceNode,
14
14
  condition: ExpressionNode,
15
15
  relationName?: string
16
16
  ): JoinNode => ({
17
17
  type: 'Join',
18
18
  kind,
19
- table: typeof tableName === 'string' ? { type: 'Table', name: tableName } as TableNode : (tableName as TableNode | FunctionTableNode),
19
+ table: typeof tableName === 'string'
20
+ ? ({ type: 'Table', name: tableName } as TableNode)
21
+ : (tableName as TableSourceNode),
20
22
  condition,
21
23
  meta: relationName ? ({ relationName } as JoinMetadata) : undefined
22
24
  });
@@ -1,18 +1,18 @@
1
- import { TableNode, FunctionTableNode } from './query.js';
2
- import { ExpressionNode } from './expression.js';
3
- import { JoinKind } from '../sql/sql.js';
4
-
5
- /**
6
- * AST node representing a JOIN clause
1
+ import { TableSourceNode } from './query.js';
2
+ import { ExpressionNode } from './expression.js';
3
+ import { JoinKind } from '../sql/sql.js';
4
+
5
+ /**
6
+ * AST node representing a JOIN clause
7
7
  */
8
8
  export interface JoinNode {
9
- type: 'Join';
10
- /** Type of join (INNER, LEFT, RIGHT, etc.) */
11
- kind: JoinKind;
12
- /** Table to join */
13
- table: TableNode | FunctionTableNode;
14
- /** Join condition expression */
15
- condition: ExpressionNode;
16
- /** Optional metadata for non-SQL concerns (e.g., relation name) */
17
- meta?: Record<string, unknown>;
18
- }
9
+ type: 'Join';
10
+ /** Type of join (INNER, LEFT, RIGHT, etc.) */
11
+ kind: JoinKind;
12
+ /** Table to join */
13
+ table: TableSourceNode;
14
+ /** Join condition expression */
15
+ condition: ExpressionNode;
16
+ /** Optional metadata for non-SQL concerns (e.g., relation name) */
17
+ meta?: Record<string, unknown>;
18
+ }
@@ -13,18 +13,18 @@ import { OrderDirection } from '../sql/sql.js';
13
13
  /**
14
14
  * AST node representing a table reference in a query
15
15
  */
16
- export interface TableNode {
17
- type: 'Table';
18
- /** Table name */
19
- name: string;
20
- /** Optional schema name */
21
- schema?: string;
22
- /** Optional table alias */
23
- alias?: string;
24
- }
25
-
26
- /**
27
- * AST node representing a function used as a table source (table-valued function)
16
+ export interface TableNode {
17
+ type: 'Table';
18
+ /** Table name */
19
+ name: string;
20
+ /** Optional schema name */
21
+ schema?: string;
22
+ /** Optional table alias */
23
+ alias?: string;
24
+ }
25
+
26
+ /**
27
+ * AST node representing a function used as a table source (table-valued function)
28
28
  */
29
29
  export interface FunctionTableNode {
30
30
  type: 'FunctionTable';
@@ -37,17 +37,32 @@ export interface FunctionTableNode {
37
37
  /** Optional alias for the function table */
38
38
  alias?: string;
39
39
  /** LATERAL flag */
40
- lateral?: boolean;
41
- /** WITH ORDINALITY flag */
42
- withOrdinality?: boolean;
43
- /** Optional column aliases */
44
- columnAliases?: string[];
45
- }
46
-
47
- /**
48
- * AST node representing an ORDER BY clause
49
- */
50
- export interface OrderByNode {
40
+ lateral?: boolean;
41
+ /** WITH ORDINALITY flag */
42
+ withOrdinality?: boolean;
43
+ /** Optional column aliases */
44
+ columnAliases?: string[];
45
+ }
46
+
47
+ /**
48
+ * AST node representing a derived table (subquery with an alias)
49
+ */
50
+ export interface DerivedTableNode {
51
+ type: 'DerivedTable';
52
+ /** Subquery providing the rows */
53
+ query: SelectQueryNode;
54
+ /** Required alias for the derived table */
55
+ alias: string;
56
+ /** Optional column aliases */
57
+ columnAliases?: string[];
58
+ }
59
+
60
+ export type TableSourceNode = TableNode | FunctionTableNode | DerivedTableNode;
61
+
62
+ /**
63
+ * AST node representing an ORDER BY clause
64
+ */
65
+ export interface OrderByNode {
51
66
  type: 'OrderBy';
52
67
  /** Column to order by */
53
68
  column: ColumnNode;
@@ -89,12 +104,12 @@ export interface SetOperationNode {
89
104
  /**
90
105
  * AST node representing a complete SELECT query
91
106
  */
92
- export interface SelectQueryNode {
93
- type: 'SelectQuery';
94
- /** Optional CTEs (WITH clauses) */
95
- ctes?: CommonTableExpressionNode[];
96
- /** FROM clause table (either a Table or a FunctionTable) */
97
- from: TableNode | FunctionTableNode;
107
+ export interface SelectQueryNode {
108
+ type: 'SelectQuery';
109
+ /** Optional CTEs (WITH clauses) */
110
+ ctes?: CommonTableExpressionNode[];
111
+ /** FROM clause table (either a Table or a FunctionTable) */
112
+ from: TableSourceNode;
98
113
  /** SELECT clause columns */
99
114
  columns: (ColumnNode | FunctionNode | ScalarSubqueryNode | CaseExpressionNode | WindowFunctionNode)[];
100
115
  /** JOIN clauses */
@@ -65,6 +65,24 @@ export class MSSqlSchemaDialect extends BaseSchemaDialect {
65
65
  case 'TEXT':
66
66
  case 'text':
67
67
  return 'NVARCHAR(MAX)';
68
+ case 'BINARY':
69
+ case 'binary': {
70
+ const length = column.args?.[0];
71
+ return length !== undefined ? `BINARY(${length})` : 'BINARY(255)';
72
+ }
73
+ case 'VARBINARY':
74
+ case 'varbinary': {
75
+ const length = column.args?.[0];
76
+ if (typeof length === 'string' && length.toLowerCase() === 'max') {
77
+ return 'VARBINARY(MAX)';
78
+ }
79
+ return length !== undefined ? `VARBINARY(${length})` : 'VARBINARY(255)';
80
+ }
81
+ case 'BLOB':
82
+ case 'blob':
83
+ case 'BYTEA':
84
+ case 'bytea':
85
+ return 'VARBINARY(MAX)';
68
86
  case 'ENUM':
69
87
  case 'enum':
70
88
  return 'NVARCHAR(255)';
@@ -69,6 +69,17 @@ export class MySqlSchemaDialect extends BaseSchemaDialect {
69
69
  case 'TEXT':
70
70
  case 'text':
71
71
  return 'TEXT';
72
+ case 'BINARY':
73
+ case 'binary':
74
+ return column.args?.length ? `BINARY(${column.args[0]})` : 'BINARY(255)';
75
+ case 'VARBINARY':
76
+ case 'varbinary':
77
+ return column.args?.length ? `VARBINARY(${column.args[0]})` : 'VARBINARY(255)';
78
+ case 'BLOB':
79
+ case 'blob':
80
+ case 'BYTEA':
81
+ case 'bytea':
82
+ return 'BLOB';
72
83
  case 'ENUM':
73
84
  case 'enum':
74
85
  return column.args && Array.isArray(column.args) && column.args.length
@@ -70,6 +70,15 @@ export class PostgresSchemaDialect extends BaseSchemaDialect {
70
70
  case 'ENUM':
71
71
  case 'enum':
72
72
  return 'text';
73
+ case 'BINARY':
74
+ case 'binary':
75
+ case 'VARBINARY':
76
+ case 'varbinary':
77
+ case 'BLOB':
78
+ case 'blob':
79
+ case 'BYTEA':
80
+ case 'bytea':
81
+ return 'bytea';
73
82
  default:
74
83
  return String(column.type).toLowerCase();
75
84
  }
@@ -62,6 +62,15 @@ export class SQLiteSchemaDialect extends BaseSchemaDialect {
62
62
  case 'ENUM':
63
63
  case 'enum':
64
64
  return 'TEXT';
65
+ case 'BINARY':
66
+ case 'binary':
67
+ case 'VARBINARY':
68
+ case 'varbinary':
69
+ case 'BLOB':
70
+ case 'blob':
71
+ case 'BYTEA':
72
+ case 'bytea':
73
+ return 'BLOB';
65
74
  default:
66
75
  return 'TEXT';
67
76
  }
@@ -1,7 +1,7 @@
1
1
  import { CompilerContext, Dialect } from '../abstract.js';
2
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query.js';
2
+ import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode, TableSourceNode, DerivedTableNode, FunctionTableNode } from '../../ast/query.js';
3
3
  import { ColumnNode } from '../../ast/expression.js';
4
- import { FunctionTableFormatter, FunctionTableNode } from './function-table-formatter.js';
4
+ import { FunctionTableFormatter } from './function-table-formatter.js';
5
5
  import { PaginationStrategy, StandardLimitOffsetPagination } from './pagination-strategy.js';
6
6
  import { CteCompiler } from './cte-compiler.js';
7
7
  import { ReturningStrategy, NoReturningStrategy } from './returning-strategy.js';
@@ -63,11 +63,9 @@ export abstract class SqlDialectBase extends Dialect {
63
63
  return this.returningStrategy.compileReturning(returning, ctx);
64
64
  }
65
65
 
66
- private compileInsertColumnList(columns: ColumnNode[]): string {
67
- return columns
68
- .map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`)
69
- .join(', ');
70
- }
66
+ private compileInsertColumnList(columns: ColumnNode[]): string {
67
+ return columns.map(column => this.quoteIdentifier(column.name)).join(', ');
68
+ }
71
69
 
72
70
  private compileInsertValues(values: any[][], ctx: CompilerContext): string {
73
71
  return values
@@ -99,15 +97,15 @@ export abstract class SqlDialectBase extends Dialect {
99
97
  assignments: { column: ColumnNode; value: any }[],
100
98
  ctx: CompilerContext
101
99
  ): string {
102
- return assignments
103
- .map(assignment => {
104
- const col = assignment.column;
105
- const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
106
- const value = this.compileOperand(assignment.value, ctx);
107
- return `${target} = ${value}`;
108
- })
109
- .join(', ');
110
- }
100
+ return assignments
101
+ .map(assignment => {
102
+ const col = assignment.column;
103
+ const target = this.quoteIdentifier(col.name);
104
+ const value = this.compileOperand(assignment.value, ctx);
105
+ return `${target} = ${value}`;
106
+ })
107
+ .join(', ');
108
+ }
111
109
 
112
110
  protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
113
111
  const table = this.compileTableName(ast.from);
@@ -135,29 +133,49 @@ export abstract class SqlDialectBase extends Dialect {
135
133
  }).join(', ');
136
134
  }
137
135
 
138
- protected compileFrom(ast: SelectQueryNode['from'], ctx?: CompilerContext): string {
139
- const tableSource = ast as any;
140
- if (tableSource.type === 'FunctionTable') {
141
- return this.compileFunctionTable(tableSource, ctx);
142
- }
143
- return this.compileTableSource(tableSource);
144
- }
145
-
146
- protected compileFunctionTable(fn: FunctionTableNode, ctx?: CompilerContext): string {
147
- return FunctionTableFormatter.format(fn, ctx, this);
148
- }
149
-
150
- protected compileTableSource(table: TableSourceNode): string {
151
- const base = this.compileTableName(table);
152
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
153
- }
154
-
155
- protected compileTableName(table: { name: string; schema?: string }): string {
156
- if (table.schema) {
157
- return `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`;
158
- }
159
- return this.quoteIdentifier(table.name);
160
- }
136
+ protected compileFrom(ast: SelectQueryNode['from'], ctx?: CompilerContext): string {
137
+ const tableSource = ast as any;
138
+ if (tableSource.type === 'FunctionTable') {
139
+ return this.compileFunctionTable(tableSource, ctx);
140
+ }
141
+ if (tableSource.type === 'DerivedTable') {
142
+ return this.compileDerivedTable(tableSource, ctx);
143
+ }
144
+ return this.compileTableSource(tableSource);
145
+ }
146
+
147
+ protected compileFunctionTable(fn: FunctionTableNode, ctx?: CompilerContext): string {
148
+ return FunctionTableFormatter.format(fn, ctx, this);
149
+ }
150
+
151
+ protected compileDerivedTable(table: DerivedTableNode, ctx?: CompilerContext): string {
152
+ if (!table.alias) {
153
+ throw new Error('Derived tables must have an alias.');
154
+ }
155
+ const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx!).trim().replace(/;$/, '');
156
+ const columns = table.columnAliases?.length
157
+ ? ` (${table.columnAliases.map(c => this.quoteIdentifier(c)).join(', ')})`
158
+ : '';
159
+ return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
160
+ }
161
+
162
+ protected compileTableSource(table: TableSourceNode): string {
163
+ if (table.type === 'FunctionTable') {
164
+ return this.compileFunctionTable(table as FunctionTableNode);
165
+ }
166
+ if (table.type === 'DerivedTable') {
167
+ return this.compileDerivedTable(table as DerivedTableNode);
168
+ }
169
+ const base = this.compileTableName(table);
170
+ return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
171
+ }
172
+
173
+ protected compileTableName(table: { name: string; schema?: string }): string {
174
+ if (table.schema) {
175
+ return `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`;
176
+ }
177
+ return this.quoteIdentifier(table.name);
178
+ }
161
179
 
162
180
  protected compileHaving(ast: SelectQueryNode, ctx: CompilerContext): string {
163
181
  if (!ast.having) return '';
@@ -172,10 +190,4 @@ export abstract class SqlDialectBase extends Dialect {
172
190
  const trimmed = this.stripTrailingSemicolon(sql);
173
191
  return `(${trimmed})`;
174
192
  }
175
- }
176
-
177
- interface TableSourceNode {
178
- name: string;
179
- schema?: string;
180
- alias?: string;
181
- }
193
+ }
@@ -1,7 +1,8 @@
1
1
  import { CompilerContext, Dialect } from '../abstract.js';
2
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query.js';
3
- import { JsonPathNode } from '../../ast/expression.js';
4
- import { MssqlFunctionStrategy } from './functions.js';
2
+ import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode, TableSourceNode, DerivedTableNode } from '../../ast/query.js';
3
+ import { JsonPathNode } from '../../ast/expression.js';
4
+ import { MssqlFunctionStrategy } from './functions.js';
5
+ import { FunctionTableFormatter } from '../base/function-table-formatter.js';
5
6
 
6
7
  /**
7
8
  * Microsoft SQL Server dialect implementation
@@ -94,13 +95,16 @@ export class SqlServerDialect extends Dialect {
94
95
  return `UPDATE ${table} SET ${assignments}${whereClause};`;
95
96
  }
96
97
 
97
- protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
98
- const table = this.quoteIdentifier(ast.from.name);
99
- const whereClause = this.compileWhere(ast.where, ctx);
100
- return `DELETE FROM ${table}${whereClause};`;
101
- }
102
-
103
- private compileSelectCore(ast: SelectQueryNode, ctx: CompilerContext): string {
98
+ protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
99
+ if (ast.from.type !== 'Table') {
100
+ throw new Error('DELETE only supports base tables in the MSSQL dialect.');
101
+ }
102
+ const table = this.quoteIdentifier(ast.from.name);
103
+ const whereClause = this.compileWhere(ast.where, ctx);
104
+ return `DELETE FROM ${table}${whereClause};`;
105
+ }
106
+
107
+ private compileSelectCore(ast: SelectQueryNode, ctx: CompilerContext): string {
104
108
  const columns = ast.columns.map(c => {
105
109
  let expr = '';
106
110
  if (c.type === 'Function') {
@@ -119,15 +123,15 @@ export class SqlServerDialect extends Dialect {
119
123
  }
120
124
  return expr;
121
125
  }).join(', ');
122
-
123
- const distinct = ast.distinct ? 'DISTINCT ' : '';
124
- const from = `${this.quoteIdentifier(ast.from.name)}`;
125
-
126
- const joins = ast.joins.map(j => {
127
- const table = this.quoteIdentifier(j.table.name);
128
- const cond = this.compileExpression(j.condition, ctx);
129
- return `${j.kind} JOIN ${table} ON ${cond}`;
130
- }).join(' ');
126
+
127
+ const distinct = ast.distinct ? 'DISTINCT ' : '';
128
+ const from = this.compileTableSource(ast.from, ctx);
129
+
130
+ const joins = ast.joins.map(j => {
131
+ const table = this.compileTableSource(j.table, ctx);
132
+ const cond = this.compileExpression(j.condition, ctx);
133
+ return `${j.kind} JOIN ${table} ON ${cond}`;
134
+ }).join(' ');
131
135
  const whereClause = this.compileWhere(ast.where, ctx);
132
136
 
133
137
  const groupBy = ast.groupBy && ast.groupBy.length > 0
@@ -155,19 +159,40 @@ export class SqlServerDialect extends Dialect {
155
159
  .join(', ');
156
160
  }
157
161
 
158
- private compilePagination(ast: SelectQueryNode, orderBy: string): string {
159
- const hasLimit = ast.limit !== undefined;
160
- const hasOffset = ast.offset !== undefined;
161
- if (!hasLimit && !hasOffset) return '';
162
+ private compilePagination(ast: SelectQueryNode, orderBy: string): string {
163
+ const hasLimit = ast.limit !== undefined;
164
+ const hasOffset = ast.offset !== undefined;
165
+ if (!hasLimit && !hasOffset) return '';
162
166
 
163
167
  const off = ast.offset ?? 0;
164
168
  const orderClause = orderBy || ' ORDER BY (SELECT NULL)';
165
169
  let pagination = `${orderClause} OFFSET ${off} ROWS`;
166
- if (hasLimit) {
167
- pagination += ` FETCH NEXT ${ast.limit} ROWS ONLY`;
168
- }
169
- return pagination;
170
- }
170
+ if (hasLimit) {
171
+ pagination += ` FETCH NEXT ${ast.limit} ROWS ONLY`;
172
+ }
173
+ return pagination;
174
+ }
175
+
176
+ private compileTableSource(table: TableSourceNode, ctx: CompilerContext): string {
177
+ if (table.type === 'FunctionTable') {
178
+ return FunctionTableFormatter.format(table, ctx, this as any);
179
+ }
180
+ if (table.type === 'DerivedTable') {
181
+ return this.compileDerivedTable(table, ctx);
182
+ }
183
+ const base = table.schema
184
+ ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}`
185
+ : this.quoteIdentifier(table.name);
186
+ return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
187
+ }
188
+
189
+ private compileDerivedTable(table: DerivedTableNode, ctx: CompilerContext): string {
190
+ const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, '');
191
+ const cols = table.columnAliases?.length
192
+ ? ` (${table.columnAliases.map(c => this.quoteIdentifier(c)).join(', ')})`
193
+ : '';
194
+ return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
195
+ }
171
196
 
172
197
  private compileCtes(ast: SelectQueryNode, ctx: CompilerContext): string {
173
198
  if (!ast.ctes || ast.ctes.length === 0) return '';
@@ -6,14 +6,14 @@ import { SqliteFunctionStrategy } from './functions.js';
6
6
  /**
7
7
  * SQLite dialect implementation
8
8
  */
9
- export class SqliteDialect extends SqlDialectBase {
10
- protected readonly dialect = 'sqlite';
11
- /**
12
- * Creates a new SqliteDialect instance
13
- */
14
- public constructor() {
15
- super(new SqliteFunctionStrategy());
16
- }
9
+ export class SqliteDialect extends SqlDialectBase {
10
+ protected readonly dialect = 'sqlite';
11
+ /**
12
+ * Creates a new SqliteDialect instance
13
+ */
14
+ public constructor() {
15
+ super(new SqliteFunctionStrategy());
16
+ }
17
17
 
18
18
  /**
19
19
  * Quotes an identifier using SQLite double-quote syntax
@@ -35,11 +35,20 @@ export class SqliteDialect extends SqlDialectBase {
35
35
  return `json_extract(${col}, '${node.path}')`;
36
36
  }
37
37
 
38
- protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
39
- if (!returning || returning.length === 0) return '';
40
- const columns = this.formatReturningColumns(returning);
41
- return ` RETURNING ${columns}`;
42
- }
38
+ protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
39
+ if (!returning || returning.length === 0) return '';
40
+ const columns = this.formatReturningColumns(returning);
41
+ return ` RETURNING ${columns}`;
42
+ }
43
+
44
+ protected formatReturningColumns(returning: ColumnNode[]): string {
45
+ return returning
46
+ .map(column => {
47
+ const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : '';
48
+ return `${this.quoteIdentifier(column.name)}${alias}`;
49
+ })
50
+ .join(', ');
51
+ }
43
52
 
44
53
  supportsReturning(): boolean {
45
54
  return true;
@@ -69,10 +69,12 @@ export class ColumnSelector {
69
69
  * @param columns - Columns to make distinct
70
70
  * @returns Updated query context with DISTINCT clause
71
71
  */
72
- distinct(context: SelectQueryBuilderContext, columns: (ColumnDef | ColumnNode)[]): SelectQueryBuilderContext {
73
- const nodes = columns.map(col => buildColumnNode(this.env.table, col));
74
- const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
75
- const nextState = astService.withDistinct(nodes);
76
- return { state: nextState, hydration: context.hydration };
77
- }
78
- }
72
+ distinct(context: SelectQueryBuilderContext, columns: (ColumnDef | ColumnNode)[]): SelectQueryBuilderContext {
73
+ const from = context.state.ast.from;
74
+ const tableRef = from.type === 'Table' && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
75
+ const nodes = columns.map(col => buildColumnNode(tableRef, col));
76
+ const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
77
+ const nextState = astService.withDistinct(nodes);
78
+ return { state: nextState, hydration: context.hydration };
79
+ }
80
+ }