@entity-access/entity-access 1.0.25 → 1.0.27
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/decorators/IColumn.d.ts +5 -0
- package/dist/decorators/IColumn.d.ts.map +1 -1
- package/dist/decorators/IIndex.d.ts +25 -0
- package/dist/decorators/IIndex.d.ts.map +1 -0
- package/dist/decorators/IIndex.js +2 -0
- package/dist/decorators/IIndex.js.map +1 -0
- package/dist/decorators/Index.d.ts +4 -0
- package/dist/decorators/Index.d.ts.map +1 -0
- package/dist/decorators/Index.js +27 -0
- package/dist/decorators/Index.js.map +1 -0
- package/dist/drivers/postgres/PostgreSqlDriver.js +1 -1
- package/dist/drivers/postgres/PostgreSqlDriver.js.map +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.js +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.js.map +1 -1
- package/dist/entity-query/EntityType.d.ts +2 -0
- package/dist/entity-query/EntityType.d.ts.map +1 -1
- package/dist/entity-query/EntityType.js +1 -0
- package/dist/entity-query/EntityType.js.map +1 -1
- package/dist/migrations/Migrations.d.ts +7 -1
- package/dist/migrations/Migrations.d.ts.map +1 -1
- package/dist/migrations/Migrations.js +11 -0
- package/dist/migrations/Migrations.js.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts +3 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js +28 -12
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts +3 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +31 -15
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
- package/dist/model/changes/ChangeEntry.d.ts.map +1 -1
- package/dist/model/changes/ChangeEntry.js +30 -4
- package/dist/model/changes/ChangeEntry.js.map +1 -1
- package/dist/model/changes/ChangeSet.d.ts.map +1 -1
- package/dist/model/changes/ChangeSet.js +6 -1
- package/dist/model/changes/ChangeSet.js.map +1 -1
- package/dist/model/events/EntityEvents.d.ts +6 -6
- package/dist/model/events/EntityEvents.d.ts.map +1 -1
- package/dist/tests/model/ShoppingContext.d.ts +1 -0
- package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
- package/dist/tests/model/ShoppingContext.js +12 -1
- package/dist/tests/model/ShoppingContext.js.map +1 -1
- package/dist/tests/model/createContext.d.ts.map +1 -1
- package/dist/tests/model/createContext.js +10 -2
- package/dist/tests/model/createContext.js.map +1 -1
- package/dist/tests/security/tests/place-order.js +2 -2
- package/dist/tests/security/tests/place-order.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/decorators/IColumn.ts +5 -0
- package/src/decorators/IIndex.ts +24 -0
- package/src/decorators/Index.ts +42 -0
- package/src/drivers/postgres/PostgreSqlDriver.ts +1 -1
- package/src/drivers/sql-server/SqlServerDriver.ts +1 -1
- package/src/entity-query/EntityType.ts +3 -0
- package/src/migrations/Migrations.ts +18 -1
- package/src/migrations/postgres/PostgresAutomaticMigrations.ts +30 -14
- package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +33 -17
- package/src/model/changes/ChangeEntry.ts +33 -4
- package/src/model/changes/ChangeSet.ts +6 -1
- package/src/model/events/EntityEvents.ts +6 -6
- package/src/tests/model/ShoppingContext.ts +9 -0
- package/src/tests/model/createContext.ts +10 -2
- package/src/tests/security/tests/place-order.ts +2 -2
package/package.json
CHANGED
|
@@ -8,6 +8,11 @@ export interface IColumn {
|
|
|
8
8
|
columnName?: string;
|
|
9
9
|
order?: number;
|
|
10
10
|
key?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* While creating table, descending order will be chosen for primary keys/foreign keys
|
|
13
|
+
* for non text keys.
|
|
14
|
+
*/
|
|
15
|
+
indexOrder?: "descending" | "ascending";
|
|
11
16
|
autoGenerate?: boolean;
|
|
12
17
|
dataType?: ISqlType;
|
|
13
18
|
nullable?: boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface IIndexedColumn {
|
|
2
|
+
name: string;
|
|
3
|
+
descending: boolean;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type IndexedColumn<T> = ((x: T) => any) | { name:((x: T) => any), descending: boolean};
|
|
7
|
+
|
|
8
|
+
export default interface IIndexDef<T = any> {
|
|
9
|
+
name: string;
|
|
10
|
+
columns: IndexedColumn<T>[];
|
|
11
|
+
unique?: boolean;
|
|
12
|
+
include?: string[];
|
|
13
|
+
indexType?: string;
|
|
14
|
+
filter?: (x: T) => boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface IIndex{
|
|
18
|
+
name: string;
|
|
19
|
+
columns: IIndexedColumn[];
|
|
20
|
+
unique?: boolean;
|
|
21
|
+
include?: string[];
|
|
22
|
+
indexType?: string;
|
|
23
|
+
filter?: ((x: any) => boolean) | string;
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import ExpressionToSql from "../query/ast/ExpressionToSql.js";
|
|
2
|
+
import ArrowToExpression from "../query/parser/ArrowToExpression.js";
|
|
3
|
+
import { IClassOf } from "./IClassOf.js";
|
|
4
|
+
import IIndexDef, { IIndex, IIndexedColumn } from "./IIndex.js";
|
|
5
|
+
import SchemaRegistry from "./SchemaRegistry.js";
|
|
6
|
+
import NameParser from "./parser/NameParser.js";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default function Index<T>(
|
|
10
|
+
{
|
|
11
|
+
name,
|
|
12
|
+
columns: columnDefs,
|
|
13
|
+
unique,
|
|
14
|
+
include,
|
|
15
|
+
indexType,
|
|
16
|
+
filter
|
|
17
|
+
}
|
|
18
|
+
: IIndexDef<T>) {
|
|
19
|
+
return function(target: IClassOf<T>) {
|
|
20
|
+
const model = SchemaRegistry.model(target);
|
|
21
|
+
const columns = [] as IIndexedColumn[];
|
|
22
|
+
|
|
23
|
+
const i: IIndex = {
|
|
24
|
+
name,
|
|
25
|
+
unique,
|
|
26
|
+
include,
|
|
27
|
+
indexType,
|
|
28
|
+
filter,
|
|
29
|
+
columns
|
|
30
|
+
};
|
|
31
|
+
for (const iterator of columnDefs) {
|
|
32
|
+
const def = typeof iterator === "function"
|
|
33
|
+
? { name: iterator, descending: false }
|
|
34
|
+
: iterator;
|
|
35
|
+
columns.push({
|
|
36
|
+
name: NameParser.parseMember(def.name),
|
|
37
|
+
descending: def.descending
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
model.indexes.push(i);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -93,7 +93,7 @@ export default class PostgreSqlDriver extends BaseDriver {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
public automaticMigrations(): Migrations {
|
|
96
|
-
return new PostgresAutomaticMigrations();
|
|
96
|
+
return new PostgresAutomaticMigrations(this.compiler);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
public async executeReader(command: IQuery, signal?: AbortSignal): Promise<IDbReader> {
|
|
@@ -114,7 +114,7 @@ export default class SqlServerDriver extends BaseDriver {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
public automaticMigrations(): Migrations {
|
|
117
|
-
return new SqlServerAutomaticMigrations();
|
|
117
|
+
return new SqlServerAutomaticMigrations(this.sqlQueryCompiler);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
protected async newRequest() {
|
|
@@ -5,6 +5,7 @@ import NameParser from "../decorators/parser/NameParser.js";
|
|
|
5
5
|
import SchemaRegistry from "../decorators/SchemaRegistry.js";
|
|
6
6
|
import { Expression, ExpressionAs, QuotedLiteral, SelectStatement, TableLiteral } from "../query/ast/Expressions.js";
|
|
7
7
|
import InstanceCache from "../common/cache/InstanceCache.js";
|
|
8
|
+
import { IIndex } from "../decorators/IIndex.js";
|
|
8
9
|
|
|
9
10
|
export const addOrCreateColumnSymbol = Symbol("addOrCreateColumn");
|
|
10
11
|
export const addColumnSymbol = Symbol("addOrCreateColumn");
|
|
@@ -26,6 +27,8 @@ export default class EntityType {
|
|
|
26
27
|
|
|
27
28
|
public readonly relations: IEntityRelation[] = [];
|
|
28
29
|
|
|
30
|
+
public readonly indexes: IIndex[] = [];
|
|
31
|
+
|
|
29
32
|
public readonly keys: IColumn[] = [];
|
|
30
33
|
|
|
31
34
|
public readonly nonKeys: IColumn[] = [];
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
+
import type QueryCompiler from "../compiler/QueryCompiler.js";
|
|
2
|
+
import { IIndex } from "../decorators/IIndex.js";
|
|
1
3
|
import SchemaRegistry from "../decorators/SchemaRegistry.js";
|
|
2
|
-
import EntityType from "../entity-query/EntityType.js";
|
|
4
|
+
import type EntityType from "../entity-query/EntityType.js";
|
|
3
5
|
import type EntityContext from "../model/EntityContext.js";
|
|
4
6
|
|
|
5
7
|
export default abstract class Migrations {
|
|
6
8
|
|
|
9
|
+
constructor(protected compiler: QueryCompiler) {}
|
|
10
|
+
|
|
7
11
|
public async migrate(context: EntityContext) {
|
|
8
12
|
for (const iterator of context.model.entities.keys()) {
|
|
9
13
|
const type = SchemaRegistry.model(iterator);
|
|
10
14
|
await this.migrateTable(context, type);
|
|
15
|
+
|
|
16
|
+
for (const index of type.indexes) {
|
|
17
|
+
await this.migrateIndexInternal(context, index, type);
|
|
18
|
+
}
|
|
11
19
|
}
|
|
20
|
+
|
|
12
21
|
}
|
|
13
22
|
|
|
23
|
+
async migrateIndexInternal(context: EntityContext, index: IIndex, type: EntityType) {
|
|
24
|
+
// parse filter... pending...
|
|
25
|
+
this.migrateIndex(context, index, type);
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
abstract migrateIndex(context: EntityContext, index: IIndex, type: EntityType);
|
|
30
|
+
|
|
14
31
|
abstract migrateTable(context: EntityContext, type: EntityType): Promise<any>;
|
|
15
32
|
|
|
16
33
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IColumn } from "../../decorators/IColumn.js";
|
|
2
|
+
import { IIndex } from "../../decorators/IIndex.js";
|
|
2
3
|
import { BaseDriver } from "../../drivers/base/BaseDriver.js";
|
|
3
4
|
import EntityType from "../../entity-query/EntityType.js";
|
|
4
5
|
import EntityContext from "../../model/EntityContext.js";
|
|
@@ -20,24 +21,21 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
|
|
|
20
21
|
|
|
21
22
|
await this.createColumns(driver, type, nonKeyColumns);
|
|
22
23
|
|
|
23
|
-
await this.createIndexes(
|
|
24
|
+
await this.createIndexes(context, type, nonKeyColumns.filter((x) => x.fkRelation && !x.fkRelation?.dotNotCreateIndex));
|
|
24
25
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
async createIndexes(
|
|
28
|
-
|
|
29
|
-
const name = type.schema
|
|
30
|
-
? JSON.stringify(type.schema) + "." + JSON.stringify(type.name)
|
|
31
|
-
: JSON.stringify(type.name);
|
|
32
|
-
|
|
28
|
+
async createIndexes(context: EntityContext, type: EntityType, fkColumns: IColumn[]) {
|
|
33
29
|
for (const iterator of fkColumns) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
const filter = iterator.nullable
|
|
31
|
+
? `${ JSON.stringify(iterator.columnName)} IS NOT NULL`
|
|
32
|
+
: "";
|
|
33
|
+
const indexDef: IIndex = {
|
|
34
|
+
name: `IX_${type.name}_${iterator.columnName}`,
|
|
35
|
+
columns: [{ name: iterator.columnName, descending: iterator.indexOrder !== "ascending"}],
|
|
36
|
+
filter
|
|
37
|
+
};
|
|
38
|
+
await this.migrateIndex(context, indexDef, type);
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
41
|
|
|
@@ -93,5 +91,23 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
|
|
|
93
91
|
|
|
94
92
|
}
|
|
95
93
|
|
|
94
|
+
async migrateIndex(context: EntityContext, index: IIndex, type: EntityType) {
|
|
95
|
+
const driver = context.driver;
|
|
96
|
+
const name = type.schema
|
|
97
|
+
? JSON.stringify(type.schema) + "." + JSON.stringify(type.name)
|
|
98
|
+
: JSON.stringify(type.name);
|
|
99
|
+
const indexName = JSON.stringify(index.name);
|
|
100
|
+
const columns = [];
|
|
101
|
+
for (const column of index.columns) {
|
|
102
|
+
const columnName = JSON.stringify(column.name);
|
|
103
|
+
columns.push(`${columnName} ${column.descending ? "DESC" : "ASC"}`);
|
|
104
|
+
}
|
|
105
|
+
let query = `CREATE ${index.unique ? "UNIQUE" : ""} INDEX IF NOT EXISTS ${indexName} ON ${name} ( ${columns.join(", ")})`;
|
|
106
|
+
if (index.filter) {
|
|
107
|
+
query += ` WHERE (${index.filter})`;
|
|
108
|
+
}
|
|
109
|
+
await driver.executeQuery(query);
|
|
110
|
+
}
|
|
111
|
+
|
|
96
112
|
|
|
97
113
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IColumn } from "../../decorators/IColumn.js";
|
|
2
|
+
import { IIndex } from "../../decorators/IIndex.js";
|
|
2
3
|
import { BaseDriver } from "../../drivers/base/BaseDriver.js";
|
|
3
4
|
import { SqlServerLiteral } from "../../drivers/sql-server/SqlServerLiteral.js";
|
|
4
5
|
import EntityType from "../../entity-query/EntityType.js";
|
|
@@ -21,27 +22,21 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
21
22
|
|
|
22
23
|
await this.createColumns(driver, type, nonKeyColumns);
|
|
23
24
|
|
|
24
|
-
await this.createIndexes(
|
|
25
|
+
await this.createIndexes(context, type, nonKeyColumns.filter((x) => x.fkRelation && !x.fkRelation?.dotNotCreateIndex));
|
|
25
26
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
async createIndexes(
|
|
29
|
-
|
|
30
|
-
const name = type.schema
|
|
31
|
-
? SqlServerLiteral.quotedLiteral(type.schema) + "." + SqlServerLiteral.quotedLiteral(type.name)
|
|
32
|
-
: SqlServerLiteral.quotedLiteral(type.name);
|
|
33
|
-
|
|
29
|
+
async createIndexes(context: EntityContext, type: EntityType, fkColumns: IColumn[]) {
|
|
34
30
|
for (const iterator of fkColumns) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
await driver.executeQuery(query);
|
|
31
|
+
const filter = iterator.nullable
|
|
32
|
+
? `${ SqlServerLiteral.quotedLiteral(iterator.columnName)} IS NOT NULL`
|
|
33
|
+
: "";
|
|
34
|
+
const indexDef: IIndex = {
|
|
35
|
+
name: `IX_${type.name}_${iterator.columnName}`,
|
|
36
|
+
columns: [{ name: iterator.columnName, descending: iterator.indexOrder !== "ascending"}],
|
|
37
|
+
filter
|
|
38
|
+
};
|
|
39
|
+
await this.migrateIndex(context, indexDef, type);
|
|
45
40
|
}
|
|
46
41
|
}
|
|
47
42
|
|
|
@@ -101,5 +96,26 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
|
|
|
101
96
|
|
|
102
97
|
}
|
|
103
98
|
|
|
99
|
+
async migrateIndex(context: EntityContext, index: IIndex, type: EntityType) {
|
|
100
|
+
const driver = context.driver;
|
|
101
|
+
const name = type.schema
|
|
102
|
+
? SqlServerLiteral.quotedLiteral(type.schema) + "." + SqlServerLiteral.quotedLiteral(type.name)
|
|
103
|
+
: SqlServerLiteral.quotedLiteral(type.name);
|
|
104
|
+
const indexName = SqlServerLiteral.quotedLiteral(index.name);
|
|
105
|
+
const columns = [];
|
|
106
|
+
for (const column of index.columns) {
|
|
107
|
+
const columnName = SqlServerLiteral.quotedLiteral(column.name);
|
|
108
|
+
columns.push(`${columnName} ${column.descending ? "DESC" : "ASC"}`);
|
|
109
|
+
}
|
|
110
|
+
let query = `IF NOT EXISTS(SELECT * FROM sys.indexes WHERE name = '${indexName}' AND object_id = OBJECT_ID('${name}'))
|
|
111
|
+
BEGIN
|
|
112
|
+
CREATE ${index.unique ? "UNIQUE" : ""} INDEX ${indexName} ON ${name} ( ${columns.join(", ")})`;
|
|
113
|
+
if (index.filter) {
|
|
114
|
+
query += ` WHERE (${index.filter})`;
|
|
115
|
+
}
|
|
116
|
+
query += `\nEND`;
|
|
117
|
+
await driver.executeQuery(query);
|
|
118
|
+
}
|
|
119
|
+
|
|
104
120
|
|
|
105
121
|
}
|
|
@@ -49,12 +49,36 @@ export default class ChangeEntry implements IChanges {
|
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const { type: { columns }, entity
|
|
52
|
+
const { type: { columns, keys }, entity } = this;
|
|
53
|
+
let { original } = this;
|
|
53
54
|
|
|
54
55
|
if (original === void 0) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
|
|
57
|
+
// check if all keys are set or not...
|
|
58
|
+
|
|
59
|
+
let keysSet = true;
|
|
60
|
+
let autoGenerate = false;
|
|
61
|
+
for (const iterator of keys) {
|
|
62
|
+
autoGenerate ||= iterator.autoGenerate;
|
|
63
|
+
if(entity[iterator.name] === void 0) {
|
|
64
|
+
keysSet = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (keysSet) {
|
|
69
|
+
if (!autoGenerate) {
|
|
70
|
+
this.status = "inserted";
|
|
71
|
+
this.detectDependencies();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
} else if (autoGenerate) {
|
|
75
|
+
this.status = "inserted";
|
|
76
|
+
this.detectDependencies();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.original = { ... entity };
|
|
81
|
+
original = this.original;
|
|
58
82
|
}
|
|
59
83
|
|
|
60
84
|
this.detectDependencies();
|
|
@@ -133,6 +157,11 @@ export default class ChangeEntry implements IChanges {
|
|
|
133
157
|
// if related has key defined.. set it...
|
|
134
158
|
const rKey = iterator.relatedEntity.keys[0];
|
|
135
159
|
|
|
160
|
+
// lets set the prototype...
|
|
161
|
+
const prototype = iterator.relatedTypeClass.prototype;
|
|
162
|
+
if (Object.getPrototypeOf(related) !== prototype) {
|
|
163
|
+
Object.setPrototypeOf(related, prototype);
|
|
164
|
+
}
|
|
136
165
|
const relatedChanges = this.changeSet.getEntry(related);
|
|
137
166
|
|
|
138
167
|
const keyValue = related[rKey.name];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import EntityAccessError from "../../common/EntityAccessError.js";
|
|
1
2
|
import SchemaRegistry from "../../decorators/SchemaRegistry.js";
|
|
2
3
|
import EntityContext from "../EntityContext.js";
|
|
3
4
|
import IdentityService, { identityMapSymbol } from "../identity/IdentityService.js";
|
|
@@ -47,7 +48,11 @@ export default class ChangeSet {
|
|
|
47
48
|
if (entry) {
|
|
48
49
|
return entry;
|
|
49
50
|
}
|
|
50
|
-
const
|
|
51
|
+
const c = Object.getPrototypeOf(entity).constructor;
|
|
52
|
+
if (c === Object) {
|
|
53
|
+
throw new EntityAccessError("Entity type not set");
|
|
54
|
+
}
|
|
55
|
+
const type = SchemaRegistry.model(c);
|
|
51
56
|
const jsonKey = IdentityService.getIdentity(entity);
|
|
52
57
|
if (jsonKey) {
|
|
53
58
|
const existing = this.identityMap.get(jsonKey);
|
|
@@ -61,7 +61,7 @@ export default abstract class EntityEvents<T> {
|
|
|
61
61
|
return this.modify(query);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
beforeInsert(entity: T, entry: ChangeEntry) {
|
|
64
|
+
beforeInsert(entity: T, entry: ChangeEntry): void | Promise<void> {
|
|
65
65
|
return done;
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -69,23 +69,23 @@ export default abstract class EntityEvents<T> {
|
|
|
69
69
|
return filter.modify();
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
afterInsert(entity: T, entry: ChangeEntry) {
|
|
72
|
+
afterInsert(entity: T, entry: ChangeEntry): void | Promise<void> {
|
|
73
73
|
return done;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
beforeUpdate(entity: T, entry: ChangeEntry) {
|
|
76
|
+
beforeUpdate(entity: T, entry: ChangeEntry): void | Promise<void> {
|
|
77
77
|
return done;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
afterUpdate(entity: T, entry: ChangeEntry) {
|
|
80
|
+
afterUpdate(entity: T, entry: ChangeEntry): void | Promise<void> {
|
|
81
81
|
return done;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
beforeDelete(entity: T, entry: ChangeEntry) {
|
|
84
|
+
beforeDelete(entity: T, entry: ChangeEntry): void | Promise<void> {
|
|
85
85
|
return done;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
afterDelete(entity: T, entry: ChangeEntry) {
|
|
88
|
+
afterDelete(entity: T, entry: ChangeEntry): void | Promise<void> {
|
|
89
89
|
return done;
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -2,6 +2,7 @@ import EntityContext from "../../model/EntityContext.js";
|
|
|
2
2
|
import Column from "../../decorators/Column.js";
|
|
3
3
|
import { RelateTo } from "../../decorators/Relate.js";
|
|
4
4
|
import Table from "../../decorators/Table.js";
|
|
5
|
+
import Index from "../../decorators/Index.js";
|
|
5
6
|
|
|
6
7
|
export const statusPublished = "published";
|
|
7
8
|
|
|
@@ -24,6 +25,11 @@ export class ShoppingContext extends EntityContext {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
@Table("Users")
|
|
28
|
+
@Index({
|
|
29
|
+
name: "IX_Unique_Users",
|
|
30
|
+
columns: [(x) => x.userName],
|
|
31
|
+
unique: true
|
|
32
|
+
})
|
|
27
33
|
export class User {
|
|
28
34
|
|
|
29
35
|
@Column({ key: true , autoGenerate: true, dataType: "BigInt" })
|
|
@@ -32,6 +38,9 @@ export class User {
|
|
|
32
38
|
@Column({})
|
|
33
39
|
public dateCreated: Date;
|
|
34
40
|
|
|
41
|
+
@Column({ dataType: "Char", length: 200 })
|
|
42
|
+
public userName: string;
|
|
43
|
+
|
|
35
44
|
public ownedProducts: Product[];
|
|
36
45
|
|
|
37
46
|
public orders: Order[];
|
|
@@ -17,6 +17,7 @@ export async function createContext(driver: BaseDriver) {
|
|
|
17
17
|
|
|
18
18
|
await seed(context);
|
|
19
19
|
|
|
20
|
+
driver.connectionString.database = context.driver.connectionString.database;
|
|
20
21
|
return context;
|
|
21
22
|
|
|
22
23
|
}
|
|
@@ -29,9 +30,15 @@ async function seed(context: ShoppingContext) {
|
|
|
29
30
|
const now = new Date();
|
|
30
31
|
|
|
31
32
|
// add admin user...
|
|
32
|
-
context.users.add({
|
|
33
|
+
context.users.add({
|
|
34
|
+
userName: "admin",
|
|
35
|
+
dateCreated: new Date()
|
|
36
|
+
});
|
|
33
37
|
// add seller
|
|
34
|
-
const seller = context.users.add({
|
|
38
|
+
const seller = context.users.add({
|
|
39
|
+
userName: "self",
|
|
40
|
+
dateCreated: new Date()
|
|
41
|
+
});
|
|
35
42
|
|
|
36
43
|
addHeadPhones(context, now, seller);
|
|
37
44
|
|
|
@@ -45,6 +52,7 @@ async function seed(context: ShoppingContext) {
|
|
|
45
52
|
const productPrice = product.prices[0];
|
|
46
53
|
|
|
47
54
|
const user = context.users.add({
|
|
55
|
+
userName: "customer1",
|
|
48
56
|
dateCreated: new Date(),
|
|
49
57
|
orders: [
|
|
50
58
|
context.orders.add({
|
|
@@ -94,11 +94,11 @@ async function addNewOrder(this: TestConfig, customer: User, userID?) {
|
|
|
94
94
|
|
|
95
95
|
async function createUser(config: TestConfig) {
|
|
96
96
|
const context = await createContext(config.driver);
|
|
97
|
-
config.driver.connectionString.database = context.driver.connectionString.database;
|
|
98
97
|
const user = context.users.add({
|
|
98
|
+
userName: "customer",
|
|
99
99
|
dateCreated: new Date()
|
|
100
100
|
});
|
|
101
101
|
await context.saveChanges();
|
|
102
|
-
return user;
|
|
102
|
+
return { ... user };
|
|
103
103
|
}
|
|
104
104
|
|