1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var tslib_1 = require("tslib");
|
4 | /**
|
5 | * Loads database entities for all operate subjects which do not have database entity set.
|
6 | * All entities that we load database entities for are marked as updated or inserted.
|
7 | * To understand which of them really needs to be inserted or updated we need to load
|
8 | * their original representations from the database.
|
9 | */
|
10 | var SubjectDatabaseEntityLoader = /** @class */ (function () {
|
11 | // ---------------------------------------------------------------------
|
12 | // Constructor
|
13 | // ---------------------------------------------------------------------
|
14 | function SubjectDatabaseEntityLoader(queryRunner, subjects) {
|
15 | this.queryRunner = queryRunner;
|
16 | this.subjects = subjects;
|
17 | }
|
18 | // ---------------------------------------------------------------------
|
19 | // Public Methods
|
20 | // ---------------------------------------------------------------------
|
21 | /**
|
22 | * Loads database entities for all subjects.
|
23 | *
|
24 | * loadAllRelations flag is used to load all relation ids of the object, no matter if they present in subject entity or not.
|
25 | * This option is used for deletion.
|
26 | */
|
27 | SubjectDatabaseEntityLoader.prototype.load = function (operationType) {
|
28 | return tslib_1.__awaiter(this, void 0, void 0, function () {
|
29 | var promises;
|
30 | var _this = this;
|
31 | return tslib_1.__generator(this, function (_a) {
|
32 | switch (_a.label) {
|
33 | case 0:
|
34 | promises = this.groupByEntityTargets().map(function (subjectGroup) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
35 | var e_1, _a, allIds, allSubjects, loadRelationPropertyPaths, findOptions, entities, allSubjects_1, allSubjects_1_1, subject;
|
36 | var _this = this;
|
37 | return tslib_1.__generator(this, function (_b) {
|
38 | switch (_b.label) {
|
39 | case 0:
|
40 | allIds = [];
|
41 | allSubjects = [];
|
42 | subjectGroup.subjects.forEach(function (subject) {
|
43 | // we don't load if subject already has a database entity loaded
|
44 | if (subject.databaseEntity || !subject.identifier)
|
45 | return;
|
46 | allIds.push(subject.identifier);
|
47 | allSubjects.push(subject);
|
48 | });
|
49 | // if there no ids found (means all entities are new and have generated ids) - then nothing to load there
|
50 | if (!allIds.length)
|
51 | return [2 /*return*/];
|
52 | loadRelationPropertyPaths = [];
|
53 | // for the save operation
|
54 | // extract all property paths of the relations we need to load relation ids for
|
55 | // this is for optimization purpose - this way we don't load relation ids for entities
|
56 | // whose relations are undefined, and since they are undefined its really pointless to
|
57 | // load something for them, since undefined properties are skipped by the orm
|
58 | if (operationType === "save") {
|
59 | subjectGroup.subjects.forEach(function (subject) {
|
60 | // gets all relation property paths that exist in the persisted entity.
|
61 | subject.metadata.relations.forEach(function (relation) {
|
62 | var value = relation.getEntityValue(subject.entityWithFulfilledIds);
|
63 | if (value === undefined)
|
64 | return;
|
65 | if (loadRelationPropertyPaths.indexOf(relation.propertyPath) === -1)
|
66 | loadRelationPropertyPaths.push(relation.propertyPath);
|
67 | });
|
68 | });
|
69 | }
|
70 | else { // remove
|
71 | // for remove operation
|
72 | // we only need to load junction relation ids since only they are removed by cascades
|
73 | loadRelationPropertyPaths.push.apply(// remove
|
74 | loadRelationPropertyPaths, tslib_1.__spread(subjectGroup.subjects[0].metadata.manyToManyRelations.map(function (relation) { return relation.propertyPath; })));
|
75 | }
|
76 | findOptions = {
|
77 | loadEagerRelations: false,
|
78 | loadRelationIds: {
|
79 | relations: loadRelationPropertyPaths,
|
80 | disableMixedMap: true
|
81 | }
|
82 | };
|
83 | return [4 /*yield*/, this.queryRunner.manager
|
84 | .getRepository(subjectGroup.target)
|
85 | .findByIds(allIds, findOptions)];
|
86 | case 1:
|
87 | entities = _b.sent();
|
88 | // now when we have entities we need to find subject of each entity
|
89 | // and insert that entity into database entity of the found subjects
|
90 | entities.forEach(function (entity) {
|
91 | var subjects = _this.findByPersistEntityLike(subjectGroup.target, entity);
|
92 | subjects.forEach(function (subject) {
|
93 | subject.databaseEntity = entity;
|
94 | if (!subject.identifier)
|
95 | subject.identifier = subject.metadata.hasAllPrimaryKeys(entity) ? subject.metadata.getEntityIdMap(entity) : undefined;
|
96 | });
|
97 | });
|
98 | try {
|
99 | // this way we tell what subjects we tried to load database entities of
|
100 | for (allSubjects_1 = tslib_1.__values(allSubjects), allSubjects_1_1 = allSubjects_1.next(); !allSubjects_1_1.done; allSubjects_1_1 = allSubjects_1.next()) {
|
101 | subject = allSubjects_1_1.value;
|
102 | subject.databaseEntityLoaded = true;
|
103 | }
|
104 | }
|
105 | catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
106 | finally {
|
107 | try {
|
108 | if (allSubjects_1_1 && !allSubjects_1_1.done && (_a = allSubjects_1.return)) _a.call(allSubjects_1);
|
109 | }
|
110 | finally { if (e_1) throw e_1.error; }
|
111 | }
|
112 | return [2 /*return*/];
|
113 | }
|
114 | });
|
115 | }); });
|
116 | return [4 /*yield*/, Promise.all(promises)];
|
117 | case 1:
|
118 | _a.sent();
|
119 | return [2 /*return*/];
|
120 | }
|
121 | });
|
122 | });
|
123 | };
|
124 | // ---------------------------------------------------------------------
|
125 | // Protected Methods
|
126 | // ---------------------------------------------------------------------
|
127 | /**
|
128 | * Finds subjects where entity like given subject's entity.
|
129 | * Comparision made by entity id.
|
130 | * Multiple subjects may be returned if duplicates are present in the subject array.
|
131 | * This will likely result in the same row being updated multiple times during a transaction.
|
132 | */
|
133 | SubjectDatabaseEntityLoader.prototype.findByPersistEntityLike = function (entityTarget, entity) {
|
134 | return this.subjects.filter(function (subject) {
|
135 | if (!subject.entity)
|
136 | return false;
|
137 | if (subject.entity === entity)
|
138 | return true;
|
139 | return subject.metadata.target === entityTarget && subject.metadata.compareEntities(subject.entityWithFulfilledIds, entity);
|
140 | });
|
141 | };
|
142 | /**
|
143 | * Groups given Subject objects into groups separated by entity targets.
|
144 | */
|
145 | SubjectDatabaseEntityLoader.prototype.groupByEntityTargets = function () {
|
146 | return this.subjects.reduce(function (groups, operatedEntity) {
|
147 | var group = groups.find(function (group) { return group.target === operatedEntity.metadata.target; });
|
148 | if (!group) {
|
149 | group = { target: operatedEntity.metadata.target, subjects: [] };
|
150 | groups.push(group);
|
151 | }
|
152 | group.subjects.push(operatedEntity);
|
153 | return groups;
|
154 | }, []);
|
155 | };
|
156 | return SubjectDatabaseEntityLoader;
|
157 | }());
|
158 | exports.SubjectDatabaseEntityLoader = SubjectDatabaseEntityLoader;
|
159 |
|
160 | //# sourceMappingURL=SubjectDatabaseEntityLoader.js.map
|