metal-orm 1.0.8 → 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.
- package/README.md +12 -1
- package/dist/decorators/index.cjs +2564 -0
- package/dist/decorators/index.cjs.map +1 -0
- package/dist/decorators/index.d.cts +53 -0
- package/dist/decorators/index.d.ts +53 -0
- package/dist/decorators/index.js +2530 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/index.cjs +4227 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +701 -0
- package/dist/index.d.ts +701 -0
- package/dist/index.js +4131 -0
- package/dist/index.js.map +1 -0
- package/dist/select-654m4qy8.d.cts +1522 -0
- package/dist/select-654m4qy8.d.ts +1522 -0
- package/package.json +27 -20
- package/src/codegen/typescript.ts +405 -393
- package/src/core/ast/aggregate-functions.ts +30 -0
- package/src/core/ast/builders.ts +43 -0
- package/src/core/ast/expression-builders.ts +310 -0
- package/src/core/ast/expression-nodes.ts +211 -0
- package/src/core/ast/expression-visitor.ts +99 -0
- package/src/core/ast/expression.ts +5 -0
- package/src/{utils → core/ast}/join-node.ts +20 -20
- package/src/{ast → core/ast}/join.ts +18 -18
- package/src/{ast → core/ast}/query.ts +113 -113
- package/src/core/ast/window-functions.ts +140 -0
- package/src/{dialect → core/dialect}/abstract.ts +94 -94
- package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
- package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
- package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
- package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
- package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
- package/src/decorators/bootstrap.ts +126 -0
- package/src/decorators/column.ts +78 -0
- package/src/decorators/entity.ts +36 -0
- package/src/decorators/index.ts +4 -0
- package/src/decorators/relations.ts +107 -0
- package/src/global.d.ts +1 -0
- package/src/index.ts +22 -22
- package/src/orm/db-executor.ts +11 -0
- package/src/orm/domain-event-bus.ts +52 -0
- package/src/{runtime → orm}/entity-meta.ts +52 -52
- package/src/orm/entity-metadata.ts +140 -0
- package/src/{runtime → orm}/entity.ts +252 -252
- package/src/{runtime → orm}/execute.ts +36 -36
- package/src/{runtime → orm}/hydration.ts +103 -103
- package/src/orm/identity-map.ts +37 -0
- package/src/{runtime → orm}/lazy-batch.ts +205 -205
- package/src/orm/orm-context.ts +154 -0
- package/src/orm/relation-change-processor.ts +140 -0
- package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
- package/src/{runtime → orm}/relations/has-many.ts +111 -111
- package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
- package/src/orm/runtime-types.ts +39 -0
- package/src/orm/transaction-runner.ts +17 -0
- package/src/orm/unit-of-work.ts +232 -0
- package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
- package/src/{builder → query-builder}/delete-query-state.ts +38 -42
- package/src/{builder → query-builder}/delete.ts +46 -57
- package/src/{builder → query-builder}/hydration-manager.ts +87 -87
- package/src/{builder → query-builder}/hydration-planner.ts +182 -182
- package/src/{builder → query-builder}/insert-query-state.ts +51 -62
- package/src/{builder → query-builder}/insert.ts +48 -59
- package/src/{builder → query-builder}/query-ast-service.ts +208 -226
- package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
- package/src/{builder → query-builder}/relation-conditions.ts +112 -112
- package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
- package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
- package/src/{builder → query-builder}/relation-service.ts +284 -284
- package/src/{builder → query-builder}/relation-types.ts +21 -21
- package/src/{builder → query-builder}/relation-utils.ts +12 -12
- package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
- package/src/{builder → query-builder}/select-query-state.ts +179 -179
- package/src/{builder → query-builder}/select.ts +78 -69
- package/src/{builder → query-builder}/update-query-state.ts +55 -59
- package/src/{builder → query-builder}/update.ts +50 -61
- package/src/schema/column.ts +25 -25
- package/src/schema/relation.ts +116 -116
- package/src/schema/table.ts +34 -34
- package/src/schema/types.ts +76 -76
- package/.github/workflows/publish-metal-orm.yml +0 -38
- package/ROADMAP.md +0 -125
- package/docs/CHANGES.md +0 -104
- package/docs/advanced-features.md +0 -176
- package/docs/api-reference.md +0 -31
- package/docs/dml-operations.md +0 -156
- package/docs/getting-started.md +0 -171
- package/docs/hydration.md +0 -115
- package/docs/index.md +0 -36
- package/docs/multi-dialect-support.md +0 -59
- package/docs/query-builder.md +0 -135
- package/docs/runtime.md +0 -105
- package/docs/schema-definition.md +0 -112
- package/metadata.json +0 -5
- package/playground/api/playground-api.ts +0 -94
- package/playground/index.html +0 -15
- package/playground/src/App.css +0 -1
- package/playground/src/App.tsx +0 -114
- package/playground/src/components/CodeDisplay.tsx +0 -43
- package/playground/src/components/QueryExecutor.tsx +0 -189
- package/playground/src/components/ResultsTable.tsx +0 -67
- package/playground/src/components/ResultsTabs.tsx +0 -105
- package/playground/src/components/ScenarioList.tsx +0 -56
- package/playground/src/components/logo.svg +0 -45
- package/playground/src/data/scenarios.ts +0 -2
- package/playground/src/main.tsx +0 -9
- package/playground/src/services/PlaygroundApiService.ts +0 -60
- package/postcss.config.cjs +0 -5
- package/sql_sql-ansi-cheatsheet-2025.md +0 -264
- package/src/ast/expression.ts +0 -658
- package/src/builder/operations/cte-manager.ts +0 -34
- package/src/builder/operations/filter-manager.ts +0 -68
- package/src/builder/operations/join-manager.ts +0 -36
- package/src/builder/operations/pagination-manager.ts +0 -36
- package/src/playground/features/playground/api/types.ts +0 -16
- package/src/playground/features/playground/clients/MockClient.ts +0 -17
- package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
- package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
- package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
- package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
- package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
- package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
- package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
- package/src/playground/features/playground/data/scenarios/index.ts +0 -29
- package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
- package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
- package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
- package/src/playground/features/playground/data/scenarios/types.ts +0 -70
- package/src/playground/features/playground/data/schema.ts +0 -91
- package/src/playground/features/playground/data/seed.ts +0 -104
- package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
- package/src/runtime/orm-context.ts +0 -539
- package/tests/belongs-to-many.test.ts +0 -57
- package/tests/between.test.ts +0 -43
- package/tests/case-expression.test.ts +0 -58
- package/tests/complex-exists.test.ts +0 -230
- package/tests/cte.test.ts +0 -118
- package/tests/dml.test.ts +0 -206
- package/tests/exists.test.ts +0 -127
- package/tests/like.test.ts +0 -33
- package/tests/orm-runtime.test.ts +0 -254
- package/tests/postgres.test.ts +0 -30
- package/tests/right-join.test.ts +0 -89
- package/tests/subquery-having.test.ts +0 -193
- package/tests/window-function.test.ts +0 -151
- package/tsconfig.json +0 -30
- package/tsup.config.ts +0 -10
- package/vite.config.ts +0 -22
- package/vitest.config.ts +0 -14
- /package/src/{constants → core/sql}/sql.ts +0 -0
- /package/src/{runtime → orm}/als.ts +0 -0
- /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
|
+
}
|