metal-orm 1.0.7 → 1.0.9

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 (153) hide show
  1. package/README.md +133 -121
  2. package/dist/decorators/index.cjs +2564 -0
  3. package/dist/decorators/index.cjs.map +1 -0
  4. package/dist/decorators/index.d.cts +53 -0
  5. package/dist/decorators/index.d.ts +53 -0
  6. package/dist/decorators/index.js +2530 -0
  7. package/dist/decorators/index.js.map +1 -0
  8. package/dist/index.cjs +4227 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.cts +701 -0
  11. package/dist/index.d.ts +701 -0
  12. package/dist/index.js +4131 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/select-654m4qy8.d.cts +1522 -0
  15. package/dist/select-654m4qy8.d.ts +1522 -0
  16. package/package.json +27 -20
  17. package/src/codegen/typescript.ts +405 -393
  18. package/src/core/ast/aggregate-functions.ts +30 -0
  19. package/src/core/ast/builders.ts +43 -0
  20. package/src/core/ast/expression-builders.ts +310 -0
  21. package/src/core/ast/expression-nodes.ts +211 -0
  22. package/src/core/ast/expression-visitor.ts +99 -0
  23. package/src/core/ast/expression.ts +5 -0
  24. package/src/{utils → core/ast}/join-node.ts +20 -20
  25. package/src/{ast → core/ast}/join.ts +18 -18
  26. package/src/{ast → core/ast}/query.ts +113 -113
  27. package/src/core/ast/window-functions.ts +140 -0
  28. package/src/{dialect → core/dialect}/abstract.ts +94 -94
  29. package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
  30. package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
  31. package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
  32. package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
  33. package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
  34. package/src/decorators/bootstrap.ts +126 -0
  35. package/src/decorators/column.ts +78 -0
  36. package/src/decorators/entity.ts +36 -0
  37. package/src/decorators/index.ts +4 -0
  38. package/src/decorators/relations.ts +107 -0
  39. package/src/global.d.ts +1 -0
  40. package/src/index.ts +22 -22
  41. package/src/orm/db-executor.ts +11 -0
  42. package/src/orm/domain-event-bus.ts +52 -0
  43. package/src/{runtime → orm}/entity-meta.ts +52 -52
  44. package/src/orm/entity-metadata.ts +140 -0
  45. package/src/{runtime → orm}/entity.ts +252 -252
  46. package/src/{runtime → orm}/execute.ts +36 -36
  47. package/src/{runtime → orm}/hydration.ts +103 -103
  48. package/src/orm/identity-map.ts +37 -0
  49. package/src/{runtime → orm}/lazy-batch.ts +205 -205
  50. package/src/orm/orm-context.ts +154 -0
  51. package/src/orm/relation-change-processor.ts +140 -0
  52. package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
  53. package/src/{runtime → orm}/relations/has-many.ts +111 -111
  54. package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
  55. package/src/orm/runtime-types.ts +39 -0
  56. package/src/orm/transaction-runner.ts +17 -0
  57. package/src/orm/unit-of-work.ts +232 -0
  58. package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
  59. package/src/{builder → query-builder}/delete-query-state.ts +38 -42
  60. package/src/{builder → query-builder}/delete.ts +46 -57
  61. package/src/{builder → query-builder}/hydration-manager.ts +87 -87
  62. package/src/{builder → query-builder}/hydration-planner.ts +182 -182
  63. package/src/{builder → query-builder}/insert-query-state.ts +51 -62
  64. package/src/{builder → query-builder}/insert.ts +48 -59
  65. package/src/{builder → query-builder}/query-ast-service.ts +208 -226
  66. package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
  67. package/src/{builder → query-builder}/relation-conditions.ts +112 -112
  68. package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
  69. package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
  70. package/src/{builder → query-builder}/relation-service.ts +284 -284
  71. package/src/{builder → query-builder}/relation-types.ts +21 -21
  72. package/src/{builder → query-builder}/relation-utils.ts +12 -12
  73. package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
  74. package/src/{builder → query-builder}/select-query-state.ts +179 -179
  75. package/src/{builder → query-builder}/select.ts +78 -69
  76. package/src/{builder → query-builder}/update-query-state.ts +55 -59
  77. package/src/{builder → query-builder}/update.ts +50 -61
  78. package/src/schema/column.ts +25 -25
  79. package/src/schema/relation.ts +116 -116
  80. package/src/schema/table.ts +34 -34
  81. package/src/schema/types.ts +76 -76
  82. package/.github/workflows/publish-metal-orm.yml +0 -38
  83. package/ROADMAP.md +0 -125
  84. package/docs/CHANGES.md +0 -104
  85. package/docs/advanced-features.md +0 -176
  86. package/docs/api-reference.md +0 -31
  87. package/docs/dml-operations.md +0 -156
  88. package/docs/getting-started.md +0 -171
  89. package/docs/hydration.md +0 -115
  90. package/docs/index.md +0 -36
  91. package/docs/multi-dialect-support.md +0 -59
  92. package/docs/query-builder.md +0 -135
  93. package/docs/runtime.md +0 -105
  94. package/docs/schema-definition.md +0 -112
  95. package/metadata.json +0 -5
  96. package/playground/api/playground-api.ts +0 -94
  97. package/playground/index.html +0 -15
  98. package/playground/src/App.css +0 -1
  99. package/playground/src/App.tsx +0 -114
  100. package/playground/src/components/CodeDisplay.tsx +0 -43
  101. package/playground/src/components/QueryExecutor.tsx +0 -189
  102. package/playground/src/components/ResultsTable.tsx +0 -67
  103. package/playground/src/components/ResultsTabs.tsx +0 -105
  104. package/playground/src/components/ScenarioList.tsx +0 -56
  105. package/playground/src/components/logo.svg +0 -45
  106. package/playground/src/data/scenarios.ts +0 -2
  107. package/playground/src/main.tsx +0 -9
  108. package/playground/src/services/PlaygroundApiService.ts +0 -60
  109. package/postcss.config.cjs +0 -5
  110. package/sql_sql-ansi-cheatsheet-2025.md +0 -264
  111. package/src/ast/expression.ts +0 -658
  112. package/src/builder/operations/cte-manager.ts +0 -34
  113. package/src/builder/operations/filter-manager.ts +0 -68
  114. package/src/builder/operations/join-manager.ts +0 -36
  115. package/src/builder/operations/pagination-manager.ts +0 -36
  116. package/src/playground/features/playground/api/types.ts +0 -16
  117. package/src/playground/features/playground/clients/MockClient.ts +0 -17
  118. package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
  119. package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
  120. package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
  121. package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
  122. package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
  123. package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
  124. package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
  125. package/src/playground/features/playground/data/scenarios/index.ts +0 -29
  126. package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
  127. package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
  128. package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
  129. package/src/playground/features/playground/data/scenarios/types.ts +0 -70
  130. package/src/playground/features/playground/data/schema.ts +0 -91
  131. package/src/playground/features/playground/data/seed.ts +0 -104
  132. package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
  133. package/src/runtime/orm-context.ts +0 -539
  134. package/tests/belongs-to-many.test.ts +0 -57
  135. package/tests/between.test.ts +0 -43
  136. package/tests/case-expression.test.ts +0 -58
  137. package/tests/complex-exists.test.ts +0 -230
  138. package/tests/cte.test.ts +0 -118
  139. package/tests/dml.test.ts +0 -206
  140. package/tests/exists.test.ts +0 -127
  141. package/tests/like.test.ts +0 -33
  142. package/tests/orm-runtime.test.ts +0 -254
  143. package/tests/postgres.test.ts +0 -30
  144. package/tests/right-join.test.ts +0 -89
  145. package/tests/subquery-having.test.ts +0 -193
  146. package/tests/window-function.test.ts +0 -151
  147. package/tsconfig.json +0 -30
  148. package/tsup.config.ts +0 -10
  149. package/vite.config.ts +0 -22
  150. package/vitest.config.ts +0 -14
  151. /package/src/{constants → core/sql}/sql.ts +0 -0
  152. /package/src/{runtime → orm}/als.ts +0 -0
  153. /package/src/{utils → query-builder}/relation-alias.ts +0 -0
@@ -1,20 +1,20 @@
1
- import { JoinNode } from '../ast/join';
2
- import { ExpressionNode } from '../ast/expression';
3
- import { JoinKind } from '../constants/sql';
4
-
5
- /**
6
- * Creates a JoinNode ready for AST insertion.
7
- * Centralizing this avoids copy/pasted object literals when multiple services need to synthesize joins.
8
- */
9
- export const createJoinNode = (
10
- kind: JoinKind,
11
- tableName: string,
12
- condition: ExpressionNode,
13
- relationName?: string
14
- ): JoinNode => ({
15
- type: 'Join',
16
- kind,
17
- table: { type: 'Table', name: tableName },
18
- condition,
19
- relationName
20
- });
1
+ import { JoinNode } from './join.js';
2
+ import { ExpressionNode } from './expression.js';
3
+ import { JoinKind } from '../sql/sql.js';
4
+
5
+ /**
6
+ * Creates a JoinNode ready for AST insertion.
7
+ * Centralizing this avoids copy/pasted object literals when multiple services need to synthesize joins.
8
+ */
9
+ export const createJoinNode = (
10
+ kind: JoinKind,
11
+ tableName: string,
12
+ condition: ExpressionNode,
13
+ relationName?: string
14
+ ): JoinNode => ({
15
+ type: 'Join',
16
+ kind,
17
+ table: { type: 'Table', name: tableName },
18
+ condition,
19
+ relationName
20
+ });
@@ -1,18 +1,18 @@
1
- import { TableNode } from './query';
2
- import { ExpressionNode } from './expression';
3
- import { JoinKind } from '../constants/sql';
4
-
5
- /**
6
- * AST node representing a JOIN clause
7
- */
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;
14
- /** Join condition expression */
15
- condition: ExpressionNode;
16
- /** Optional relation name for code generation */
17
- relationName?: string;
18
- }
1
+ import { TableNode } 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
+ */
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;
14
+ /** Join condition expression */
15
+ condition: ExpressionNode;
16
+ /** Optional relation name for code generation */
17
+ relationName?: string;
18
+ }
@@ -1,15 +1,15 @@
1
- import {
2
- ColumnNode,
3
- FunctionNode,
4
- ExpressionNode,
5
- ScalarSubqueryNode,
6
- CaseExpressionNode,
7
- WindowFunctionNode,
8
- OperandNode
9
- } from './expression';
10
- import { JoinNode } from './join';
11
- import { RelationType } from '../schema/relation';
12
- import { OrderDirection } from '../constants/sql';
1
+ import {
2
+ ColumnNode,
3
+ FunctionNode,
4
+ ExpressionNode,
5
+ ScalarSubqueryNode,
6
+ CaseExpressionNode,
7
+ WindowFunctionNode,
8
+ OperandNode
9
+ } from './expression.js';
10
+ import { JoinNode } from './join.js';
11
+ import { RelationType } from '../../schema/relation.js';
12
+ import { OrderDirection } from '../sql/sql.js';
13
13
 
14
14
  /**
15
15
  * AST node representing a table reference in a query
@@ -35,39 +35,39 @@ export interface OrderByNode {
35
35
  direction: OrderDirection;
36
36
  }
37
37
 
38
- /**
39
- * Plan describing pivot columns needed for hydration
40
- */
41
- export interface HydrationPivotPlan {
42
- table: string;
43
- primaryKey: string;
44
- aliasPrefix: string;
45
- columns: string[];
46
- }
47
-
48
- /**
49
- * Plan for hydrating relationship data
50
- */
51
- export interface HydrationRelationPlan {
52
- /** Name of the relationship */
53
- name: string;
54
- /** Alias prefix for the relationship */
55
- aliasPrefix: string;
56
- /** Type of relationship */
57
- type: RelationType;
58
- /** Target table name */
59
- targetTable: string;
60
- /** Target table primary key */
61
- targetPrimaryKey: string;
62
- /** Foreign key column */
63
- foreignKey: string;
64
- /** Local key column */
65
- localKey: string;
66
- /** Columns to include */
67
- columns: string[];
68
- /** Optional pivot plan for many-to-many relationships */
69
- pivot?: HydrationPivotPlan;
70
- }
38
+ /**
39
+ * Plan describing pivot columns needed for hydration
40
+ */
41
+ export interface HydrationPivotPlan {
42
+ table: string;
43
+ primaryKey: string;
44
+ aliasPrefix: string;
45
+ columns: string[];
46
+ }
47
+
48
+ /**
49
+ * Plan for hydrating relationship data
50
+ */
51
+ export interface HydrationRelationPlan {
52
+ /** Name of the relationship */
53
+ name: string;
54
+ /** Alias prefix for the relationship */
55
+ aliasPrefix: string;
56
+ /** Type of relationship */
57
+ type: RelationType;
58
+ /** Target table name */
59
+ targetTable: string;
60
+ /** Target table primary key */
61
+ targetPrimaryKey: string;
62
+ /** Foreign key column */
63
+ foreignKey: string;
64
+ /** Local key column */
65
+ localKey: string;
66
+ /** Columns to include */
67
+ columns: string[];
68
+ /** Optional pivot plan for many-to-many relationships */
69
+ pivot?: HydrationPivotPlan;
70
+ }
71
71
 
72
72
  /**
73
73
  * Complete hydration plan for a query
@@ -109,71 +109,71 @@ export interface CommonTableExpressionNode {
109
109
  /**
110
110
  * AST node representing a complete SELECT query
111
111
  */
112
- export interface SelectQueryNode {
113
- type: 'SelectQuery';
114
- /** Optional CTEs (WITH clauses) */
115
- ctes?: CommonTableExpressionNode[];
116
- /** FROM clause table */
117
- from: TableNode;
118
- /** SELECT clause columns */
119
- columns: (ColumnNode | FunctionNode | ScalarSubqueryNode | CaseExpressionNode | WindowFunctionNode)[];
120
- /** JOIN clauses */
121
- joins: JoinNode[];
122
- /** Optional WHERE clause */
123
- where?: ExpressionNode;
124
- /** Optional GROUP BY clause */
125
- groupBy?: ColumnNode[];
126
- /** Optional HAVING clause */
127
- having?: ExpressionNode;
128
- /** Optional ORDER BY clause */
129
- orderBy?: OrderByNode[];
130
- /** Optional LIMIT clause */
131
- limit?: number;
132
- /** Optional OFFSET clause */
133
- offset?: number;
134
- /** Optional query metadata */
135
- meta?: QueryMetadata;
136
- /** Optional DISTINCT clause */
137
- distinct?: ColumnNode[];
138
- }
139
-
140
- export interface InsertQueryNode {
141
- type: 'InsertQuery';
142
- /** Target table */
143
- into: TableNode;
144
- /** Column order for inserted values */
145
- columns: ColumnNode[];
146
- /** Rows of values to insert */
147
- values: OperandNode[][];
148
- /** Optional RETURNING clause */
149
- returning?: ColumnNode[];
150
- }
151
-
152
- export interface UpdateAssignmentNode {
153
- /** Column to update */
154
- column: ColumnNode;
155
- /** Value to set */
156
- value: OperandNode;
157
- }
158
-
159
- export interface UpdateQueryNode {
160
- type: 'UpdateQuery';
161
- /** Table being updated */
162
- table: TableNode;
163
- /** Assignments for SET clause */
164
- set: UpdateAssignmentNode[];
165
- /** Optional WHERE clause */
166
- where?: ExpressionNode;
167
- /** Optional RETURNING clause */
168
- returning?: ColumnNode[];
169
- }
170
-
171
- export interface DeleteQueryNode {
172
- type: 'DeleteQuery';
173
- /** Table to delete from */
174
- from: TableNode;
175
- /** Optional WHERE clause */
176
- where?: ExpressionNode;
177
- /** Optional RETURNING clause */
178
- returning?: ColumnNode[];
179
- }
112
+ export interface SelectQueryNode {
113
+ type: 'SelectQuery';
114
+ /** Optional CTEs (WITH clauses) */
115
+ ctes?: CommonTableExpressionNode[];
116
+ /** FROM clause table */
117
+ from: TableNode;
118
+ /** SELECT clause columns */
119
+ columns: (ColumnNode | FunctionNode | ScalarSubqueryNode | CaseExpressionNode | WindowFunctionNode)[];
120
+ /** JOIN clauses */
121
+ joins: JoinNode[];
122
+ /** Optional WHERE clause */
123
+ where?: ExpressionNode;
124
+ /** Optional GROUP BY clause */
125
+ groupBy?: ColumnNode[];
126
+ /** Optional HAVING clause */
127
+ having?: ExpressionNode;
128
+ /** Optional ORDER BY clause */
129
+ orderBy?: OrderByNode[];
130
+ /** Optional LIMIT clause */
131
+ limit?: number;
132
+ /** Optional OFFSET clause */
133
+ offset?: number;
134
+ /** Optional query metadata */
135
+ meta?: QueryMetadata;
136
+ /** Optional DISTINCT clause */
137
+ distinct?: ColumnNode[];
138
+ }
139
+
140
+ export interface InsertQueryNode {
141
+ type: 'InsertQuery';
142
+ /** Target table */
143
+ into: TableNode;
144
+ /** Column order for inserted values */
145
+ columns: ColumnNode[];
146
+ /** Rows of values to insert */
147
+ values: OperandNode[][];
148
+ /** Optional RETURNING clause */
149
+ returning?: ColumnNode[];
150
+ }
151
+
152
+ export interface UpdateAssignmentNode {
153
+ /** Column to update */
154
+ column: ColumnNode;
155
+ /** Value to set */
156
+ value: OperandNode;
157
+ }
158
+
159
+ export interface UpdateQueryNode {
160
+ type: 'UpdateQuery';
161
+ /** Table being updated */
162
+ table: TableNode;
163
+ /** Assignments for SET clause */
164
+ set: UpdateAssignmentNode[];
165
+ /** Optional WHERE clause */
166
+ where?: ExpressionNode;
167
+ /** Optional RETURNING clause */
168
+ returning?: ColumnNode[];
169
+ }
170
+
171
+ export interface DeleteQueryNode {
172
+ type: 'DeleteQuery';
173
+ /** Table to delete from */
174
+ from: TableNode;
175
+ /** Optional WHERE clause */
176
+ where?: ExpressionNode;
177
+ /** Optional RETURNING clause */
178
+ returning?: ColumnNode[];
179
+ }
@@ -0,0 +1,140 @@
1
+ import { ColumnDef } from '../../schema/column.js';
2
+ import { ColumnNode, LiteralNode, JsonPathNode, WindowFunctionNode } from './expression-nodes.js';
3
+ import { columnOperand } from './expression-builders.js';
4
+ import { OrderDirection } from '../sql/sql.js';
5
+ import { OrderByNode } from './query.js';
6
+
7
+ const buildWindowFunction = (
8
+ name: string,
9
+ args: (ColumnNode | LiteralNode | JsonPathNode)[] = [],
10
+ partitionBy?: ColumnNode[],
11
+ orderBy?: OrderByNode[]
12
+ ): WindowFunctionNode => {
13
+ const node: WindowFunctionNode = {
14
+ type: 'WindowFunction',
15
+ name,
16
+ args
17
+ };
18
+
19
+ if (partitionBy && partitionBy.length) {
20
+ node.partitionBy = partitionBy;
21
+ }
22
+
23
+ if (orderBy && orderBy.length) {
24
+ node.orderBy = orderBy;
25
+ }
26
+
27
+ return node;
28
+ };
29
+
30
+ /**
31
+ * Creates a ROW_NUMBER window function
32
+ * @returns Window function node for ROW_NUMBER
33
+ */
34
+ export const rowNumber = (): WindowFunctionNode => buildWindowFunction('ROW_NUMBER');
35
+
36
+ /**
37
+ * Creates a RANK window function
38
+ * @returns Window function node for RANK
39
+ */
40
+ export const rank = (): WindowFunctionNode => buildWindowFunction('RANK');
41
+
42
+ /**
43
+ * Creates a DENSE_RANK window function
44
+ * @returns Window function node for DENSE_RANK
45
+ */
46
+ export const denseRank = (): WindowFunctionNode => buildWindowFunction('DENSE_RANK');
47
+
48
+ /**
49
+ * Creates an NTILE window function
50
+ * @param n - Number of buckets
51
+ * @returns Window function node for NTILE
52
+ */
53
+ export const ntile = (n: number): WindowFunctionNode =>
54
+ buildWindowFunction('NTILE', [{ type: 'Literal', value: n }]);
55
+
56
+ /**
57
+ * Creates a LAG window function
58
+ * @param col - Column to lag
59
+ * @param offset - Offset (defaults to 1)
60
+ * @param defaultValue - Default value if no row exists
61
+ * @returns Window function node for LAG
62
+ */
63
+ export const lag = (col: ColumnDef | ColumnNode, offset: number = 1, defaultValue?: any): WindowFunctionNode => {
64
+ const args: (ColumnNode | LiteralNode | JsonPathNode)[] = [
65
+ columnOperand(col),
66
+ { type: 'Literal', value: offset }
67
+ ];
68
+ if (defaultValue !== undefined) {
69
+ args.push({ type: 'Literal', value: defaultValue });
70
+ }
71
+ return buildWindowFunction('LAG', args);
72
+ };
73
+
74
+ /**
75
+ * Creates a LEAD window function
76
+ * @param col - Column to lead
77
+ * @param offset - Offset (defaults to 1)
78
+ * @param defaultValue - Default value if no row exists
79
+ * @returns Window function node for LEAD
80
+ */
81
+ export const lead = (col: ColumnDef | ColumnNode, offset: number = 1, defaultValue?: any): WindowFunctionNode => {
82
+ const args: (ColumnNode | LiteralNode | JsonPathNode)[] = [
83
+ columnOperand(col),
84
+ { type: 'Literal', value: offset }
85
+ ];
86
+ if (defaultValue !== undefined) {
87
+ args.push({ type: 'Literal', value: defaultValue });
88
+ }
89
+ return buildWindowFunction('LEAD', args);
90
+ };
91
+
92
+ /**
93
+ * Creates a FIRST_VALUE window function
94
+ * @param col - Column to get first value from
95
+ * @returns Window function node for FIRST_VALUE
96
+ */
97
+ export const firstValue = (col: ColumnDef | ColumnNode): WindowFunctionNode =>
98
+ buildWindowFunction('FIRST_VALUE', [columnOperand(col)]);
99
+
100
+ /**
101
+ * Creates a LAST_VALUE window function
102
+ * @param col - Column to get last value from
103
+ * @returns Window function node for LAST_VALUE
104
+ */
105
+ export const lastValue = (col: ColumnDef | ColumnNode): WindowFunctionNode =>
106
+ buildWindowFunction('LAST_VALUE', [columnOperand(col)]);
107
+
108
+ /**
109
+ * Creates a custom window function
110
+ * @param name - Window function name
111
+ * @param args - Function arguments
112
+ * @param partitionBy - Optional PARTITION BY columns
113
+ * @param orderBy - Optional ORDER BY clauses
114
+ * @returns Window function node
115
+ */
116
+ export const windowFunction = (
117
+ name: string,
118
+ args: (ColumnDef | ColumnNode | LiteralNode | JsonPathNode)[] = [],
119
+ partitionBy?: (ColumnDef | ColumnNode)[],
120
+ orderBy?: { column: ColumnDef | ColumnNode; direction: OrderDirection }[]
121
+ ): WindowFunctionNode => {
122
+ const nodeArgs = args.map(arg => {
123
+ if (typeof (arg as LiteralNode).value !== 'undefined') {
124
+ return arg as LiteralNode;
125
+ }
126
+ if ('path' in arg) {
127
+ return arg as JsonPathNode;
128
+ }
129
+ return columnOperand(arg as ColumnDef | ColumnNode);
130
+ });
131
+
132
+ const partitionNodes = partitionBy?.map(col => columnOperand(col)) ?? undefined;
133
+ const orderNodes: OrderByNode[] | undefined = orderBy?.map(o => ({
134
+ type: 'OrderBy',
135
+ column: columnOperand(o.column),
136
+ direction: o.direction
137
+ }));
138
+
139
+ return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
140
+ };
@@ -1,4 +1,4 @@
1
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../ast/query';
1
+ import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../ast/query.js';
2
2
  import {
3
3
  ExpressionNode,
4
4
  BinaryExpressionNode,
@@ -15,7 +15,7 @@ import {
15
15
  CaseExpressionNode,
16
16
  WindowFunctionNode,
17
17
  BetweenExpressionNode
18
- } from '../ast/expression';
18
+ } from '../ast/expression.js';
19
19
 
20
20
  /**
21
21
  * Context for SQL compilation with parameter management
@@ -30,91 +30,91 @@ export interface CompilerContext {
30
30
  /**
31
31
  * Result of SQL compilation
32
32
  */
33
- export interface CompiledQuery {
34
- /** Generated SQL string */
35
- sql: string;
36
- /** Parameters for the query */
37
- params: unknown[];
38
- }
39
-
40
- export interface SelectCompiler {
41
- compileSelect(ast: SelectQueryNode): CompiledQuery;
42
- }
43
-
44
- export interface InsertCompiler {
45
- compileInsert(ast: InsertQueryNode): CompiledQuery;
46
- }
47
-
48
- export interface UpdateCompiler {
49
- compileUpdate(ast: UpdateQueryNode): CompiledQuery;
50
- }
51
-
52
- export interface DeleteCompiler {
53
- compileDelete(ast: DeleteQueryNode): CompiledQuery;
54
- }
55
-
56
- /**
57
- * Abstract base class for SQL dialect implementations
58
- */
59
- export abstract class Dialect
60
- implements SelectCompiler, InsertCompiler, UpdateCompiler, DeleteCompiler
61
- {
33
+ export interface CompiledQuery {
34
+ /** Generated SQL string */
35
+ sql: string;
36
+ /** Parameters for the query */
37
+ params: unknown[];
38
+ }
39
+
40
+ export interface SelectCompiler {
41
+ compileSelect(ast: SelectQueryNode): CompiledQuery;
42
+ }
43
+
44
+ export interface InsertCompiler {
45
+ compileInsert(ast: InsertQueryNode): CompiledQuery;
46
+ }
47
+
48
+ export interface UpdateCompiler {
49
+ compileUpdate(ast: UpdateQueryNode): CompiledQuery;
50
+ }
51
+
52
+ export interface DeleteCompiler {
53
+ compileDelete(ast: DeleteQueryNode): CompiledQuery;
54
+ }
55
+
56
+ /**
57
+ * Abstract base class for SQL dialect implementations
58
+ */
59
+ export abstract class Dialect
60
+ implements SelectCompiler, InsertCompiler, UpdateCompiler, DeleteCompiler
61
+ {
62
62
  /**
63
63
  * Compiles a SELECT query AST to SQL
64
64
  * @param ast - Query AST to compile
65
65
  * @returns Compiled query with SQL and parameters
66
66
  */
67
- compileSelect(ast: SelectQueryNode): CompiledQuery {
68
- const ctx = this.createCompilerContext();
69
- const rawSql = this.compileSelectAst(ast, ctx).trim();
70
- const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
71
- return {
72
- sql,
73
- params: [...ctx.params]
74
- };
75
- }
76
-
77
- compileInsert(ast: InsertQueryNode): CompiledQuery {
78
- const ctx = this.createCompilerContext();
79
- const rawSql = this.compileInsertAst(ast, ctx).trim();
80
- const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
81
- return {
82
- sql,
83
- params: [...ctx.params]
84
- };
85
- }
86
-
87
- compileUpdate(ast: UpdateQueryNode): CompiledQuery {
88
- const ctx = this.createCompilerContext();
89
- const rawSql = this.compileUpdateAst(ast, ctx).trim();
90
- const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
91
- return {
92
- sql,
93
- params: [...ctx.params]
94
- };
95
- }
96
-
97
- compileDelete(ast: DeleteQueryNode): CompiledQuery {
98
- const ctx = this.createCompilerContext();
99
- const rawSql = this.compileDeleteAst(ast, ctx).trim();
100
- const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
101
- return {
102
- sql,
103
- params: [...ctx.params]
104
- };
105
- }
106
-
107
- /**
108
- * Compiles SELECT query AST to SQL (to be implemented by concrete dialects)
109
- * @param ast - Query AST
110
- * @param ctx - Compiler context
111
- * @returns SQL string
112
- */
113
- protected abstract compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string;
114
-
115
- protected abstract compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string;
116
- protected abstract compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string;
117
- protected abstract compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string;
67
+ compileSelect(ast: SelectQueryNode): CompiledQuery {
68
+ const ctx = this.createCompilerContext();
69
+ const rawSql = this.compileSelectAst(ast, ctx).trim();
70
+ const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
71
+ return {
72
+ sql,
73
+ params: [...ctx.params]
74
+ };
75
+ }
76
+
77
+ compileInsert(ast: InsertQueryNode): CompiledQuery {
78
+ const ctx = this.createCompilerContext();
79
+ const rawSql = this.compileInsertAst(ast, ctx).trim();
80
+ const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
81
+ return {
82
+ sql,
83
+ params: [...ctx.params]
84
+ };
85
+ }
86
+
87
+ compileUpdate(ast: UpdateQueryNode): CompiledQuery {
88
+ const ctx = this.createCompilerContext();
89
+ const rawSql = this.compileUpdateAst(ast, ctx).trim();
90
+ const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
91
+ return {
92
+ sql,
93
+ params: [...ctx.params]
94
+ };
95
+ }
96
+
97
+ compileDelete(ast: DeleteQueryNode): CompiledQuery {
98
+ const ctx = this.createCompilerContext();
99
+ const rawSql = this.compileDeleteAst(ast, ctx).trim();
100
+ const sql = rawSql.endsWith(';') ? rawSql : `${rawSql};`;
101
+ return {
102
+ sql,
103
+ params: [...ctx.params]
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Compiles SELECT query AST to SQL (to be implemented by concrete dialects)
109
+ * @param ast - Query AST
110
+ * @param ctx - Compiler context
111
+ * @returns SQL string
112
+ */
113
+ protected abstract compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string;
114
+
115
+ protected abstract compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string;
116
+ protected abstract compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string;
117
+ protected abstract compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string;
118
118
 
119
119
  /**
120
120
  * Quotes an SQL identifier (to be implemented by concrete dialects)
@@ -129,18 +129,18 @@ export abstract class Dialect
129
129
  * @param ctx - Compiler context
130
130
  * @returns SQL WHERE clause or empty string
131
131
  */
132
- protected compileWhere(where: ExpressionNode | undefined, ctx: CompilerContext): string {
133
- if (!where) return '';
134
- return ` WHERE ${this.compileExpression(where, ctx)}`;
135
- }
136
-
137
- protected compileReturning(
138
- returning: ColumnNode[] | undefined,
139
- ctx: CompilerContext
140
- ): string {
141
- if (!returning || returning.length === 0) return '';
142
- throw new Error('RETURNING is not supported by this dialect.');
143
- }
132
+ protected compileWhere(where: ExpressionNode | undefined, ctx: CompilerContext): string {
133
+ if (!where) return '';
134
+ return ` WHERE ${this.compileExpression(where, ctx)}`;
135
+ }
136
+
137
+ protected compileReturning(
138
+ returning: ColumnNode[] | undefined,
139
+ ctx: CompilerContext
140
+ ): string {
141
+ if (!returning || returning.length === 0) return '';
142
+ throw new Error('RETURNING is not supported by this dialect.');
143
+ }
144
144
 
145
145
  /**
146
146
  * Generates subquery for EXISTS expressions