forked from typeorm/typeorm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CascadesSubjectBuilder.ts
87 lines (71 loc) · 3.99 KB
/
CascadesSubjectBuilder.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import {Subject} from "../Subject";
import {ObjectLiteral} from "../../common/ObjectLiteral";
/**
* Finds all cascade operations of the given subject and cascade operations of the found cascaded subjects,
* e.g. builds a cascade tree and creates a subjects for them.
*/
export class CascadesSubjectBuilder {
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
constructor(protected allSubjects: Subject[]) {
}
// ---------------------------------------------------------------------
// Public Methods
// ---------------------------------------------------------------------
/**
* Builds a cascade subjects tree and pushes them in into the given array of subjects.
*/
async build(subject: Subject) {
const relationValues = await subject.metadata
.extractRelationValuesFromEntity(subject.entity!, subject.metadata.relations); // todo: we can create EntityMetadata.cascadeRelations
await Promise.all(relationValues.map(async ([relation, relationEntity, relationEntityMetadata]) => {
// we need only defined values and insert or update cascades of the relation should be set
if (relationEntity === undefined ||
relationEntity === null ||
(!relation.isCascadeInsert && !relation.isCascadeUpdate))
return;
// if relation entity is just a relation id set (for example post.tag = 1)
// then we don't really need to check cascades since there is no object to insert or update
if (!(relationEntity instanceof Object))
return;
// if we already has this entity in list of operated subjects then skip it to avoid recursion
const alreadyExistRelationEntitySubject = this.findByPersistEntityLike(relationEntityMetadata.target, relationEntity);
if (alreadyExistRelationEntitySubject) {
if (alreadyExistRelationEntitySubject.canBeInserted === false) // if its not marked for insertion yet
alreadyExistRelationEntitySubject.canBeInserted = relation.isCascadeInsert === true;
if (alreadyExistRelationEntitySubject.canBeUpdated === false) // if its not marked for update yet
alreadyExistRelationEntitySubject.canBeUpdated = relation.isCascadeUpdate === true;
return;
}
// mark subject with what we can do with it
// and add to the array of subjects to load only if there is no same entity there already
const relationEntitySubject = new Subject({
metadata: relationEntityMetadata,
parentSubject: subject,
entity: relationEntity,
canBeInserted: relation.isCascadeInsert === true,
canBeUpdated: relation.isCascadeUpdate === true
});
this.allSubjects.push(relationEntitySubject);
// go recursively and find other entities we need to insert/update
await this.build(relationEntitySubject);
}));
}
// ---------------------------------------------------------------------
// Protected Methods
// ---------------------------------------------------------------------
/**
* Finds subject where entity like given subject's entity.
* Comparision made by entity id.
*/
protected findByPersistEntityLike(entityTarget: Function|string, entity: ObjectLiteral): Subject|undefined {
return this.allSubjects.find(subject => {
if (!subject.entity)
return false;
if (subject.entity === entity)
return true;
return subject.metadata.target === entityTarget && subject.metadata.compareEntities(subject.entityWithFulfilledIds!, entity);
});
}
}