333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var OrmUtils_1 = require("../util/OrmUtils");
/**
 * Subject is a subject of persistence.
 * It holds information about each entity that needs to be persisted:
 * - what entity should be persisted
 * - what is database representation of the persisted entity
 * - what entity metadata of the persisted entity
 * - what is allowed to with persisted entity (insert/update/remove)
 *
 * Having this collection of subjects we can perform database queries.
 */
var Subject = /** @class */ (function () {
    // -------------------------------------------------------------------------
    // Constructor
    // -------------------------------------------------------------------------
    function Subject(options) {
        var _a;
        /**
         * Subject identifier.
         * This identifier is not limited to table entity primary columns.
         * This can be entity id or ids as well as some unique entity properties, like name or title.
         * Insert / Update / Remove operation will be executed by a given identifier.
         */
        this.identifier = undefined;
        /**
         * Copy of entity but with relational ids fulfilled.
         */
        this.entityWithFulfilledIds = undefined;
        /**
         * Indicates if database entity was loaded.
         * No matter if it was found or not, it indicates the fact of loading.
         */
        this.databaseEntityLoaded = false;
        /**
         * Changes needs to be applied in the database for the given subject.
         */
        this.changeMaps = [];
        /**
         * Indicates if this subject can be inserted into the database.
         * This means that this subject either is newly persisted, either can be inserted by cascades.
         */
        this.canBeInserted = false;
        /**
         * Indicates if this subject can be updated in the database.
         * This means that this subject either was persisted, either can be updated by cascades.
         */
        this.canBeUpdated = false;
        /**
         * Indicates if this subject MUST be removed from the database.
         * This means that this subject either was removed, either was removed by cascades.
         */
        this.mustBeRemoved = false;
        /**
         * Relations updated by the change maps.
         */
        this.updatedRelationMaps = [];
        /**
         * List of updated columns
         */
        this.diffColumns = [];
        /**
         * List of updated relations
         */
        this.diffRelations = [];
        this.metadata = options.metadata;
        this.entity = options.entity;
        this.parentSubject = options.parentSubject;
        if (options.canBeInserted !== undefined)
            this.canBeInserted = options.canBeInserted;
        if (options.canBeUpdated !== undefined)
            this.canBeUpdated = options.canBeUpdated;
        if (options.mustBeRemoved !== undefined)
            this.mustBeRemoved = options.mustBeRemoved;
        if (options.identifier !== undefined)
            this.identifier = options.identifier;
        if (options.changeMaps !== undefined)
            (_a = this.changeMaps).push.apply(_a, tslib_1.__spread(options.changeMaps));
        this.recompute();
    }
    Object.defineProperty(Subject.prototype, "mustBeInserted", {
        // -------------------------------------------------------------------------
        // Accessors
        // -------------------------------------------------------------------------
        /**
         * Checks if this subject must be inserted into the database.
         * Subject can be inserted into the database if it is allowed to be inserted (explicitly persisted or by cascades)
         * and if it does not have database entity set.
         */
        get: function () {
            return this.canBeInserted && !this.databaseEntity;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Subject.prototype, "mustBeUpdated", {
        /**
         * Checks if this subject must be updated into the database.
         * Subject can be updated in the database if it is allowed to be updated (explicitly persisted or by cascades)
         * and if it does have differentiated columns or relations.
         */
        get: function () {
            return this.canBeUpdated &&
                this.identifier &&
                (this.databaseEntityLoaded === false || (this.databaseEntityLoaded && this.databaseEntity)) &&
                // ((this.entity && this.databaseEntity) || (!this.entity && !this.databaseEntity)) &&
                this.changeMaps.length > 0;
        },
        enumerable: true,
        configurable: true
    });
    // -------------------------------------------------------------------------
    // Public Methods
    // -------------------------------------------------------------------------
    /**
     * Creates a value set needs to be inserted / updated in the database.
     * Value set is based on the entity and change maps of the subject.
     * Important note: this method pops data from this subject's change maps.
     */
    Subject.prototype.createValueSetAndPopChangeMap = function () {
        var _this = this;
        var changeMapsWithoutValues = [];
        var changeSet = this.changeMaps.reduce(function (updateMap, changeMap) {
            var value = changeMap.value;
            if (value instanceof Subject) {
                // referenced columns can refer on values both which were just inserted and which were present in the model
                // if entity was just inserted valueSets must contain all values from the entity and values just inserted in the database
                // so, here we check if we have a value set then we simply use it as value to get our reference column values
                // otherwise simply use an entity which cannot be just inserted at the moment and have all necessary data
                value = value.insertedValueSet ? value.insertedValueSet : value.entity;
            }
            // value = changeMap.valueFactory ? changeMap.valueFactory(value) : changeMap.column.createValueMap(value);
            var valueMap;
            if (_this.metadata.isJunction && changeMap.column) {
                valueMap = changeMap.column.createValueMap(changeMap.column.referencedColumn.getEntityValue(value));
            }
            else if (changeMap.column) {
                valueMap = changeMap.column.createValueMap(value);
            }
            else if (changeMap.relation) {
                // value can be a related object, for example: post.question = { id: 1 }
                // or value can be a null or direct relation id, e.g. post.question = 1
                // if its a direction relation id then we just set it to the valueMap,
                // however if its an object then we need to extract its relation id map and set it to the valueMap
                if (value instanceof Object) {
                    // get relation id, e.g. referenced column name and its value,
                    // for example: { id: 1 } which then will be set to relation, e.g. post.category = { id: 1 }
                    var relationId = changeMap.relation.getRelationIdMap(value);
                    // but relation id can be empty, for example in the case when you insert a new post with category
                    // and both post and category are newly inserted objects (by cascades) and in this case category will not have id
                    // this means we need to insert post without question id and update post's questionId once question be inserted
                    // that's why we create a new changeMap operation for future updation of the post entity
                    if (relationId === undefined) {
                        changeMapsWithoutValues.push(changeMap);
                        _this.canBeUpdated = true;
                        return updateMap;
                    }
                    valueMap = changeMap.relation.createValueMap(relationId);
                    _this.updatedRelationMaps.push({ relation: changeMap.relation, value: relationId });
                }
                else { // value can be "null" or direct relation id here
                    valueMap = changeMap.relation.createValueMap(value);
                    _this.updatedRelationMaps.push({ relation: changeMap.relation, value: value });
                }
            }
            OrmUtils_1.OrmUtils.mergeDeep(updateMap, valueMap);
            return updateMap;
        }, {});
        this.changeMaps = changeMapsWithoutValues;
        return changeSet;
    };
    /**
     * Recomputes entityWithFulfilledIds and identifier when entity changes.
     */
    Subject.prototype.recompute = function () {
        var _this = this;
        if (this.entity) {
            this.entityWithFulfilledIds = Object.assign({}, this.entity);
            if (this.parentSubject) {
                this.metadata.primaryColumns.forEach(function (primaryColumn) {
                    if (primaryColumn.relationMetadata && primaryColumn.relationMetadata.inverseEntityMetadata === _this.parentSubject.metadata) {
                        primaryColumn.setEntityValue(_this.entityWithFulfilledIds, _this.parentSubject.entity);
                    }
                });
            }
            this.identifier = this.metadata.getEntityIdMap(this.entityWithFulfilledIds);
        }
        else if (this.databaseEntity) {
            this.identifier = this.metadata.getEntityIdMap(this.databaseEntity);
        }
    };
    return Subject;
}());
exports.Subject = Subject;
 
//# sourceMappingURL=Subject.js.map