@entity-access/entity-access 1.0.55 → 1.0.56
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/dist/compiler/NamingConventions.d.ts +7 -0
- package/dist/compiler/NamingConventions.d.ts.map +1 -0
- package/dist/compiler/NamingConventions.js +7 -0
- package/dist/compiler/NamingConventions.js.map +1 -0
- package/dist/compiler/QueryCompiler.d.ts +2 -2
- package/dist/compiler/QueryCompiler.d.ts.map +1 -1
- package/dist/compiler/QueryCompiler.js +8 -3
- package/dist/compiler/QueryCompiler.js.map +1 -1
- package/dist/decorators/Column.d.ts.map +1 -1
- package/dist/decorators/Column.js +3 -0
- package/dist/decorators/Column.js.map +1 -1
- package/dist/decorators/IColumn.d.ts +5 -0
- package/dist/decorators/IColumn.d.ts.map +1 -1
- package/dist/drivers/base/BaseDriver.d.ts.map +1 -1
- package/dist/drivers/base/BaseDriver.js +7 -7
- package/dist/drivers/base/BaseDriver.js.map +1 -1
- package/dist/drivers/postgres/PostgreSqlDriver.js +1 -1
- package/dist/drivers/postgres/PostgreSqlDriver.js.map +1 -1
- package/dist/drivers/sql-server/ExpressionToSqlServer.d.ts.map +1 -1
- package/dist/drivers/sql-server/ExpressionToSqlServer.js +2 -2
- package/dist/drivers/sql-server/ExpressionToSqlServer.js.map +1 -1
- package/dist/drivers/sql-server/SqlServerQueryCompiler.d.ts +1 -1
- package/dist/drivers/sql-server/SqlServerQueryCompiler.d.ts.map +1 -1
- package/dist/drivers/sql-server/SqlServerQueryCompiler.js +6 -2
- package/dist/drivers/sql-server/SqlServerQueryCompiler.js.map +1 -1
- package/dist/entity-query/EntityType.d.ts +7 -5
- package/dist/entity-query/EntityType.d.ts.map +1 -1
- package/dist/entity-query/EntityType.js +31 -14
- package/dist/entity-query/EntityType.js.map +1 -1
- package/dist/eternity/EternityStorage.d.ts +1 -1
- package/dist/eternity/EternityStorage.d.ts.map +1 -1
- package/dist/eternity/EternityStorage.js +4 -4
- package/dist/eternity/EternityStorage.js.map +1 -1
- package/dist/migrations/Migrations.d.ts.map +1 -1
- package/dist/migrations/Migrations.js +5 -4
- package/dist/migrations/Migrations.js.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js +17 -14
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +12 -12
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
- package/dist/model/EntityContext.js.map +1 -1
- package/dist/model/EntityModel.d.ts +4 -1
- package/dist/model/EntityModel.d.ts.map +1 -1
- package/dist/model/EntityModel.js +36 -5
- package/dist/model/EntityModel.js.map +1 -1
- package/dist/model/EntityQuery.d.ts.map +1 -1
- package/dist/model/EntityQuery.js +7 -7
- package/dist/model/EntityQuery.js.map +1 -1
- package/dist/model/SourceExpression.d.ts.map +1 -1
- package/dist/model/SourceExpression.js +3 -4
- package/dist/model/SourceExpression.js.map +1 -1
- package/dist/model/changes/ChangeEntry.js +2 -2
- package/dist/model/changes/ChangeEntry.js.map +1 -1
- package/dist/model/changes/ChangeSet.js +1 -2
- package/dist/model/changes/ChangeSet.js.map +1 -1
- package/dist/model/verification/VerificationSession.d.ts.map +1 -1
- package/dist/model/verification/VerificationSession.js +6 -6
- package/dist/model/verification/VerificationSession.js.map +1 -1
- package/dist/query/ast/DebugStringVisitor.d.ts +1 -2
- package/dist/query/ast/DebugStringVisitor.d.ts.map +1 -1
- package/dist/query/ast/DebugStringVisitor.js +0 -3
- package/dist/query/ast/DebugStringVisitor.js.map +1 -1
- package/dist/query/ast/ExpressionToSql.d.ts +1 -2
- package/dist/query/ast/ExpressionToSql.d.ts.map +1 -1
- package/dist/query/ast/ExpressionToSql.js +16 -14
- package/dist/query/ast/ExpressionToSql.js.map +1 -1
- package/dist/query/ast/Expressions.d.ts +15 -20
- package/dist/query/ast/Expressions.d.ts.map +1 -1
- package/dist/query/ast/Expressions.js +17 -19
- package/dist/query/ast/Expressions.js.map +1 -1
- package/dist/query/ast/IStringTransformer.d.ts +2 -3
- package/dist/query/ast/IStringTransformer.d.ts.map +1 -1
- package/dist/query/ast/IStringTransformer.js +4 -6
- package/dist/query/ast/IStringTransformer.js.map +1 -1
- package/dist/query/ast/Visitor.d.ts +1 -2
- package/dist/query/ast/Visitor.d.ts.map +1 -1
- package/dist/query/ast/Visitor.js +0 -5
- package/dist/query/ast/Visitor.js.map +1 -1
- package/dist/query/expander/QueryExpander.js +2 -2
- package/dist/query/expander/QueryExpander.js.map +1 -1
- package/dist/query/parser/ArrowToExpression.d.ts.map +1 -1
- package/dist/query/parser/ArrowToExpression.js +2 -2
- package/dist/query/parser/ArrowToExpression.js.map +1 -1
- package/dist/tests/eternity/eternity-tests.d.ts.map +1 -1
- package/dist/tests/eternity/eternity-tests.js +1 -1
- package/dist/tests/eternity/eternity-tests.js.map +1 -1
- package/dist/tests/expressions/left-joins/child-joins.js +41 -41
- package/dist/tests/expressions/left-joins/child-joins.js.map +1 -1
- package/dist/tests/expressions/select/select.d.ts.map +1 -1
- package/dist/tests/expressions/select/select.js +2 -2
- package/dist/tests/expressions/select/select.js.map +1 -1
- package/dist/tests/expressions/simple/parse-arrow.js +10 -10
- package/dist/tests/expressions/simple/parse-arrow.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/compiler/NamingConventions.ts +6 -0
- package/src/compiler/QueryCompiler.ts +7 -5
- package/src/decorators/Column.ts +3 -0
- package/src/decorators/IColumn.ts +7 -0
- package/src/drivers/base/BaseDriver.ts +9 -9
- package/src/drivers/postgres/PostgreSqlDriver.ts +1 -1
- package/src/drivers/sql-server/ExpressionToSqlServer.ts +2 -2
- package/src/drivers/sql-server/SqlServerQueryCompiler.ts +5 -2
- package/src/entity-query/EntityType.ts +34 -13
- package/src/eternity/EternityStorage.ts +3 -3
- package/src/migrations/Migrations.ts +5 -3
- package/src/migrations/postgres/PostgresAutomaticMigrations.ts +17 -14
- package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +12 -12
- package/src/model/EntityContext.ts +1 -1
- package/src/model/EntityModel.ts +41 -7
- package/src/model/EntityQuery.ts +7 -7
- package/src/model/SourceExpression.ts +3 -4
- package/src/model/changes/ChangeEntry.ts +2 -2
- package/src/model/changes/ChangeSet.ts +1 -1
- package/src/model/verification/VerificationSession.ts +6 -7
- package/src/query/ast/DebugStringVisitor.ts +1 -5
- package/src/query/ast/ExpressionToSql.ts +18 -15
- package/src/query/ast/Expressions.ts +33 -34
- package/src/query/ast/IStringTransformer.ts +4 -4
- package/src/query/ast/Visitor.ts +1 -7
- package/src/query/expander/QueryExpander.ts +4 -4
- package/src/query/parser/ArrowToExpression.ts +2 -2
- package/src/tests/eternity/eternity-tests.ts +2 -1
- package/src/tests/expressions/left-joins/child-joins.ts +41 -41
- package/src/tests/expressions/select/select.ts +2 -5
- package/src/tests/expressions/simple/parse-arrow.ts +10 -10
|
@@ -3,7 +3,7 @@ import { IClassOf } from "../decorators/IClassOf.js";
|
|
|
3
3
|
import { Query } from "../query/Query.js";
|
|
4
4
|
import NameParser from "../decorators/parser/NameParser.js";
|
|
5
5
|
import SchemaRegistry from "../decorators/SchemaRegistry.js";
|
|
6
|
-
import { Expression, ExpressionAs,
|
|
6
|
+
import { Expression, ExpressionAs, NumberLiteral, SelectStatement, TableLiteral } from "../query/ast/Expressions.js";
|
|
7
7
|
import InstanceCache from "../common/cache/InstanceCache.js";
|
|
8
8
|
import { IIndex } from "../decorators/IIndex.js";
|
|
9
9
|
|
|
@@ -37,10 +37,10 @@ export default class EntityType {
|
|
|
37
37
|
public get fullyQualifiedName() {
|
|
38
38
|
return this.schema
|
|
39
39
|
? TableLiteral.create({
|
|
40
|
-
schema:
|
|
41
|
-
name:
|
|
40
|
+
schema: Expression.identifier(this.schema) ,
|
|
41
|
+
name: Expression.identifier(this.name)
|
|
42
42
|
})
|
|
43
|
-
:
|
|
43
|
+
: Expression.identifier(this.name);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
private fieldMap: Map<string, IColumn> = new Map();
|
|
@@ -50,6 +50,16 @@ export default class EntityType {
|
|
|
50
50
|
private selectAll: SelectStatement;
|
|
51
51
|
private selectOne: SelectStatement;
|
|
52
52
|
|
|
53
|
+
constructor(original?: EntityType) {
|
|
54
|
+
if (!original) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.typeClass = original.typeClass;
|
|
58
|
+
this.name = original.name;
|
|
59
|
+
this.schema = original.schema;
|
|
60
|
+
this.entityName = original.entityName;
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
[addOrCreateColumnSymbol](name: string): IColumn {
|
|
54
64
|
return this.fieldMap.get(name) ?? { name };
|
|
55
65
|
}
|
|
@@ -86,7 +96,7 @@ export default class EntityType {
|
|
|
86
96
|
return this.fieldMap.get(name);
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
addRelation(relation: IEntityRelation) {
|
|
99
|
+
addRelation(relation: IEntityRelation, getInverseModel?: (t) => EntityType) {
|
|
90
100
|
// we will also set fk to the corresponding column
|
|
91
101
|
this.relations.push(relation);
|
|
92
102
|
this.relationMap.set(relation.name, relation);
|
|
@@ -108,8 +118,12 @@ export default class EntityType {
|
|
|
108
118
|
fkColumn.dataType = "BigInt";
|
|
109
119
|
}
|
|
110
120
|
|
|
121
|
+
if (!getInverseModel) {
|
|
122
|
+
return relation;
|
|
123
|
+
}
|
|
124
|
+
|
|
111
125
|
// let us set inverse relations...
|
|
112
|
-
const relatedType =
|
|
126
|
+
const relatedType = getInverseModel(relation.relatedTypeClass);
|
|
113
127
|
relation.relatedEntity = relatedType;
|
|
114
128
|
const inverseRelation: IEntityRelation = {
|
|
115
129
|
name: relation.relatedName,
|
|
@@ -137,12 +151,7 @@ export default class EntityType {
|
|
|
137
151
|
}
|
|
138
152
|
const source = this.fullyQualifiedName;
|
|
139
153
|
const as = Expression.parameter(this.name[0] + "1");
|
|
140
|
-
const fields = this.columns.map((c) =>
|
|
141
|
-
? ExpressionAs.create({
|
|
142
|
-
expression: Expression.member(as, c.columnName),
|
|
143
|
-
alias: QuotedLiteral.create({ literal: c.name })
|
|
144
|
-
})
|
|
145
|
-
: Expression.member(as, c.columnName));
|
|
154
|
+
const fields = this.columns.map((c) => Expression.member(as, c.columnName));
|
|
146
155
|
this.selectAll = SelectStatement.create({
|
|
147
156
|
source,
|
|
148
157
|
model: this,
|
|
@@ -159,7 +168,7 @@ export default class EntityType {
|
|
|
159
168
|
const source = this.fullyQualifiedName;
|
|
160
169
|
const as = Expression.parameter(this.name[0] + "1");
|
|
161
170
|
const fields = [
|
|
162
|
-
|
|
171
|
+
NumberLiteral.one
|
|
163
172
|
];
|
|
164
173
|
this.selectOne = SelectStatement.create({
|
|
165
174
|
source,
|
|
@@ -169,4 +178,16 @@ export default class EntityType {
|
|
|
169
178
|
});
|
|
170
179
|
return { ... this.selectOne };
|
|
171
180
|
}
|
|
181
|
+
|
|
182
|
+
public map(row: any) {
|
|
183
|
+
const c = new this.typeClass();
|
|
184
|
+
for (const iterator of this.columns) {
|
|
185
|
+
const value = row[iterator.columnName];
|
|
186
|
+
if (value === void 0) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
c[iterator.name] = value;
|
|
190
|
+
}
|
|
191
|
+
return c;
|
|
192
|
+
}
|
|
172
193
|
}
|
|
@@ -10,8 +10,8 @@ import WorkflowClock from "./WorkflowClock.js";
|
|
|
10
10
|
@Table("Workflows")
|
|
11
11
|
@Index({
|
|
12
12
|
name: "IX_Workflows_Group",
|
|
13
|
-
columns: [{ name: (x) => x.
|
|
14
|
-
filter: (x) => x.
|
|
13
|
+
columns: [{ name: (x) => x.groupName, descending: false }],
|
|
14
|
+
filter: (x) => x.groupName !== null
|
|
15
15
|
})
|
|
16
16
|
@Index({
|
|
17
17
|
name: "IX_Workflows_ETA",
|
|
@@ -30,7 +30,7 @@ export class WorkflowStorage {
|
|
|
30
30
|
public name: string;
|
|
31
31
|
|
|
32
32
|
@Column({ dataType: "Char", length: 200, nullable: true })
|
|
33
|
-
public
|
|
33
|
+
public groupName: string;
|
|
34
34
|
|
|
35
35
|
@Column({ dataType: "Char"})
|
|
36
36
|
public input: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { modelSymbol } from "../common/symbols/symbols.js";
|
|
1
2
|
import type QueryCompiler from "../compiler/QueryCompiler.js";
|
|
2
3
|
import { IIndex } from "../decorators/IIndex.js";
|
|
3
4
|
import SchemaRegistry from "../decorators/SchemaRegistry.js";
|
|
@@ -10,8 +11,9 @@ export default abstract class Migrations {
|
|
|
10
11
|
constructor(protected compiler: QueryCompiler) {}
|
|
11
12
|
|
|
12
13
|
public async migrate(context: EntityContext) {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const { model } = context;
|
|
15
|
+
for (const s of model.sources.values()) {
|
|
16
|
+
const type = s[modelSymbol] as EntityType;
|
|
15
17
|
await this.migrateTable(context, type);
|
|
16
18
|
|
|
17
19
|
for (const index of type.indexes) {
|
|
@@ -30,7 +32,7 @@ export default abstract class Migrations {
|
|
|
30
32
|
// parse..
|
|
31
33
|
const source = context.query(type.typeClass) as EntityQuery<any>;
|
|
32
34
|
const { target , textQuery } = this.compiler.compileToSql(source, `(p) => ${index.filter}` as any);
|
|
33
|
-
index.filter = textQuery.join("").split(
|
|
35
|
+
index.filter = textQuery.join("").split( source.selectStatement.sourceParameter.name + ".").join("");
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
this.migrateIndex(context, index, type);
|
|
@@ -28,7 +28,7 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
|
|
|
28
28
|
async createIndexes(context: EntityContext, type: EntityType, fkColumns: IColumn[]) {
|
|
29
29
|
for (const iterator of fkColumns) {
|
|
30
30
|
const filter = iterator.nullable
|
|
31
|
-
? `${
|
|
31
|
+
? `${iterator.columnName} IS NOT NULL`
|
|
32
32
|
: "";
|
|
33
33
|
const indexDef: IIndex = {
|
|
34
34
|
name: `IX_${type.name}_${iterator.columnName}`,
|
|
@@ -42,15 +42,15 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
|
|
|
42
42
|
async createColumns(driver: BaseDriver, type: EntityType, nonKeyColumns: IColumn[]) {
|
|
43
43
|
|
|
44
44
|
const name = type.schema
|
|
45
|
-
?
|
|
46
|
-
:
|
|
45
|
+
? type.schema + "." + type.name
|
|
46
|
+
: type.name;
|
|
47
47
|
|
|
48
48
|
if (nonKeyColumns.length > 1) {
|
|
49
49
|
nonKeyColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
for (const iterator of nonKeyColumns) {
|
|
53
|
-
const columnName =
|
|
53
|
+
const columnName = iterator.columnName;
|
|
54
54
|
let def = `ALTER TABLE ${name} ADD COLUMN IF NOT EXISTS ${columnName} `;
|
|
55
55
|
def += this.getColumnDefinition(iterator);
|
|
56
56
|
if (iterator.nullable !== true) {
|
|
@@ -67,8 +67,8 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
|
|
|
67
67
|
async createTable(driver: BaseDriver, type: EntityType, keys: IColumn[]) {
|
|
68
68
|
|
|
69
69
|
const name = type.schema
|
|
70
|
-
?
|
|
71
|
-
:
|
|
70
|
+
? type.schema + "." + type.name
|
|
71
|
+
: type.name;
|
|
72
72
|
|
|
73
73
|
if (keys.length > 1) {
|
|
74
74
|
keys.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
@@ -77,29 +77,32 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
|
|
|
77
77
|
const fields = [];
|
|
78
78
|
|
|
79
79
|
for (const iterator of keys) {
|
|
80
|
-
let def =
|
|
80
|
+
let def = iterator.columnName + " ";
|
|
81
81
|
if (iterator.autoGenerate) {
|
|
82
|
-
def += iterator.dataType === "BigInt" ? "
|
|
82
|
+
def += iterator.dataType === "BigInt" ? "bigint " : "int ";
|
|
83
|
+
def += " not null GENERATED BY DEFAULT AS IDENTITY\r\n\t";
|
|
83
84
|
} else {
|
|
84
85
|
def += this.getColumnDefinition(iterator);
|
|
86
|
+
def += " not null \r\n\t";
|
|
85
87
|
}
|
|
86
|
-
def += " not null primary key\r\n\t";
|
|
87
88
|
fields.push(def);
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
await driver.executeQuery(`CREATE TABLE IF NOT EXISTS ${name} (${fields.join(",")}
|
|
91
|
+
await driver.executeQuery(`CREATE TABLE IF NOT EXISTS ${name} (${fields.join(",")}
|
|
92
|
+
,CONSTRAINT PK_${name} PRIMARY KEY (${keys.map((x) => x.columnName).join(",")})
|
|
93
|
+
)`);
|
|
91
94
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
async migrateIndex(context: EntityContext, index: IIndex, type: EntityType) {
|
|
95
98
|
const driver = context.driver;
|
|
96
99
|
const name = type.schema
|
|
97
|
-
?
|
|
98
|
-
:
|
|
99
|
-
const indexName =
|
|
100
|
+
? type.schema + "." + type.name
|
|
101
|
+
: type.name;
|
|
102
|
+
const indexName = index.name;
|
|
100
103
|
const columns = [];
|
|
101
104
|
for (const column of index.columns) {
|
|
102
|
-
const columnName =
|
|
105
|
+
const columnName = column.name;
|
|
103
106
|
columns.push(`${columnName} ${column.descending ? "DESC" : "ASC"}`);
|
|
104
107
|
}
|
|
105
108
|
let query = `CREATE ${index.unique ? "UNIQUE" : ""} INDEX IF NOT EXISTS ${indexName} ON ${name} ( ${columns.join(", ")})`;
|
|
@@ -29,10 +29,10 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
29
29
|
async createIndexes(context: EntityContext, type: EntityType, fkColumns: IColumn[]) {
|
|
30
30
|
for (const iterator of fkColumns) {
|
|
31
31
|
const filter = iterator.nullable
|
|
32
|
-
? `${
|
|
32
|
+
? `${ iterator.columnName} IS NOT NULL`
|
|
33
33
|
: "";
|
|
34
34
|
const indexDef: IIndex = {
|
|
35
|
-
name: `IX_${type.name}_${iterator.
|
|
35
|
+
name: `IX_${type.name}_${iterator.name}`,
|
|
36
36
|
columns: [{ name: iterator.columnName, descending: iterator.indexOrder !== "ascending"}],
|
|
37
37
|
filter
|
|
38
38
|
};
|
|
@@ -43,15 +43,15 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
43
43
|
async createColumns(driver: BaseDriver, type: EntityType, nonKeyColumns: IColumn[]) {
|
|
44
44
|
|
|
45
45
|
const name = type.schema
|
|
46
|
-
?
|
|
47
|
-
:
|
|
46
|
+
? type.schema + "." + type.name
|
|
47
|
+
: type.name;
|
|
48
48
|
|
|
49
49
|
if (nonKeyColumns.length > 1) {
|
|
50
50
|
nonKeyColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
for (const iterator of nonKeyColumns) {
|
|
54
|
-
const columnName =
|
|
54
|
+
const columnName = iterator.columnName;
|
|
55
55
|
let def = `IF COL_LENGTH(${ SqlServerLiteral.escapeLiteral(name)}, ${ SqlServerLiteral.escapeLiteral(columnName)}) IS NULL ALTER TABLE ${name} ADD ${columnName} `;
|
|
56
56
|
def += this.getColumnDefinition(iterator);
|
|
57
57
|
if (iterator.nullable === true) {
|
|
@@ -70,8 +70,8 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
70
70
|
async createTable(driver: BaseDriver, type: EntityType, keys: IColumn[]) {
|
|
71
71
|
|
|
72
72
|
const name = type.schema
|
|
73
|
-
?
|
|
74
|
-
:
|
|
73
|
+
? type.schema + "." + type.name
|
|
74
|
+
: type.name;
|
|
75
75
|
|
|
76
76
|
if (keys.length > 1) {
|
|
77
77
|
keys.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
@@ -80,7 +80,7 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
80
80
|
const fields = [];
|
|
81
81
|
|
|
82
82
|
for (const iterator of keys) {
|
|
83
|
-
let def =
|
|
83
|
+
let def = iterator.columnName + " ";
|
|
84
84
|
if (iterator.autoGenerate) {
|
|
85
85
|
def += this.getColumnDefinition(iterator) + " IDENTITY(1,1)";
|
|
86
86
|
} else {
|
|
@@ -99,12 +99,12 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
99
99
|
async migrateIndex(context: EntityContext, index: IIndex, type: EntityType) {
|
|
100
100
|
const driver = context.driver;
|
|
101
101
|
const name = type.schema
|
|
102
|
-
?
|
|
103
|
-
:
|
|
104
|
-
const indexName =
|
|
102
|
+
? type.schema + "." + type.name
|
|
103
|
+
: type.name;
|
|
104
|
+
const indexName = index.name;
|
|
105
105
|
const columns = [];
|
|
106
106
|
for (const column of index.columns) {
|
|
107
|
-
const columnName =
|
|
107
|
+
const columnName = column.name;
|
|
108
108
|
columns.push(`${columnName} ${column.descending ? "DESC" : "ASC"}`);
|
|
109
109
|
}
|
|
110
110
|
let query = `IF NOT EXISTS(SELECT * FROM sys.indexes WHERE name = '${indexName}' AND object_id = OBJECT_ID('${name}'))
|
|
@@ -181,7 +181,7 @@ export default class EntityContext {
|
|
|
181
181
|
|
|
182
182
|
protected async saveChangesWithoutEvents(signal: AbortSignal) {
|
|
183
183
|
return this.driver.runInTransaction(async () => {
|
|
184
|
-
const copy = [].concat(this.changeSet.entries);
|
|
184
|
+
const copy = [].concat(this.changeSet.entries) as ChangeEntry[];
|
|
185
185
|
for (const iterator of copy) {
|
|
186
186
|
switch (iterator.status) {
|
|
187
187
|
case "inserted":
|
package/src/model/EntityModel.ts
CHANGED
|
@@ -1,27 +1,61 @@
|
|
|
1
1
|
import type EntityContext from "./EntityContext.js";
|
|
2
2
|
import { IClassOf } from "../decorators/IClassOf.js";
|
|
3
3
|
import SchemaRegistry from "../decorators/SchemaRegistry.js";
|
|
4
|
-
import EntityQuery from "./EntityQuery.js";
|
|
5
|
-
import { Expression } from "@babel/types";
|
|
6
4
|
import { EntitySource } from "./EntitySource.js";
|
|
5
|
+
import { BaseDriver } from "../drivers/base/BaseDriver.js";
|
|
6
|
+
import EntityType from "../entity-query/EntityType.js";
|
|
7
|
+
import { IStringTransformer } from "../query/ast/IStringTransformer.js";
|
|
8
|
+
import { IEntityRelation } from "../decorators/IColumn.js";
|
|
7
9
|
|
|
10
|
+
const driverModelCache = Symbol("driverModelCache");
|
|
8
11
|
|
|
12
|
+
const getOrCreateModel = (map: Map<any, EntityType>, type: IClassOf<any>, namingConvention: IStringTransformer) => {
|
|
13
|
+
let t = map.get(type);
|
|
14
|
+
if (t) {
|
|
15
|
+
return t;
|
|
16
|
+
}
|
|
17
|
+
const original = SchemaRegistry.model(type);
|
|
18
|
+
t = new EntityType(original);
|
|
19
|
+
map.set(type, t);
|
|
20
|
+
for (const iterator of original.columns) {
|
|
21
|
+
const column = { ... iterator };
|
|
22
|
+
column.columnName = column.explicitName ? column.columnName : (namingConvention ? namingConvention(column.columnName) : column.columnName);
|
|
23
|
+
t.addColumn(column);
|
|
24
|
+
column.entityType = t;
|
|
25
|
+
}
|
|
26
|
+
for (const iterator of original.relations) {
|
|
27
|
+
if (iterator.isInverseRelation) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const relation: IEntityRelation = { ... iterator, fkColumn: void 0, relatedEntity: void 0,type: t };
|
|
31
|
+
t.addRelation(relation, (tc) => getOrCreateModel(map, tc, namingConvention));
|
|
32
|
+
}
|
|
33
|
+
return t;
|
|
34
|
+
};
|
|
9
35
|
|
|
10
36
|
export default class EntityModel {
|
|
11
37
|
|
|
12
|
-
public
|
|
38
|
+
public sources: Map<IClassOf<any>, EntitySource> = new Map();
|
|
39
|
+
|
|
40
|
+
public types: Map<IClassOf<any>, EntityType> = new Map();
|
|
13
41
|
|
|
14
42
|
constructor(private context: EntityContext) {
|
|
15
43
|
}
|
|
16
44
|
|
|
17
45
|
register<T>(type: IClassOf<T>) {
|
|
18
|
-
let source = this.
|
|
46
|
+
let source = this.sources.get(type);
|
|
19
47
|
if (!source) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
this.
|
|
48
|
+
const cache = (this.context.driver[driverModelCache] ??= new Map());
|
|
49
|
+
const entityType = getOrCreateModel(cache, type, this.context.driver.compiler.namingConvention);
|
|
50
|
+
this.types.set(type, entityType);
|
|
51
|
+
source = new EntitySource(entityType, this.context);
|
|
52
|
+
this.sources.set(type, source);
|
|
23
53
|
}
|
|
24
54
|
return source as EntitySource<T>;
|
|
25
55
|
}
|
|
26
56
|
|
|
57
|
+
getEntityType<T>(type: IClassOf<T>): EntityType{
|
|
58
|
+
return this.types.get(type);
|
|
59
|
+
}
|
|
60
|
+
|
|
27
61
|
}
|
package/src/model/EntityQuery.ts
CHANGED
|
@@ -2,7 +2,7 @@ import Logger from "../common/Logger.js";
|
|
|
2
2
|
import { DisposableScope } from "../common/usingAsync.js";
|
|
3
3
|
import { ServiceProvider } from "../di/di.js";
|
|
4
4
|
import EntityType from "../entity-query/EntityType.js";
|
|
5
|
-
import { CallExpression, Expression, ExpressionAs, Identifier, OrderByExpression,
|
|
5
|
+
import { CallExpression, Expression, ExpressionAs, Identifier, OrderByExpression, SelectStatement } from "../query/ast/Expressions.js";
|
|
6
6
|
import { QueryExpander } from "../query/expander/QueryExpander.js";
|
|
7
7
|
import EntityContext from "./EntityContext.js";
|
|
8
8
|
import { IOrderedEntityQuery, IEntityQuery } from "./IFilterWithParameter.js";
|
|
@@ -95,9 +95,9 @@ export default class EntityQuery<T = any>
|
|
|
95
95
|
scope.register(reader);
|
|
96
96
|
for await (const iterator of reader.next(10, signal)) {
|
|
97
97
|
if (type) {
|
|
98
|
-
|
|
98
|
+
const item = type?.map(iterator) ?? iterator;
|
|
99
99
|
// set identity...
|
|
100
|
-
const entry = this.context.changeSet.getEntry(
|
|
100
|
+
const entry = this.context.changeSet.getEntry(item, item);
|
|
101
101
|
relationMapper.fix(entry);
|
|
102
102
|
yield entry.entity;
|
|
103
103
|
continue;
|
|
@@ -118,8 +118,8 @@ export default class EntityQuery<T = any>
|
|
|
118
118
|
const reader = await this.context.driver.executeReader(query, signal);
|
|
119
119
|
try {
|
|
120
120
|
for await (const iterator of reader.next(10, signal)) {
|
|
121
|
-
|
|
122
|
-
const entry = this.context.changeSet.getEntry(
|
|
121
|
+
const item = select.model?.map(iterator) ?? iterator;
|
|
122
|
+
const entry = this.context.changeSet.getEntry(item, item);
|
|
123
123
|
relationMapper.fix(entry);
|
|
124
124
|
}
|
|
125
125
|
} catch (error) {
|
|
@@ -183,7 +183,7 @@ export default class EntityQuery<T = any>
|
|
|
183
183
|
callee: Identifier.create({ value: "COUNT"}),
|
|
184
184
|
arguments: [ Identifier.create({ value: "*"})]
|
|
185
185
|
}),
|
|
186
|
-
alias:
|
|
186
|
+
alias: Expression.identifier("c1")
|
|
187
187
|
})
|
|
188
188
|
] };
|
|
189
189
|
|
|
@@ -194,7 +194,7 @@ export default class EntityQuery<T = any>
|
|
|
194
194
|
|
|
195
195
|
try {
|
|
196
196
|
for await (const iterator of reader.next()) {
|
|
197
|
-
return iterator.
|
|
197
|
+
return iterator.c1 as number;
|
|
198
198
|
}
|
|
199
199
|
} finally {
|
|
200
200
|
await reader.dispose();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { modelSymbol } from "../common/symbols/symbols.js";
|
|
2
2
|
import EntityType from "../entity-query/EntityType.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Expression, JoinExpression, ParameterExpression, SelectStatement } from "../query/ast/Expressions.js";
|
|
4
4
|
import { ITextQueryFragment, QueryParameter } from "../query/ast/IStringTransformer.js";
|
|
5
5
|
import EntityContext from "./EntityContext.js";
|
|
6
6
|
|
|
@@ -64,7 +64,7 @@ export class SourceExpression {
|
|
|
64
64
|
as: source.alias,
|
|
65
65
|
joinType: column.nullable ? "LEFT" : "INNER",
|
|
66
66
|
model,
|
|
67
|
-
source:
|
|
67
|
+
source: Expression.identifier(model.name),
|
|
68
68
|
where: Expression.logicalAnd(
|
|
69
69
|
Expression.member(
|
|
70
70
|
this.alias,
|
|
@@ -121,9 +121,8 @@ export class SourceExpression {
|
|
|
121
121
|
|
|
122
122
|
prepareNames([property , ... others]: string[]): ITextQueryFragment {
|
|
123
123
|
const p = this.model.getProperty(property);
|
|
124
|
-
const quotedLiteral = this.context.driver.compiler.quotedLiteral;
|
|
125
124
|
if (others.length === 0) {
|
|
126
|
-
return `${ QueryParameter.create(() => this.alias.name
|
|
125
|
+
return `${ QueryParameter.create(() => this.alias.name)}.${p.field.columnName}`;
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
// this must be a navigation...
|
|
@@ -89,9 +89,9 @@ export default class ChangeEntry<T = any> implements IChanges {
|
|
|
89
89
|
this.detectDependencies();
|
|
90
90
|
|
|
91
91
|
for (const iterator of columns) {
|
|
92
|
-
const oldValue = original[iterator.
|
|
92
|
+
const oldValue = original[iterator.name];
|
|
93
93
|
const newValue = entity[iterator.name];
|
|
94
|
-
if (entity[iterator.name] !== original[iterator.
|
|
94
|
+
if (entity[iterator.name] !== original[iterator.name]) {
|
|
95
95
|
let modifiedEntry = this.modified.get(iterator);
|
|
96
96
|
if (!modifiedEntry) {
|
|
97
97
|
modifiedEntry = { column: iterator, oldValue, newValue };
|
|
@@ -52,7 +52,7 @@ export default class ChangeSet {
|
|
|
52
52
|
if (c === Object) {
|
|
53
53
|
throw new EntityAccessError("Entity type not set");
|
|
54
54
|
}
|
|
55
|
-
const type =
|
|
55
|
+
const type = this.context.model.getEntityType(c);
|
|
56
56
|
const jsonKey = IdentityService.getIdentity(entity);
|
|
57
57
|
if (jsonKey) {
|
|
58
58
|
const existing = this.identityMap.get(jsonKey);
|
|
@@ -3,8 +3,7 @@ import Logger from "../../common/Logger.js";
|
|
|
3
3
|
import { TypeInfo } from "../../common/TypeInfo.js";
|
|
4
4
|
import { IEntityRelation } from "../../decorators/IColumn.js";
|
|
5
5
|
import { ServiceProvider } from "../../di/di.js";
|
|
6
|
-
import
|
|
7
|
-
import { ConditionalExpression, Constant, ExistsExpression, Expression, Identifier, ParameterExpression, QuotedLiteral, SelectStatement, TemplateLiteral, ValuesStatement } from "../../query/ast/Expressions.js";
|
|
6
|
+
import { ConditionalExpression, ExistsExpression, Expression, NumberLiteral, ParameterExpression, SelectStatement, ValuesStatement } from "../../query/ast/Expressions.js";
|
|
8
7
|
import EntityContext from "../EntityContext.js";
|
|
9
8
|
import EntityQuery from "../EntityQuery.js";
|
|
10
9
|
import ChangeEntry from "../changes/ChangeEntry.js";
|
|
@@ -106,7 +105,7 @@ export default class VerificationSession {
|
|
|
106
105
|
const eq = query as EntityQuery;
|
|
107
106
|
for (const [key, value] of keys) {
|
|
108
107
|
const test = Expression.equal(
|
|
109
|
-
Expression.member(eq.selectStatement.sourceParameter, Expression.
|
|
108
|
+
Expression.member(eq.selectStatement.sourceParameter, Expression.identifier(key)),
|
|
110
109
|
Expression.constant(value)
|
|
111
110
|
);
|
|
112
111
|
compare = compare
|
|
@@ -127,10 +126,10 @@ export default class VerificationSession {
|
|
|
127
126
|
this.select.sourceParameter = ParameterExpression.create({ name: "x"});
|
|
128
127
|
const source = ValuesStatement.create({
|
|
129
128
|
values: [
|
|
130
|
-
[
|
|
129
|
+
[NumberLiteral.one]
|
|
131
130
|
],
|
|
132
|
-
as:
|
|
133
|
-
fields: [
|
|
131
|
+
as: Expression.identifier("a"),
|
|
132
|
+
fields: [Expression.identifier("a")]
|
|
134
133
|
});
|
|
135
134
|
this.select.source = source;
|
|
136
135
|
const compiler = this.context.driver.compiler;
|
|
@@ -151,7 +150,7 @@ export default class VerificationSession {
|
|
|
151
150
|
addError(query: EntityQuery, compare: Expression, error: string) {
|
|
152
151
|
const select = { ... query.selectStatement};
|
|
153
152
|
select.fields = [
|
|
154
|
-
|
|
153
|
+
NumberLiteral.one
|
|
155
154
|
];
|
|
156
155
|
|
|
157
156
|
const where = select.where
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArrowFunctionExpression, BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, Identifier, InsertStatement, JoinExpression, MemberExpression, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression,
|
|
1
|
+
import { ArrowFunctionExpression, BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, Identifier, InsertStatement, JoinExpression, MemberExpression, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression, ReturnUpdated, SelectStatement, StringLiteral, TableLiteral, TemplateElement, TemplateLiteral, UnionAllStatement, UpdateStatement, ValuesStatement } from "./Expressions.js";
|
|
2
2
|
import Visitor from "./Visitor.js";
|
|
3
3
|
|
|
4
4
|
const isBinary = (type) => /^(BinaryExpression|CoalesceExpression)$/.test(type);
|
|
@@ -89,10 +89,6 @@ export default class DebugStringVisitor extends Visitor<string> {
|
|
|
89
89
|
return e.name;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
visitQuotedLiteral(e: QuotedLiteral): string {
|
|
93
|
-
return `"${e.literal}"`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
92
|
visitStringLiteral(e: StringLiteral): string {
|
|
97
93
|
return `'${e.value}'`;
|
|
98
94
|
}
|
|
@@ -2,7 +2,7 @@ import QueryCompiler from "../../compiler/QueryCompiler.js";
|
|
|
2
2
|
import EntityType from "../../entity-query/EntityType.js";
|
|
3
3
|
import EntityQuery from "../../model/EntityQuery.js";
|
|
4
4
|
import { filteredSymbol } from "../../model/events/EntityEvents.js";
|
|
5
|
-
import { BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, ExpressionType, Identifier, InsertStatement, JoinExpression, MemberExpression, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression,
|
|
5
|
+
import { BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, ExpressionType, Identifier, InsertStatement, JoinExpression, MemberExpression, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression, ReturnUpdated, SelectStatement, StringLiteral, TableLiteral, TemplateLiteral, UnionAllStatement, UpdateStatement, ValuesStatement } from "./Expressions.js";
|
|
6
6
|
import { ITextQuery, QueryParameter, prepare, prepareJoin } from "./IStringTransformer.js";
|
|
7
7
|
import ParameterScope from "./ParameterScope.js";
|
|
8
8
|
import Visitor from "./Visitor.js";
|
|
@@ -75,7 +75,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
75
75
|
const source = e.source.type === "ValuesStatement"
|
|
76
76
|
? prepare `(${this.visit(e.source)})`
|
|
77
77
|
: this.visit(e.source);
|
|
78
|
-
const as = e.sourceParameter ? prepare ` AS ${this.
|
|
78
|
+
const as = e.sourceParameter ? prepare ` AS ${this.scope.nameOf(e.sourceParameter)}` : "";
|
|
79
79
|
const fields = this.visitArray(e.fields, ",\n\t\t");
|
|
80
80
|
return prepare `SELECT
|
|
81
81
|
${fields}
|
|
@@ -100,10 +100,6 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
visitQuotedLiteral(e: QuotedLiteral): ITextQuery {
|
|
104
|
-
return [this.compiler.quotedLiteral(e.literal)];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
103
|
visitExpressionAs(e: ExpressionAs): ITextQuery {
|
|
108
104
|
return prepare `${this.visit(e.expression)} AS ${this.visit(e.alias)}`;
|
|
109
105
|
}
|
|
@@ -113,16 +109,16 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
visitBigIntLiteral({ value }: BigIntLiteral): ITextQuery {
|
|
116
|
-
return [()
|
|
112
|
+
return [value.toString()];
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
visitNumberLiteral( { value }: NumberLiteral): ITextQuery {
|
|
120
|
-
return [()
|
|
116
|
+
return [value.toString()];
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
visitStringLiteral({ value }: StringLiteral): ITextQuery {
|
|
124
120
|
const escapeLiteral = this.compiler.escapeLiteral;
|
|
125
|
-
return [
|
|
121
|
+
return [escapeLiteral(value)];
|
|
126
122
|
}
|
|
127
123
|
|
|
128
124
|
visitBooleanLiteral( { value }: BooleanLiteral): ITextQuery {
|
|
@@ -171,7 +167,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
171
167
|
// }
|
|
172
168
|
select = { ... (query as EntityQuery).selectStatement };
|
|
173
169
|
select.fields = [
|
|
174
|
-
|
|
170
|
+
NumberLiteral.create({ value: 1})
|
|
175
171
|
];
|
|
176
172
|
} else {
|
|
177
173
|
select = relatedModel.selectOneNumber();
|
|
@@ -273,7 +269,14 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
273
269
|
return [(p) => p[chain[0]]];
|
|
274
270
|
}
|
|
275
271
|
const name = this.scope.nameOf(parameter);
|
|
276
|
-
|
|
272
|
+
|
|
273
|
+
// need to change name as per naming convention here...
|
|
274
|
+
const namingConvention = this.compiler.namingConvention;
|
|
275
|
+
if (scope.model && namingConvention) {
|
|
276
|
+
chain[0] = namingConvention(chain[0]);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return [ QueryParameter.create(() => name) , "." , chain.join(".")];
|
|
277
280
|
}
|
|
278
281
|
|
|
279
282
|
const { target, computed, property } = me;
|
|
@@ -395,9 +398,9 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
395
398
|
}
|
|
396
399
|
const table = this.visit(e.source);
|
|
397
400
|
const where = this.visit(e.where);
|
|
398
|
-
const as = e.as ? prepare ` AS ${ e.as.type === "
|
|
399
|
-
?
|
|
400
|
-
: this.
|
|
401
|
+
const as = e.as ? prepare ` AS ${ e.as.type === "Identifier"
|
|
402
|
+
? e.as.value
|
|
403
|
+
: this.scope.nameOf(e.as )}` : "";
|
|
401
404
|
return prepare ` ${e.joinType || "LEFT"} JOIN ${table}${as} ON ${where}`;
|
|
402
405
|
}
|
|
403
406
|
|
|
@@ -519,7 +522,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
519
522
|
as: joinParameter,
|
|
520
523
|
joinType,
|
|
521
524
|
model: joinParameter.model,
|
|
522
|
-
source: Expression.
|
|
525
|
+
source: Expression.identifier(relation.relatedEntity.name),
|
|
523
526
|
where: Expression.equal(
|
|
524
527
|
Expression.member(parameter, fkColumn.columnName),
|
|
525
528
|
Expression.member(joinParameter, relation.relatedEntity.keys[0].columnName)
|