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,6 +1,6 @@
1
- import { CompilerContext, Dialect } from '../abstract';
2
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query';
3
- import { JsonPathNode } from '../../ast/expression';
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
4
 
5
5
  /**
6
6
  * Microsoft SQL Server dialect implementation
@@ -48,7 +48,7 @@ export class SqlServerDialect extends Dialect {
48
48
  * @param ctx - Compiler context
49
49
  * @returns SQL Server SQL string
50
50
  */
51
- protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
51
+ protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
52
52
  const columns = ast.columns.map(c => {
53
53
  let expr = '';
54
54
  if (c.type === 'Function') {
@@ -111,31 +111,31 @@ export class SqlServerDialect extends Dialect {
111
111
  }).join(', ') + ' '
112
112
  : '';
113
113
 
114
- return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy};`;
115
- }
116
-
117
- protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
118
- const table = this.quoteIdentifier(ast.into.name);
119
- const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
120
- const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
121
- return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
122
- }
123
-
124
- protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
125
- const table = this.quoteIdentifier(ast.table.name);
126
- const assignments = ast.set.map(assignment => {
127
- const col = assignment.column;
128
- const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
129
- const value = this.compileOperand(assignment.value, ctx);
130
- return `${target} = ${value}`;
131
- }).join(', ');
132
- const whereClause = this.compileWhere(ast.where, ctx);
133
- return `UPDATE ${table} SET ${assignments}${whereClause};`;
134
- }
135
-
136
- protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
137
- const table = this.quoteIdentifier(ast.from.name);
138
- const whereClause = this.compileWhere(ast.where, ctx);
139
- return `DELETE FROM ${table}${whereClause};`;
140
- }
114
+ return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy};`;
115
+ }
116
+
117
+ protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
118
+ const table = this.quoteIdentifier(ast.into.name);
119
+ const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
120
+ const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
121
+ return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
122
+ }
123
+
124
+ protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
125
+ const table = this.quoteIdentifier(ast.table.name);
126
+ const assignments = ast.set.map(assignment => {
127
+ const col = assignment.column;
128
+ const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
129
+ const value = this.compileOperand(assignment.value, ctx);
130
+ return `${target} = ${value}`;
131
+ }).join(', ');
132
+ const whereClause = this.compileWhere(ast.where, ctx);
133
+ return `UPDATE ${table} SET ${assignments}${whereClause};`;
134
+ }
135
+
136
+ protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
137
+ const table = this.quoteIdentifier(ast.from.name);
138
+ const whereClause = this.compileWhere(ast.where, ctx);
139
+ return `DELETE FROM ${table}${whereClause};`;
140
+ }
141
141
  }
@@ -1,6 +1,6 @@
1
- import { CompilerContext, Dialect } from '../abstract';
2
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query';
3
- import { JsonPathNode } from '../../ast/expression';
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
4
 
5
5
  /**
6
6
  * MySQL dialect implementation
@@ -39,7 +39,7 @@ export class MySqlDialect extends Dialect {
39
39
  * @param ctx - Compiler context
40
40
  * @returns MySQL SQL string
41
41
  */
42
- protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
42
+ protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
43
43
  const columns = ast.columns.map(c => {
44
44
  let expr = '';
45
45
  if (c.type === 'Function') {
@@ -98,31 +98,31 @@ export class MySqlDialect extends Dialect {
98
98
  })()
99
99
  : '';
100
100
 
101
- return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
102
- }
103
-
104
- protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
105
- const table = this.quoteIdentifier(ast.into.name);
106
- const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
107
- const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
108
- return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
109
- }
110
-
111
- protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
112
- const table = this.quoteIdentifier(ast.table.name);
113
- const assignments = ast.set.map(assignment => {
114
- const col = assignment.column;
115
- const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
116
- const value = this.compileOperand(assignment.value, ctx);
117
- return `${target} = ${value}`;
118
- }).join(', ');
119
- const whereClause = this.compileWhere(ast.where, ctx);
120
- return `UPDATE ${table} SET ${assignments}${whereClause};`;
121
- }
122
-
123
- protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
124
- const table = this.quoteIdentifier(ast.from.name);
125
- const whereClause = this.compileWhere(ast.where, ctx);
126
- return `DELETE FROM ${table}${whereClause};`;
127
- }
101
+ return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
102
+ }
103
+
104
+ protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
105
+ const table = this.quoteIdentifier(ast.into.name);
106
+ const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
107
+ const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
108
+ return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
109
+ }
110
+
111
+ protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
112
+ const table = this.quoteIdentifier(ast.table.name);
113
+ const assignments = ast.set.map(assignment => {
114
+ const col = assignment.column;
115
+ const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
116
+ const value = this.compileOperand(assignment.value, ctx);
117
+ return `${target} = ${value}`;
118
+ }).join(', ');
119
+ const whereClause = this.compileWhere(ast.where, ctx);
120
+ return `UPDATE ${table} SET ${assignments}${whereClause};`;
121
+ }
122
+
123
+ protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
124
+ const table = this.quoteIdentifier(ast.from.name);
125
+ const whereClause = this.compileWhere(ast.where, ctx);
126
+ return `DELETE FROM ${table}${whereClause};`;
127
+ }
128
128
  }
@@ -1,6 +1,6 @@
1
- import { CompilerContext, Dialect } from '../abstract';
2
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query';
3
- import { JsonPathNode, ColumnNode } from '../../ast/expression';
1
+ import { CompilerContext, Dialect } from '../abstract.js';
2
+ import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query.js';
3
+ import { JsonPathNode, ColumnNode } from '../../ast/expression.js';
4
4
 
5
5
  /**
6
6
  * PostgreSQL dialect implementation
@@ -39,7 +39,7 @@ export class PostgresDialect extends Dialect {
39
39
  * @param ctx - Compiler context
40
40
  * @returns PostgreSQL SQL string
41
41
  */
42
- protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
42
+ protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
43
43
  const columns = ast.columns.map(c => {
44
44
  let expr = '';
45
45
  if (c.type === 'Function') {
@@ -98,45 +98,45 @@ export class PostgresDialect extends Dialect {
98
98
  })()
99
99
  : '';
100
100
 
101
- return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
102
- }
103
-
104
- protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
105
- const table = this.quoteIdentifier(ast.into.name);
106
- const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
107
- const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
108
- const returning = this.compileReturning(ast.returning, ctx);
109
- return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning};`;
110
- }
111
-
112
- protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
113
- const table = this.quoteIdentifier(ast.table.name);
114
- const assignments = ast.set.map(assignment => {
115
- const col = assignment.column;
116
- const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
117
- const value = this.compileOperand(assignment.value, ctx);
118
- return `${target} = ${value}`;
119
- }).join(', ');
120
- const whereClause = this.compileWhere(ast.where, ctx);
121
- const returning = this.compileReturning(ast.returning, ctx);
122
- return `UPDATE ${table} SET ${assignments}${whereClause}${returning};`;
123
- }
124
-
125
- protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
126
- const table = this.quoteIdentifier(ast.from.name);
127
- const whereClause = this.compileWhere(ast.where, ctx);
128
- const returning = this.compileReturning(ast.returning, ctx);
129
- return `DELETE FROM ${table}${whereClause}${returning};`;
130
- }
131
-
132
- protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
133
- if (!returning || returning.length === 0) return '';
134
- const columns = returning
135
- .map(column => {
136
- const tablePart = column.table ? `${this.quoteIdentifier(column.table)}.` : '';
137
- return `${tablePart}${this.quoteIdentifier(column.name)}`;
138
- })
139
- .join(', ');
140
- return ` RETURNING ${columns}`;
141
- }
101
+ return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
102
+ }
103
+
104
+ protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
105
+ const table = this.quoteIdentifier(ast.into.name);
106
+ const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
107
+ const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
108
+ const returning = this.compileReturning(ast.returning, ctx);
109
+ return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning};`;
110
+ }
111
+
112
+ protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
113
+ const table = this.quoteIdentifier(ast.table.name);
114
+ const assignments = ast.set.map(assignment => {
115
+ const col = assignment.column;
116
+ const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
117
+ const value = this.compileOperand(assignment.value, ctx);
118
+ return `${target} = ${value}`;
119
+ }).join(', ');
120
+ const whereClause = this.compileWhere(ast.where, ctx);
121
+ const returning = this.compileReturning(ast.returning, ctx);
122
+ return `UPDATE ${table} SET ${assignments}${whereClause}${returning};`;
123
+ }
124
+
125
+ protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
126
+ const table = this.quoteIdentifier(ast.from.name);
127
+ const whereClause = this.compileWhere(ast.where, ctx);
128
+ const returning = this.compileReturning(ast.returning, ctx);
129
+ return `DELETE FROM ${table}${whereClause}${returning};`;
130
+ }
131
+
132
+ protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
133
+ if (!returning || returning.length === 0) return '';
134
+ const columns = returning
135
+ .map(column => {
136
+ const tablePart = column.table ? `${this.quoteIdentifier(column.table)}.` : '';
137
+ return `${tablePart}${this.quoteIdentifier(column.name)}`;
138
+ })
139
+ .join(', ');
140
+ return ` RETURNING ${columns}`;
141
+ }
142
142
  }
@@ -1,6 +1,6 @@
1
- import { CompilerContext, Dialect } from '../abstract';
2
- import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query';
3
- import { JsonPathNode, ColumnNode } from '../../ast/expression';
1
+ import { CompilerContext, Dialect } from '../abstract.js';
2
+ import { SelectQueryNode, InsertQueryNode, UpdateQueryNode, DeleteQueryNode } from '../../ast/query.js';
3
+ import { JsonPathNode, ColumnNode } from '../../ast/expression.js';
4
4
 
5
5
  /**
6
6
  * SQLite dialect implementation
@@ -39,7 +39,7 @@ export class SqliteDialect extends Dialect {
39
39
  * @param ctx - Compiler context
40
40
  * @returns SQLite SQL string
41
41
  */
42
- protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
42
+ protected compileSelectAst(ast: SelectQueryNode, ctx: CompilerContext): string {
43
43
  const columns = ast.columns.map(c => {
44
44
  let expr = '';
45
45
  if (c.type === 'Function') {
@@ -102,45 +102,45 @@ export class SqliteDialect extends Dialect {
102
102
  })()
103
103
  : '';
104
104
 
105
- return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
106
- }
107
-
108
- protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
109
- const table = this.quoteIdentifier(ast.into.name);
110
- const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
111
- const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
112
- const returning = this.compileReturning(ast.returning, ctx);
113
- return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning};`;
114
- }
115
-
116
- protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
117
- const table = this.quoteIdentifier(ast.table.name);
118
- const assignments = ast.set.map(assignment => {
119
- const col = assignment.column;
120
- const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
121
- const value = this.compileOperand(assignment.value, ctx);
122
- return `${target} = ${value}`;
123
- }).join(', ');
124
- const whereClause = this.compileWhere(ast.where, ctx);
125
- const returning = this.compileReturning(ast.returning, ctx);
126
- return `UPDATE ${table} SET ${assignments}${whereClause}${returning};`;
127
- }
128
-
129
- protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
130
- const table = this.quoteIdentifier(ast.from.name);
131
- const whereClause = this.compileWhere(ast.where, ctx);
132
- const returning = this.compileReturning(ast.returning, ctx);
133
- return `DELETE FROM ${table}${whereClause}${returning};`;
134
- }
135
-
136
- protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
137
- if (!returning || returning.length === 0) return '';
138
- const columns = returning
139
- .map(column => {
140
- const tablePart = column.table ? `${this.quoteIdentifier(column.table)}.` : '';
141
- return `${tablePart}${this.quoteIdentifier(column.name)}`;
142
- })
143
- .join(', ');
144
- return ` RETURNING ${columns}`;
145
- }
105
+ return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
106
+ }
107
+
108
+ protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
109
+ const table = this.quoteIdentifier(ast.into.name);
110
+ const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
111
+ const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
112
+ const returning = this.compileReturning(ast.returning, ctx);
113
+ return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning};`;
114
+ }
115
+
116
+ protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
117
+ const table = this.quoteIdentifier(ast.table.name);
118
+ const assignments = ast.set.map(assignment => {
119
+ const col = assignment.column;
120
+ const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
121
+ const value = this.compileOperand(assignment.value, ctx);
122
+ return `${target} = ${value}`;
123
+ }).join(', ');
124
+ const whereClause = this.compileWhere(ast.where, ctx);
125
+ const returning = this.compileReturning(ast.returning, ctx);
126
+ return `UPDATE ${table} SET ${assignments}${whereClause}${returning};`;
127
+ }
128
+
129
+ protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
130
+ const table = this.quoteIdentifier(ast.from.name);
131
+ const whereClause = this.compileWhere(ast.where, ctx);
132
+ const returning = this.compileReturning(ast.returning, ctx);
133
+ return `DELETE FROM ${table}${whereClause}${returning};`;
134
+ }
135
+
136
+ protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
137
+ if (!returning || returning.length === 0) return '';
138
+ const columns = returning
139
+ .map(column => {
140
+ const tablePart = column.table ? `${this.quoteIdentifier(column.table)}.` : '';
141
+ return `${tablePart}${this.quoteIdentifier(column.name)}`;
142
+ })
143
+ .join(', ');
144
+ return ` RETURNING ${columns}`;
145
+ }
146
146
  }
@@ -1,39 +1,39 @@
1
- import { SQL_OPERATORS, SqlOperator } from './sql';
2
-
3
- /**
4
- * Configuration for how SQL operators map to TypeScript builder helpers
5
- */
6
- export interface SqlOperatorConfig {
7
- /**
8
- * SQL operator literal
9
- */
10
- sql: SqlOperator;
11
- /**
12
- * Corresponding TypeScript helper name
13
- */
14
- tsName: string;
15
- }
16
-
17
- /**
18
- * Registry of supported SQL operators and their companion helper names
19
- */
20
- export const SQL_OPERATOR_REGISTRY: Record<SqlOperator, SqlOperatorConfig> = {
21
- [SQL_OPERATORS.EQUALS]: { sql: SQL_OPERATORS.EQUALS, tsName: 'eq' },
22
- [SQL_OPERATORS.NOT_EQUALS]: { sql: SQL_OPERATORS.NOT_EQUALS, tsName: 'neq' },
23
- [SQL_OPERATORS.GREATER_THAN]: { sql: SQL_OPERATORS.GREATER_THAN, tsName: 'gt' },
24
- [SQL_OPERATORS.GREATER_OR_EQUAL]: { sql: SQL_OPERATORS.GREATER_OR_EQUAL, tsName: 'gte' },
25
- [SQL_OPERATORS.LESS_THAN]: { sql: SQL_OPERATORS.LESS_THAN, tsName: 'lt' },
26
- [SQL_OPERATORS.LESS_OR_EQUAL]: { sql: SQL_OPERATORS.LESS_OR_EQUAL, tsName: 'lte' },
27
- [SQL_OPERATORS.LIKE]: { sql: SQL_OPERATORS.LIKE, tsName: 'like' },
28
- [SQL_OPERATORS.NOT_LIKE]: { sql: SQL_OPERATORS.NOT_LIKE, tsName: 'notLike' },
29
- [SQL_OPERATORS.IN]: { sql: SQL_OPERATORS.IN, tsName: 'inList' },
30
- [SQL_OPERATORS.NOT_IN]: { sql: SQL_OPERATORS.NOT_IN, tsName: 'notInList' },
31
- [SQL_OPERATORS.IS_NULL]: { sql: SQL_OPERATORS.IS_NULL, tsName: 'isNull' },
32
- [SQL_OPERATORS.IS_NOT_NULL]: { sql: SQL_OPERATORS.IS_NOT_NULL, tsName: 'isNotNull' },
33
- [SQL_OPERATORS.AND]: { sql: SQL_OPERATORS.AND, tsName: 'and' },
34
- [SQL_OPERATORS.OR]: { sql: SQL_OPERATORS.OR, tsName: 'or' },
35
- [SQL_OPERATORS.BETWEEN]: { sql: SQL_OPERATORS.BETWEEN, tsName: 'between' },
36
- [SQL_OPERATORS.NOT_BETWEEN]: { sql: SQL_OPERATORS.NOT_BETWEEN, tsName: 'notBetween' },
37
- [SQL_OPERATORS.EXISTS]: { sql: SQL_OPERATORS.EXISTS, tsName: 'exists' },
38
- [SQL_OPERATORS.NOT_EXISTS]: { sql: SQL_OPERATORS.NOT_EXISTS, tsName: 'notExists' }
39
- };
1
+ import { SQL_OPERATORS, SqlOperator } from './sql.js';
2
+
3
+ /**
4
+ * Configuration for how SQL operators map to TypeScript builder helpers
5
+ */
6
+ export interface SqlOperatorConfig {
7
+ /**
8
+ * SQL operator literal
9
+ */
10
+ sql: SqlOperator;
11
+ /**
12
+ * Corresponding TypeScript helper name
13
+ */
14
+ tsName: string;
15
+ }
16
+
17
+ /**
18
+ * Registry of supported SQL operators and their companion helper names
19
+ */
20
+ export const SQL_OPERATOR_REGISTRY: Record<SqlOperator, SqlOperatorConfig> = {
21
+ [SQL_OPERATORS.EQUALS]: { sql: SQL_OPERATORS.EQUALS, tsName: 'eq' },
22
+ [SQL_OPERATORS.NOT_EQUALS]: { sql: SQL_OPERATORS.NOT_EQUALS, tsName: 'neq' },
23
+ [SQL_OPERATORS.GREATER_THAN]: { sql: SQL_OPERATORS.GREATER_THAN, tsName: 'gt' },
24
+ [SQL_OPERATORS.GREATER_OR_EQUAL]: { sql: SQL_OPERATORS.GREATER_OR_EQUAL, tsName: 'gte' },
25
+ [SQL_OPERATORS.LESS_THAN]: { sql: SQL_OPERATORS.LESS_THAN, tsName: 'lt' },
26
+ [SQL_OPERATORS.LESS_OR_EQUAL]: { sql: SQL_OPERATORS.LESS_OR_EQUAL, tsName: 'lte' },
27
+ [SQL_OPERATORS.LIKE]: { sql: SQL_OPERATORS.LIKE, tsName: 'like' },
28
+ [SQL_OPERATORS.NOT_LIKE]: { sql: SQL_OPERATORS.NOT_LIKE, tsName: 'notLike' },
29
+ [SQL_OPERATORS.IN]: { sql: SQL_OPERATORS.IN, tsName: 'inList' },
30
+ [SQL_OPERATORS.NOT_IN]: { sql: SQL_OPERATORS.NOT_IN, tsName: 'notInList' },
31
+ [SQL_OPERATORS.IS_NULL]: { sql: SQL_OPERATORS.IS_NULL, tsName: 'isNull' },
32
+ [SQL_OPERATORS.IS_NOT_NULL]: { sql: SQL_OPERATORS.IS_NOT_NULL, tsName: 'isNotNull' },
33
+ [SQL_OPERATORS.AND]: { sql: SQL_OPERATORS.AND, tsName: 'and' },
34
+ [SQL_OPERATORS.OR]: { sql: SQL_OPERATORS.OR, tsName: 'or' },
35
+ [SQL_OPERATORS.BETWEEN]: { sql: SQL_OPERATORS.BETWEEN, tsName: 'between' },
36
+ [SQL_OPERATORS.NOT_BETWEEN]: { sql: SQL_OPERATORS.NOT_BETWEEN, tsName: 'notBetween' },
37
+ [SQL_OPERATORS.EXISTS]: { sql: SQL_OPERATORS.EXISTS, tsName: 'exists' },
38
+ [SQL_OPERATORS.NOT_EXISTS]: { sql: SQL_OPERATORS.NOT_EXISTS, tsName: 'notExists' }
39
+ };
@@ -0,0 +1,126 @@
1
+ import { SelectQueryBuilder } from '../query-builder/select.js';
2
+ import {
3
+ hasMany,
4
+ belongsTo,
5
+ belongsToMany,
6
+ RelationKinds,
7
+ type RelationDef
8
+ } from '../schema/relation.js';
9
+ import { TableDef } from '../schema/table.js';
10
+ import {
11
+ buildTableDef,
12
+ EntityConstructor,
13
+ EntityOrTableTarget,
14
+ EntityOrTableTargetResolver,
15
+ getAllEntityMetadata,
16
+ getEntityMetadata,
17
+ RelationMetadata
18
+ } from '../orm/entity-metadata.js';
19
+
20
+ const isTableDef = (value: unknown): value is TableDef => {
21
+ return typeof value === 'object' && value !== null && 'columns' in (value as TableDef);
22
+ };
23
+
24
+ const unwrapTarget = (target: EntityOrTableTargetResolver): EntityOrTableTarget => {
25
+ if (typeof target === 'function' && (target as Function).prototype === undefined) {
26
+ return (target as () => EntityOrTableTarget)();
27
+ }
28
+ return target as EntityOrTableTarget;
29
+ };
30
+
31
+ const resolveTableTarget = (
32
+ target: EntityOrTableTargetResolver,
33
+ tableMap: Map<EntityConstructor, TableDef>
34
+ ): TableDef => {
35
+ const resolved = unwrapTarget(target);
36
+ if (isTableDef(resolved)) {
37
+ return resolved;
38
+ }
39
+ const table = tableMap.get(resolved as EntityConstructor);
40
+ if (!table) {
41
+ throw new Error(`Entity '${(resolved as EntityConstructor).name}' is not registered with decorators`);
42
+ }
43
+ return table;
44
+ };
45
+
46
+ const buildRelationDefinitions = (
47
+ meta: { relations: Record<string, RelationMetadata> },
48
+ tableMap: Map<EntityConstructor, TableDef>
49
+ ): Record<string, RelationDef> => {
50
+ const relations: Record<string, RelationDef> = {};
51
+
52
+ for (const [name, relation] of Object.entries(meta.relations)) {
53
+ switch (relation.kind) {
54
+ case RelationKinds.HasMany: {
55
+ relations[name] = hasMany(
56
+ resolveTableTarget(relation.target, tableMap),
57
+ relation.foreignKey,
58
+ relation.localKey,
59
+ relation.cascade
60
+ );
61
+ break;
62
+ }
63
+ case RelationKinds.BelongsTo: {
64
+ relations[name] = belongsTo(
65
+ resolveTableTarget(relation.target, tableMap),
66
+ relation.foreignKey,
67
+ relation.localKey,
68
+ relation.cascade
69
+ );
70
+ break;
71
+ }
72
+ case RelationKinds.BelongsToMany: {
73
+ relations[name] = belongsToMany(
74
+ resolveTableTarget(relation.target, tableMap),
75
+ resolveTableTarget(relation.pivotTable, tableMap),
76
+ {
77
+ pivotForeignKeyToRoot: relation.pivotForeignKeyToRoot,
78
+ pivotForeignKeyToTarget: relation.pivotForeignKeyToTarget,
79
+ localKey: relation.localKey,
80
+ targetKey: relation.targetKey,
81
+ pivotPrimaryKey: relation.pivotPrimaryKey,
82
+ defaultPivotColumns: relation.defaultPivotColumns,
83
+ cascade: relation.cascade
84
+ }
85
+ );
86
+ break;
87
+ }
88
+ }
89
+ }
90
+
91
+ return relations;
92
+ };
93
+
94
+ export const bootstrapEntities = (): TableDef[] => {
95
+ const metas = getAllEntityMetadata();
96
+ const tableMap = new Map<EntityConstructor, TableDef>();
97
+
98
+ for (const meta of metas) {
99
+ const table = buildTableDef(meta);
100
+ tableMap.set(meta.target, table);
101
+ }
102
+
103
+ for (const meta of metas) {
104
+ const table = meta.table!;
105
+ const relations = buildRelationDefinitions(meta, tableMap);
106
+ table.relations = relations;
107
+ }
108
+
109
+ return metas.map(meta => meta.table!) as TableDef[];
110
+ };
111
+
112
+ export const getTableDefFromEntity = (ctor: EntityConstructor): TableDef | undefined => {
113
+ const meta = getEntityMetadata(ctor);
114
+ if (!meta) return undefined;
115
+ return meta.table;
116
+ };
117
+
118
+ export const selectFromEntity = <TTable extends TableDef>(
119
+ ctor: EntityConstructor
120
+ ): SelectQueryBuilder<any, TTable> => {
121
+ const table = getTableDefFromEntity(ctor);
122
+ if (!table) {
123
+ throw new Error('Entity metadata has not been bootstrapped');
124
+ }
125
+ return new SelectQueryBuilder(table as TTable);
126
+ };
@@ -0,0 +1,78 @@
1
+ import { ColumnDef, ColumnType } from '../schema/column.js';
2
+ import {
3
+ addColumnMetadata,
4
+ EntityConstructor,
5
+ ColumnDefLike,
6
+ ensureEntityMetadata
7
+ } from '../orm/entity-metadata.js';
8
+
9
+ export interface ColumnOptions {
10
+ type: ColumnType;
11
+ args?: ColumnDef['args'];
12
+ notNull?: boolean;
13
+ primary?: boolean;
14
+ }
15
+
16
+ export type ColumnInput = ColumnOptions | ColumnDef;
17
+
18
+ const normalizeColumnInput = (input: ColumnInput): ColumnDefLike => {
19
+ const column: ColumnDefLike = {
20
+ type: (input as ColumnOptions).type ?? (input as ColumnDef).type,
21
+ args: (input as ColumnOptions).args ?? (input as ColumnDef).args,
22
+ notNull: (input as ColumnOptions).notNull ?? (input as ColumnDef).notNull,
23
+ primary: (input as ColumnOptions).primary ?? (input as ColumnDef).primary
24
+ };
25
+
26
+ if (!column.type) {
27
+ throw new Error('Column decorator requires a column type');
28
+ }
29
+
30
+ return column;
31
+ };
32
+
33
+ const normalizePropertyName = (name: string | symbol): string => {
34
+ if (typeof name === 'symbol') {
35
+ return name.description ?? name.toString();
36
+ }
37
+ return name;
38
+ };
39
+
40
+ const resolveConstructor = (target: unknown): EntityConstructor | undefined => {
41
+ if (typeof target === 'function') {
42
+ return target as EntityConstructor;
43
+ }
44
+
45
+ if (target && typeof (target as any).constructor === 'function') {
46
+ return (target as any).constructor as EntityConstructor;
47
+ }
48
+
49
+ return undefined;
50
+ };
51
+
52
+ const registerColumn = (ctor: EntityConstructor, propertyName: string, column: ColumnDefLike): void => {
53
+ const meta = ensureEntityMetadata(ctor);
54
+ if (meta.columns[propertyName]) {
55
+ return;
56
+ }
57
+ addColumnMetadata(ctor, propertyName, column);
58
+ };
59
+
60
+ export function Column(definition: ColumnInput) {
61
+ const normalized = normalizeColumnInput(definition);
62
+ const decorator = (target: object, propertyKey: string | symbol) => {
63
+ const propertyName = normalizePropertyName(propertyKey);
64
+ const ctor = resolveConstructor(target);
65
+ if (!ctor) {
66
+ throw new Error('Unable to resolve constructor when registering column metadata');
67
+ }
68
+ registerColumn(ctor, propertyName, { ...normalized });
69
+ };
70
+
71
+ return decorator as PropertyDecorator;
72
+ }
73
+
74
+ export function PrimaryKey(definition: ColumnInput) {
75
+ const normalized = normalizeColumnInput(definition);
76
+ normalized.primary = true;
77
+ return Column(normalized);
78
+ }