@entity-access/entity-access 1.0.252 → 1.0.254
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/.vscode/launch.json +2 -1
- package/dist/common/symbols/symbols.d.ts +1 -0
- package/dist/common/symbols/symbols.d.ts.map +1 -1
- package/dist/common/symbols/symbols.js +1 -0
- package/dist/common/symbols/symbols.js.map +1 -1
- package/dist/decorators/ForeignKey.d.ts +8 -7
- package/dist/decorators/ForeignKey.d.ts.map +1 -1
- package/dist/decorators/ForeignKey.js +43 -8
- package/dist/decorators/ForeignKey.js.map +1 -1
- package/dist/decorators/IColumn.d.ts +6 -3
- package/dist/decorators/IColumn.d.ts.map +1 -1
- package/dist/decorators/Relate.d.ts.map +1 -1
- package/dist/decorators/Relate.js +8 -6
- package/dist/decorators/Relate.js.map +1 -1
- package/dist/entity-query/EntityType.d.ts +5 -1
- package/dist/entity-query/EntityType.d.ts.map +1 -1
- package/dist/entity-query/EntityType.js +61 -25
- package/dist/entity-query/EntityType.js.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
- package/dist/migrations/postgres/PostgresMigrations.d.ts +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
- package/dist/migrations/sql-server/SqlServerMigrations.d.ts +1 -1
- package/dist/model/EntityModel.js +2 -2
- package/dist/model/EntityModel.js.map +1 -1
- package/dist/model/EntitySource.d.ts +6 -1
- package/dist/model/EntitySource.d.ts.map +1 -1
- package/dist/model/EntitySource.js.map +1 -1
- package/dist/model/SourceExpression.d.ts +1 -22
- package/dist/model/SourceExpression.d.ts.map +1 -1
- package/dist/model/SourceExpression.js +116 -98
- package/dist/model/SourceExpression.js.map +1 -1
- package/dist/model/changes/ChangeEntry.d.ts.map +1 -1
- package/dist/model/changes/ChangeEntry.js +62 -25
- package/dist/model/changes/ChangeEntry.js.map +1 -1
- package/dist/model/changes/ChangeSet.d.ts +2 -1
- package/dist/model/changes/ChangeSet.d.ts.map +1 -1
- package/dist/model/changes/ChangeSet.js +4 -3
- package/dist/model/changes/ChangeSet.js.map +1 -1
- package/dist/model/identity/IdentityMap.d.ts +23 -0
- package/dist/model/identity/IdentityMap.d.ts.map +1 -0
- package/dist/model/identity/IdentityMap.js +113 -0
- package/dist/model/identity/IdentityMap.js.map +1 -0
- package/dist/model/identity/RelationMapper.d.ts +2 -3
- package/dist/model/identity/RelationMapper.d.ts.map +1 -1
- package/dist/model/identity/RelationMapper.js +60 -27
- package/dist/model/identity/RelationMapper.js.map +1 -1
- package/dist/model/identity/SearchIndex.d.ts +17 -0
- package/dist/model/identity/SearchIndex.d.ts.map +1 -0
- package/dist/model/identity/SearchIndex.js +109 -0
- package/dist/model/identity/SearchIndex.js.map +1 -0
- package/dist/model/verification/VerificationSession.d.ts +1 -1
- package/dist/model/verification/VerificationSession.d.ts.map +1 -1
- package/dist/model/verification/VerificationSession.js +18 -16
- package/dist/model/verification/VerificationSession.js.map +1 -1
- package/dist/query/ast/ExpressionToSql.d.ts.map +1 -1
- package/dist/query/ast/ExpressionToSql.js +74 -52
- package/dist/query/ast/ExpressionToSql.js.map +1 -1
- package/dist/query/expander/QueryExpander.d.ts.map +1 -1
- package/dist/query/expander/QueryExpander.js +41 -10
- package/dist/query/expander/QueryExpander.js.map +1 -1
- package/dist/tests/db-tests/tests/multi-fk-tests.d.ts +3 -0
- package/dist/tests/db-tests/tests/multi-fk-tests.d.ts.map +1 -0
- package/dist/tests/db-tests/tests/multi-fk-tests.js +38 -0
- package/dist/tests/db-tests/tests/multi-fk-tests.js.map +1 -0
- package/dist/tests/expressions/left-joins/child-joins.js +7 -7
- package/dist/tests/model/ShoppingContext.d.ts +9 -0
- package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
- package/dist/tests/model/ShoppingContext.js +34 -0
- package/dist/tests/model/ShoppingContext.js.map +1 -1
- package/dist/tests/security/tests/include-items.d.ts.map +1 -1
- package/dist/tests/security/tests/include-items.js +1 -0
- package/dist/tests/security/tests/include-items.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/common/symbols/symbols.ts +2 -1
- package/src/decorators/ForeignKey.ts +66 -28
- package/src/decorators/IColumn.ts +4 -3
- package/src/decorators/Relate.ts +8 -6
- package/src/entity-query/EntityType.ts +64 -26
- package/src/migrations/postgres/PostgresAutomaticMigrations.ts +1 -1
- package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +1 -1
- package/src/model/EntityModel.ts +2 -2
- package/src/model/EntitySource.ts +6 -1
- package/src/model/SourceExpression.ts +132 -132
- package/src/model/changes/ChangeEntry.ts +68 -25
- package/src/model/changes/ChangeSet.ts +4 -3
- package/src/model/identity/IdentityMap.ts +126 -0
- package/src/model/identity/RelationMapper.ts +71 -27
- package/src/model/identity/SearchIndex.ts +120 -0
- package/src/model/verification/VerificationSession.ts +19 -16
- package/src/query/ast/ExpressionToSql.ts +77 -61
- package/src/query/expander/QueryExpander.ts +52 -28
- package/src/tests/db-tests/tests/multi-fk-tests.ts +46 -0
- package/src/tests/expressions/left-joins/child-joins.ts +7 -7
- package/src/tests/model/ShoppingContext.ts +32 -0
- package/src/tests/security/tests/include-items.ts +1 -0
|
@@ -168,14 +168,16 @@ export default class ChangeEntry<T = any> implements IChanges {
|
|
|
168
168
|
// this is tricky as we need to build inverse query...
|
|
169
169
|
const { relatedRelation } = relation;
|
|
170
170
|
const filter = [];
|
|
171
|
-
for (const
|
|
172
|
-
filter.push(`x.${relatedRelation.name}.${
|
|
171
|
+
for (const { fkColumn, relatedKeyColumn } of relatedRelation.fkMap) {
|
|
172
|
+
filter.push(`x.${relatedRelation.name}.${fkColumn.name} === p.${relatedKeyColumn.name}`);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
await context.model.register(relatedEntity.typeClass)
|
|
176
176
|
.where(this.entity, `(p) => (x) => ${filter.join(" && ")}` as any)
|
|
177
177
|
.toArray();
|
|
178
178
|
|
|
179
|
+
return;
|
|
180
|
+
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
if (this.entity[relation.name]) {
|
|
@@ -183,9 +185,13 @@ export default class ChangeEntry<T = any> implements IChanges {
|
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
|
|
186
|
-
|
|
188
|
+
// need to setup inverse key check
|
|
189
|
+
// const key = relatedEntity.keys[0];
|
|
187
190
|
const keys = {} as any;
|
|
188
|
-
keys[key.name] = this.entity[relation.fkColumn.name];
|
|
191
|
+
// keys[key.name] = this.entity[relation.fkColumn.name];
|
|
192
|
+
for (const { fkColumn, relatedKeyColumn } of relation.fkMap) {
|
|
193
|
+
keys[relatedKeyColumn.name] = this.entity[fkColumn.name];
|
|
194
|
+
}
|
|
189
195
|
this.entity[relation.name] = await context.model.register(relatedEntity.typeClass).loadByKeys(keys);
|
|
190
196
|
}
|
|
191
197
|
|
|
@@ -281,7 +287,7 @@ export default class ChangeEntry<T = any> implements IChanges {
|
|
|
281
287
|
}
|
|
282
288
|
|
|
283
289
|
// if related has key defined.. set it...
|
|
284
|
-
const rKey = iterator.relatedEntity.keys[0];
|
|
290
|
+
// const rKey = iterator.relatedEntity.keys[0];
|
|
285
291
|
|
|
286
292
|
// lets set the prototype...
|
|
287
293
|
const prototype = iterator.relatedTypeClass.prototype;
|
|
@@ -290,38 +296,75 @@ export default class ChangeEntry<T = any> implements IChanges {
|
|
|
290
296
|
}
|
|
291
297
|
const relatedChanges = this.changeSet.getEntry(related);
|
|
292
298
|
|
|
293
|
-
const
|
|
294
|
-
|
|
299
|
+
for (const { fkColumn, relatedKeyColumn } of iterator.fkMap) {
|
|
300
|
+
const keyValue = related[relatedKeyColumn.name];
|
|
301
|
+
if (keyValue === void 0) {
|
|
295
302
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
303
|
+
if(relatedChanges.dependents.has(this)) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
relatedChanges.dependents.add(this);
|
|
300
307
|
|
|
301
|
-
|
|
308
|
+
this.order++;
|
|
302
309
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
310
|
+
for (const d of this.dependents) {
|
|
311
|
+
d.order++;
|
|
312
|
+
}
|
|
306
313
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
314
|
+
if (!fkColumn.columnName) {
|
|
315
|
+
throw new EntityAccessError(`Configuration error, fk not set for ${fkColumn.name}`);
|
|
316
|
+
}
|
|
317
|
+
relatedChanges.pending.push(() => {
|
|
318
|
+
this.entity[fkColumn.name] = related[relatedKeyColumn.name];
|
|
319
|
+
});
|
|
320
|
+
if (this.status !== "inserted") {
|
|
321
|
+
this.modified.set(iterator, { column: fkColumn, oldValue: void 0, newValue: void 0});
|
|
322
|
+
}
|
|
316
323
|
}
|
|
317
324
|
continue;
|
|
318
325
|
}
|
|
319
326
|
|
|
327
|
+
// const keyValue = related[rKey.name];
|
|
328
|
+
// if (keyValue === void 0) {
|
|
329
|
+
|
|
330
|
+
// if(relatedChanges.dependents.has(this)) {
|
|
331
|
+
// continue;
|
|
332
|
+
// }
|
|
333
|
+
// relatedChanges.dependents.add(this);
|
|
334
|
+
|
|
335
|
+
// this.order++;
|
|
336
|
+
|
|
337
|
+
// for (const d of this.dependents) {
|
|
338
|
+
// d.order++;
|
|
339
|
+
// }
|
|
340
|
+
|
|
341
|
+
// const fk = iterator;
|
|
342
|
+
// if (!fk.fkMap?.length) {
|
|
343
|
+
// throw new EntityAccessError(`Configuration error, fk not set for ${fk.name}`);
|
|
344
|
+
// }
|
|
345
|
+
// relatedChanges.pending.push(() => {
|
|
346
|
+
// for (const { fkColumn, relatedKeyColumn } of fk.fkMap) {
|
|
347
|
+
// this.entity[fkColumn.name] = related[relatedKeyColumn.name];
|
|
348
|
+
// }
|
|
349
|
+
// // this.entity[fk.fkColumn.name] = related[rKey.name];
|
|
350
|
+
// });
|
|
351
|
+
// if (this.status !== "inserted") {
|
|
352
|
+
// for (const { fkColumn } of fk.fkMap) {
|
|
353
|
+
// this.modified.set(iterator, { column: fkColumn, oldValue: void 0, newValue: void 0});
|
|
354
|
+
// }
|
|
355
|
+
// // this.modified.set(iterator, { column: iterator.fkColumn, oldValue: void 0, newValue: void 0});
|
|
356
|
+
// }
|
|
357
|
+
// continue;
|
|
358
|
+
// }
|
|
359
|
+
|
|
320
360
|
if(!relatedChanges.dependents.has(this)) {
|
|
321
361
|
relatedChanges.dependents.add(this);
|
|
322
362
|
this.order += relatedChanges.order;
|
|
323
363
|
}
|
|
324
|
-
|
|
364
|
+
for (const { fkColumn, relatedKeyColumn } of iterator.fkMap) {
|
|
365
|
+
this.entity[fkColumn.name] = related[relatedKeyColumn.name];
|
|
366
|
+
}
|
|
367
|
+
// this.entity[iterator.fkColumn.name] = related[rKey.name];
|
|
325
368
|
}
|
|
326
369
|
}
|
|
327
370
|
|
|
@@ -3,6 +3,7 @@ import EntityAccessError from "../../common/EntityAccessError.js";
|
|
|
3
3
|
import EventSet from "../../common/EventSet.js";
|
|
4
4
|
import SchemaRegistry from "../../decorators/SchemaRegistry.js";
|
|
5
5
|
import EntityContext from "../EntityContext.js";
|
|
6
|
+
import IdentityMap from "../identity/IdentityMap.js";
|
|
6
7
|
import IdentityService, { identityMapSymbol } from "../identity/IdentityService.js";
|
|
7
8
|
import ChangeEntry, { privateUpdateEntry, getContext } from "./ChangeEntry.js";
|
|
8
9
|
|
|
@@ -26,7 +27,7 @@ export default class ChangeSet {
|
|
|
26
27
|
/**
|
|
27
28
|
* This will provide new entity for same key
|
|
28
29
|
*/
|
|
29
|
-
private identityMap
|
|
30
|
+
private identityMap = new IdentityMap();
|
|
30
31
|
|
|
31
32
|
private nextId = 1;
|
|
32
33
|
|
|
@@ -70,7 +71,7 @@ export default class ChangeSet {
|
|
|
70
71
|
this.entryMap.delete(entry.entity);
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
|
-
this.identityMap.set(jsonKey, entry.entity);
|
|
74
|
+
this.identityMap.set(jsonKey, entry.entity, entry.type);
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -101,7 +102,7 @@ export default class ChangeSet {
|
|
|
101
102
|
return entry.updateValues(original);
|
|
102
103
|
}
|
|
103
104
|
} else {
|
|
104
|
-
this.identityMap.set(jsonKey, entity);
|
|
105
|
+
this.identityMap.set(jsonKey, entity, type);
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
entry = new ChangeEntry({
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { entityTypeSymbol } from "../../common/symbols/symbols.js";
|
|
2
|
+
import { IColumn } from "../../decorators/IColumn.js";
|
|
3
|
+
import type EntityType from "../../entity-query/EntityType.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Locally cache uniquely identifiable entities
|
|
7
|
+
*/
|
|
8
|
+
export default class IdentityMap {
|
|
9
|
+
|
|
10
|
+
public get indexedColumns() {
|
|
11
|
+
return this.keys.keys();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private map = new Map<string, any>();
|
|
15
|
+
|
|
16
|
+
private keys = new Map<IColumn, Map<any, any[]>>();
|
|
17
|
+
|
|
18
|
+
public delete(jsonKey) {
|
|
19
|
+
const item = this.map.get(jsonKey);
|
|
20
|
+
this.map.delete(jsonKey);
|
|
21
|
+
if (item) {
|
|
22
|
+
const type = item[entityTypeSymbol] as EntityType;
|
|
23
|
+
for (const column of type.columns) {
|
|
24
|
+
const values = this.keys.get(column);
|
|
25
|
+
if (!values) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const value = item[column.name];
|
|
29
|
+
if (value === void 0 || value === null) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const entries = values.get(value);
|
|
33
|
+
if (!entries) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const index = entries.findIndex(item);
|
|
37
|
+
entries.splice(index, 1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public get(jsonKeys) {
|
|
43
|
+
return this.map.get(jsonKeys);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public set(jsonKey, entity, type: EntityType) {
|
|
47
|
+
entity[entityTypeSymbol] = type;
|
|
48
|
+
this.map.set(jsonKey, entity);
|
|
49
|
+
this.updateSearchIndex(type, entity);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public clear() {
|
|
53
|
+
this.map.clear();
|
|
54
|
+
this.keys.clear();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public build(key: IColumn) {
|
|
58
|
+
return this.getKeyEntry(key, true);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
searchByKeys(pairs: { key: IColumn, value}[], create = true) {
|
|
62
|
+
let results: any[];
|
|
63
|
+
for (const { key, value } of pairs) {
|
|
64
|
+
const items = this.getAll(key, value, create);
|
|
65
|
+
if (!items?.length) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!results) {
|
|
69
|
+
results = [].concat(items);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const old = results;
|
|
73
|
+
results = [];
|
|
74
|
+
for (const item of items) {
|
|
75
|
+
if (old.includes(item)) {
|
|
76
|
+
results.push(item);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return results[0];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private getAll(key: IColumn, value: any, create = true) {
|
|
84
|
+
const keyEntry = this.getKeyEntry(key, create);
|
|
85
|
+
return keyEntry.get(value);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private getKeyEntry(key: IColumn, create = false) {
|
|
89
|
+
let keyEntry = this.keys.get(key);
|
|
90
|
+
if (keyEntry) {
|
|
91
|
+
return keyEntry;
|
|
92
|
+
}
|
|
93
|
+
if (!create) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
keyEntry = new Map<any, any[]>();
|
|
97
|
+
this.keys.set(key, keyEntry);
|
|
98
|
+
for (const entry of this.map.values()) {
|
|
99
|
+
this.updateSearchIndex(entry[entityTypeSymbol], entry);
|
|
100
|
+
}
|
|
101
|
+
return keyEntry;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private updateSearchIndex(type: EntityType, entity: any) {
|
|
105
|
+
for (const key of this.keys.keys()) {
|
|
106
|
+
if (type.getField(key.name) !== key) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const keyEntry = this.getKeyEntry(key, true);
|
|
110
|
+
const value = entity[key.name];
|
|
111
|
+
if (value === void 0 || value === null) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
let values = keyEntry.get(value);
|
|
115
|
+
if (!values) {
|
|
116
|
+
values = [];
|
|
117
|
+
keyEntry.set(value, values);
|
|
118
|
+
}
|
|
119
|
+
if (values.includes(entity)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
values.push(entity);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
|
+
import EventEmitter from "events";
|
|
1
2
|
import type ChangeEntry from "../changes/ChangeEntry.js";
|
|
2
3
|
import type ChangeSet from "../changes/ChangeSet.js";
|
|
3
4
|
import IdentityService, { identityMapSymbol } from "./IdentityService.js";
|
|
5
|
+
import { IColumn } from "../../decorators/IColumn.js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
4
9
|
|
|
5
10
|
export default class RelationMapper {
|
|
6
11
|
|
|
7
|
-
private map: Map<string, ChangeEntry[]> = new Map();
|
|
12
|
+
// private map: Map<string, ChangeEntry[]> = new Map();
|
|
13
|
+
|
|
14
|
+
private events: EventEmitter = new EventEmitter();
|
|
8
15
|
|
|
9
16
|
constructor(
|
|
10
17
|
private changeSet: ChangeSet,
|
|
11
|
-
private identityMap
|
|
18
|
+
private identityMap = changeSet[identityMapSymbol]
|
|
12
19
|
) {
|
|
13
20
|
|
|
14
21
|
}
|
|
15
22
|
|
|
16
|
-
push(id: string, waiter: ChangeEntry) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
23
|
+
// push(id: string, waiter: ChangeEntry) {
|
|
24
|
+
// let queue = this.map.get(id);
|
|
25
|
+
// if (!queue) {
|
|
26
|
+
// queue = [];
|
|
27
|
+
// this.map.set(id, queue);
|
|
28
|
+
// }
|
|
29
|
+
// queue.push(waiter);
|
|
30
|
+
// }
|
|
24
31
|
|
|
25
32
|
fix(entry: ChangeEntry, nest = true) {
|
|
26
33
|
|
|
@@ -30,23 +37,48 @@ export default class RelationMapper {
|
|
|
30
37
|
if (iterator.isInverseRelation) {
|
|
31
38
|
continue;
|
|
32
39
|
}
|
|
33
|
-
const fkColumn = iterator.fkColumn.name;
|
|
34
|
-
const fkValue = entity[fkColumn];
|
|
35
|
-
if (fkValue === void 0) {
|
|
36
|
-
|
|
37
|
-
}
|
|
40
|
+
// const fkColumn = iterator.fkColumn.name;
|
|
41
|
+
// const fkValue = entity[fkColumn];
|
|
42
|
+
// if (fkValue === void 0) {
|
|
43
|
+
// continue;
|
|
44
|
+
// }
|
|
45
|
+
|
|
38
46
|
// get from identity...
|
|
39
|
-
const id = IdentityService.buildIdentity(iterator.relatedEntity, fkValue);
|
|
40
|
-
const parent = this.identityMap.get(id);
|
|
47
|
+
// const id = IdentityService.buildIdentity(iterator.relatedEntity, fkValue);
|
|
48
|
+
// const parent = this.identityMap.get(id);
|
|
49
|
+
// if (!parent) {
|
|
50
|
+
// let waiters = this.map.get(id);
|
|
51
|
+
// if (!waiters) {
|
|
52
|
+
// waiters = [];
|
|
53
|
+
// this.map.set(id, waiters);
|
|
54
|
+
// }
|
|
55
|
+
// waiters.push(entry);
|
|
56
|
+
// continue;
|
|
57
|
+
// }
|
|
58
|
+
|
|
59
|
+
const pairs = [] as { key: IColumn, value: any}[];
|
|
60
|
+
|
|
61
|
+
for (const { fkColumn, relatedKeyColumn } of iterator.fkMap) {
|
|
62
|
+
this.identityMap.build(relatedKeyColumn);
|
|
63
|
+
const fkValue = entity[fkColumn.name];
|
|
64
|
+
if (fkValue === void 0) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
pairs.push({ key: relatedKeyColumn, value: fkValue});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const parent = this.identityMap.searchByKeys(pairs, true);
|
|
41
71
|
if (!parent) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
if (nest) {
|
|
73
|
+
for (const { key, value } of pairs) {
|
|
74
|
+
this.events.once(`${key.entityType.name}-${key.name}-${value}`, (k) => {
|
|
75
|
+
this.fix(entry, false);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
46
78
|
}
|
|
47
|
-
waiters.push(entry);
|
|
48
79
|
continue;
|
|
49
80
|
}
|
|
81
|
+
|
|
50
82
|
entity[iterator.name] = parent;
|
|
51
83
|
|
|
52
84
|
if (iterator.relatedRelation.isCollection) {
|
|
@@ -64,12 +96,24 @@ export default class RelationMapper {
|
|
|
64
96
|
}
|
|
65
97
|
|
|
66
98
|
// see if anyone is waiting for us or not...
|
|
67
|
-
const identity = IdentityService.getIdentity(entry.type, entry.entity);
|
|
68
|
-
const pending = this.map.get(identity);
|
|
69
|
-
if (pending && pending.length) {
|
|
70
|
-
|
|
71
|
-
|
|
99
|
+
// const identity = IdentityService.getIdentity(entry.type, entry.entity);
|
|
100
|
+
// const pending = this.map.get(identity);
|
|
101
|
+
// if (pending && pending.length) {
|
|
102
|
+
// for (const iterator of pending) {
|
|
103
|
+
// this.fix(iterator, false);
|
|
104
|
+
// }
|
|
105
|
+
// }
|
|
106
|
+
|
|
107
|
+
for (const iterator of this.identityMap.indexedColumns) {
|
|
108
|
+
if (iterator.entityType !== entry.type) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const value = entry.entity[iterator.name];
|
|
112
|
+
if (value === void 0 || value === null) {
|
|
113
|
+
continue;
|
|
72
114
|
}
|
|
115
|
+
const key = `${iterator.entityType.name}-${iterator.name}-${value}`;
|
|
116
|
+
this.events.emit(key, key);
|
|
73
117
|
}
|
|
74
118
|
}
|
|
75
119
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { IColumn } from "../../decorators/IColumn.js";
|
|
2
|
+
import type ChangeEntry from "../changes/ChangeEntry.js";
|
|
3
|
+
|
|
4
|
+
export default class SearchIndex {
|
|
5
|
+
|
|
6
|
+
private keys = new Map<string, Map<any, any[]>>();
|
|
7
|
+
|
|
8
|
+
constructor(private entries: ChangeEntry[]) {
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getByKeys(pairs: { key, value}[], create = true) {
|
|
13
|
+
let results: any[];
|
|
14
|
+
for (const { key, value } of pairs) {
|
|
15
|
+
const items = this.getAll(key, value, create);
|
|
16
|
+
if (!items?.length) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!results) {
|
|
20
|
+
results = [].concat(items);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const old = results;
|
|
24
|
+
results = [];
|
|
25
|
+
for (const item of items) {
|
|
26
|
+
if (old.includes(item)) {
|
|
27
|
+
results.push(item);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getAll(key: string, value: any, create = true) {
|
|
35
|
+
const keyEntry = this.getKeyEntry(key, create);
|
|
36
|
+
return keyEntry.get(value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
delete(entry) {
|
|
40
|
+
for (const [key,values] of this.keys) {
|
|
41
|
+
const value = entry[key];
|
|
42
|
+
if (value === void 0 || value === null) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const entries = values.get(value);
|
|
46
|
+
if (!entries) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const index = entries.findIndex(entry);
|
|
50
|
+
entries.splice(index, 1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get(keys: IColumn[], entry) {
|
|
55
|
+
let results: any[];
|
|
56
|
+
for (const { name } of keys) {
|
|
57
|
+
const items = this.getAll(name, entry[name]);
|
|
58
|
+
if (!items?.length) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!results) {
|
|
62
|
+
results = [].concat(items);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const old = results;
|
|
66
|
+
results = [];
|
|
67
|
+
for (const item of items) {
|
|
68
|
+
if (old.includes(item)) {
|
|
69
|
+
results.push(item);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return results[0];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
update(keys: IColumn[], entry) {
|
|
77
|
+
for (const key of keys) {
|
|
78
|
+
const keyEntry = this.getKeyEntry(key.name, true);
|
|
79
|
+
const value = entry[key.name];
|
|
80
|
+
if (value === void 0 || value === null) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
let values = keyEntry.get(value);
|
|
84
|
+
if (!values) {
|
|
85
|
+
values = [];
|
|
86
|
+
keyEntry.set(value, values);
|
|
87
|
+
}
|
|
88
|
+
if (values.includes(entry)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
values.push(entry);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private getKeyEntry(key: string, create = false) {
|
|
96
|
+
let keyEntry = this.keys.get(key);
|
|
97
|
+
if (keyEntry) {
|
|
98
|
+
return keyEntry;
|
|
99
|
+
}
|
|
100
|
+
if (!create) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
keyEntry = new Map<any, any[]>();
|
|
104
|
+
this.keys.set(key, keyEntry);
|
|
105
|
+
for (const entry of this.entries) {
|
|
106
|
+
const value = entry[key];
|
|
107
|
+
if (value === void 0 || value === null) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
let values = keyEntry.get(value);
|
|
111
|
+
if (!values) {
|
|
112
|
+
values = [];
|
|
113
|
+
keyEntry.set(value, values);
|
|
114
|
+
}
|
|
115
|
+
values.push(value);
|
|
116
|
+
}
|
|
117
|
+
return keyEntry;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
|
@@ -63,30 +63,33 @@ export default class VerificationSession {
|
|
|
63
63
|
continue;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const fk = relation.
|
|
66
|
+
const fk = relation.fkMap;
|
|
67
67
|
if (!fk) {
|
|
68
68
|
continue;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const
|
|
72
|
-
if (fkValue === void 0) {
|
|
73
|
-
// not set... ignore..
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (isKeyEmpty(fkValue, relation.fkColumn)) {
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
71
|
+
for (const { fkColumn , relatedKeyColumn } of fk) {
|
|
79
72
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
const fkValue = entity[fkColumn.name];
|
|
74
|
+
if (fkValue === void 0) {
|
|
75
|
+
// not set... ignore..
|
|
83
76
|
continue;
|
|
84
77
|
}
|
|
78
|
+
if (isKeyEmpty(fkValue, fkColumn)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// only if it is modified...
|
|
83
|
+
if (change.status !== "inserted") {
|
|
84
|
+
if (!change.isModified(fkColumn.name)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
this.queueEntityForeignKey(change, relation, fkColumn, relatedKeyColumn, fkValue);
|
|
85
89
|
}
|
|
86
|
-
this.queueEntityForeignKey(change, relation, fkValue);
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
|
-
queueEntityForeignKey(change: ChangeEntry, relation: IEntityRelation, value) {
|
|
92
|
+
queueEntityForeignKey(change: ChangeEntry, relation: IEntityRelation, fkColumn, relatedKeyColumn, value) {
|
|
90
93
|
const relatedModel = relation.relatedEntity;
|
|
91
94
|
const type = relation.relatedEntity.typeClass;
|
|
92
95
|
const events = this.context.eventsFor(change.type.typeClass);
|
|
@@ -97,7 +100,7 @@ export default class VerificationSession {
|
|
|
97
100
|
events: relatedEvents,
|
|
98
101
|
type: relatedModel,
|
|
99
102
|
name: relation.name,
|
|
100
|
-
fkName:
|
|
103
|
+
fkName: fkColumn.name,
|
|
101
104
|
entity: change.entity
|
|
102
105
|
});
|
|
103
106
|
let query = events.onForeignKeyFilter(fk);
|
|
@@ -110,7 +113,7 @@ export default class VerificationSession {
|
|
|
110
113
|
|
|
111
114
|
const eq = query as EntityQuery;
|
|
112
115
|
const compare = Expression.equal(
|
|
113
|
-
Expression.member(eq.selectStatement.sourceParameter,
|
|
116
|
+
Expression.member(eq.selectStatement.sourceParameter, relatedKeyColumn.columnName),
|
|
114
117
|
Expression.constant(value)
|
|
115
118
|
);
|
|
116
119
|
const typeName = TypeInfo.nameOfType(type);
|