1 |
|
2 |
|
3 |
|
4 | 'use strict';
|
5 |
|
6 | const Base = require('../base/Base');
|
7 |
|
8 | module.exports = class ActiveLinker extends Base {
|
9 |
|
10 | async link (name, model, extraColumns) {
|
11 | const relation = this.owner.getRelation(name);
|
12 | const method = relation.isOuterLink() ? 'linkVia' : 'linkInternal';
|
13 | await this[method](relation, model, extraColumns);
|
14 | if (!relation.isMultiple()) {
|
15 | this.owner.populateRelation(name, model);
|
16 | return PromiseHelper.setImmediate();
|
17 | }
|
18 | const related = this.owner.getRelated(name);
|
19 | if (!related) {
|
20 | return PromiseHelper.setImmediate();
|
21 | }
|
22 | const index = relation.getIndex();
|
23 | if (index) {
|
24 | related[index] = model;
|
25 | } else {
|
26 | related.push(model);
|
27 | }
|
28 | return PromiseHelper.setImmediate();
|
29 | }
|
30 |
|
31 | linkInternal (relation, model) {
|
32 | return relation.isBackRef()
|
33 | ? this.bindModels(relation.refKey, relation.linkKey, model, this.owner, relation)
|
34 | : this.bindModels(relation.linkKey, relation.refKey, this.owner, model, relation);
|
35 | }
|
36 |
|
37 | linkVia (relation, model, extraColumns) {
|
38 | const via = relation.getViaTable() || relation.getViaRelation();
|
39 | const columns = {
|
40 | [via.refKey]: this.owner.get(via.linkKey),
|
41 | [relation.linkKey]: model.get(relation.refKey)
|
42 | };
|
43 | if (extraColumns) {
|
44 | Object.assign(columns, extraColumns);
|
45 | }
|
46 | if (relation.getViaTable()) {
|
47 | return this.owner.getDb().insert(via.getTable(), columns);
|
48 | }
|
49 |
|
50 | this.owner.unsetRelated(relation.getViaRelationName());
|
51 | const viaModel = this.owner.spawn(via.model.constructor);
|
52 | viaModel.assign(columns);
|
53 | return viaModel.insert();
|
54 | }
|
55 |
|
56 | linkViaModel (relation, targets, model) {
|
57 | const via = relation.getViaRelation();
|
58 | if (!model) {
|
59 | model = this.owner.spawn(via.model.constructor);
|
60 | } else if (!(model instanceof via.model.constructor)) {
|
61 | throw new Error(this.wrapMessage('Invalid link model'));
|
62 | }
|
63 | model.set(relation.linkKey, this.owner.get(relation.refKey));
|
64 | model.set(via.refKey, this.owner.get(via.linkKey));
|
65 | return model.save();
|
66 | }
|
67 |
|
68 | async unlink (name, model, deleted) {
|
69 | const relation = this.owner.getRelation(name);
|
70 | if (deleted === undefined) {
|
71 | deleted = relation.getDeleteOnUnlink();
|
72 | }
|
73 | const method = relation.isOuterLink() ? 'unlinkVia' : 'unlinkInternal';
|
74 | await this[method](relation, model, deleted);
|
75 | this.unsetUnlinked(name, model, relation);
|
76 | return PromiseHelper.setImmediate();
|
77 | }
|
78 |
|
79 | async unlinkInternal (relation, model, deleted) {
|
80 | const ref = model.get(relation.refKey);
|
81 | const link = this.owner.get(relation.linkKey);
|
82 | relation.isBackRef()
|
83 | ? await QueryHelper.unlinkInternal(ref, link, model, relation.refKey)
|
84 | : await QueryHelper.unlinkInternal(link, ref, this.owner, relation.linkKey);
|
85 | return deleted ? model.delete() : null;
|
86 | }
|
87 |
|
88 | unlinkVia (relation, model, deleted) {
|
89 | const via = relation.getViaTable() || relation.getViaRelation();
|
90 | const condition = {
|
91 | [via.refKey]: this.owner.get(via.linkKey),
|
92 | [relation.linkKey]: model.get(relation.refKey)
|
93 | };
|
94 | const nulls = {
|
95 | [via.refKey]: null,
|
96 | [relation.linkKey]: null
|
97 | };
|
98 | if (deleted === undefined) {
|
99 | deleted = via.getDeleteOnUnlink();
|
100 | }
|
101 | if (relation.getViaTable()) {
|
102 | return deleted
|
103 | ? this.owner.getDb().delete(via.getTable(), condition)
|
104 | : this.owner.getDb().update(via.getTable(), condition, nulls);
|
105 | }
|
106 | this.owner.unsetRelated(relation.getViaRelationName());
|
107 | return deleted
|
108 | ? via.model.find(condition).delete()
|
109 | : via.model.find(condition).updateAll(nulls);
|
110 | }
|
111 |
|
112 | async unlinkAll (name, deleted) {
|
113 | const relation = this.owner.getRelation(name);
|
114 | if (!relation) {
|
115 | return false;
|
116 | }
|
117 | if (deleted === undefined) {
|
118 | deleted = relation.getDeleteOnUnlink();
|
119 | }
|
120 | const method = relation.isOuterLink() ? 'unlinkViaAll' : 'unlinkInternalAll';
|
121 | await this[method](relation, deleted);
|
122 | this.owner.unsetRelated(name);
|
123 | }
|
124 |
|
125 | async unlinkViaAll (relation, deleted) {
|
126 | if (relation.getViaRelation()) {
|
127 | this.owner.unsetRelated(relation.getViaRelationName());
|
128 | }
|
129 | const via = relation.getViaTable() || relation.getViaRelation();
|
130 | let condition = {[via.refKey]: this.owner.get(via.linkKey)};
|
131 | if (via.getWhere()) {
|
132 | condition = ['AND', condition, via.getWhere()];
|
133 | }
|
134 | let nulls = {[via.refKey]: null};
|
135 | if (relation.getViaTable()) {
|
136 | condition = this.owner.getDb().buildCondition(condition);
|
137 | deleted ? await this.owner.getDb().delete(via.getTable(), condition)
|
138 | : await this.owner.getDb().update(via.getTable(), condition, nulls);
|
139 | } else if (deleted) {
|
140 | for (const model of await via.model.find(condition).all()) {
|
141 | await model.delete();
|
142 | }
|
143 | } else {
|
144 | await via.model.find(condition).updateAll(nulls);
|
145 | }
|
146 | }
|
147 |
|
148 | async unlinkInternalAll (relation, deleted) {
|
149 |
|
150 | if (!deleted && Array.isArray(this.owner.get(relation.linkKey))) {
|
151 | this.owner.set(relation.linkKey, []);
|
152 | return this.owner.forceSave();
|
153 | }
|
154 | let condition = {[relation.refKey]: this.owner.get(relation.linkKey)};
|
155 | if (relation.getWhere()) {
|
156 | condition = ['AND', condition, relation.getWhere()];
|
157 | }
|
158 | const nulls = {[relation.refKey]: null};
|
159 | if (deleted) {
|
160 | for (const model of await relation.all()) {
|
161 | await model.delete();
|
162 | }
|
163 | } else if (relation.getViaArray()) {
|
164 | await relation.model.getDb().updateAllPull(relation.model.getTable(), {}, condition);
|
165 | } else {
|
166 | await relation.model.find(condition).updateAll(nulls);
|
167 | }
|
168 | }
|
169 |
|
170 | unsetUnlinked (name, model, relation) {
|
171 | if (!relation.isMultiple()) {
|
172 | return this.owner.unsetRelated(name);
|
173 | }
|
174 | const models = this.owner.getRelated(name);
|
175 | if (Array.isArray(models)) {
|
176 | for (let i = models.length - 1; i >= 0; --i) {
|
177 | if (CommonHelper.isEqual(model.getId(), models[i].getId())) {
|
178 | models.splice(i, 1);
|
179 | }
|
180 | }
|
181 | }
|
182 | }
|
183 |
|
184 | bindModels (foreignKey, primaryKey, foreignModel, primaryModel, relation) {
|
185 | const value = primaryModel.get(primaryKey);
|
186 | if (!value) {
|
187 | throw new Error(this.wrapMessage('Primary key is null'));
|
188 | }
|
189 | if (!relation.getViaArray()) {
|
190 | foreignModel.set(foreignKey, value);
|
191 | return foreignModel.forceSave();
|
192 | }
|
193 | if (!Array.isArray(foreignModel.get(foreignKey))) {
|
194 | foreignModel.set(foreignKey, []);
|
195 | }
|
196 | if (!ArrayHelper.includes(value, foreignModel.get(foreignKey))) {
|
197 | foreignModel.get(foreignKey).push(value);
|
198 | return foreignModel.forceSave();
|
199 | }
|
200 | }
|
201 |
|
202 | wrapMessage (message) {
|
203 | return `${this.constructor.name}: ${this.owner.wrapMessage(message)}`;
|
204 | }
|
205 | };
|
206 |
|
207 | const ArrayHelper = require('../helper/ArrayHelper');
|
208 | const CommonHelper = require('../helper/CommonHelper');
|
209 | const PromiseHelper = require('../helper/PromiseHelper');
|
210 | const QueryHelper = require('../helper/QueryHelper'); |
\ | No newline at end of file |