UNPKG

7.03 kBJavaScriptView Raw
1/**
2 * @copyright Copyright (c) 2019 Maxim Khorin <maksimovichu@gmail.com>
3 */
4'use strict';
5
6const Base = require('../base/Base');
7
8module.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 // unset related so that it can be reloaded to reflect the changes
50 this.owner.unsetRelated(relation.getViaRelationName());
51 model = this.owner.spawn(via.model.constructor);
52 model.assign(columns);
53 return model.insert();
54 }
55
56 async unlink (name, model, deletion) {
57 const relation = this.owner.getRelation(name);
58 const method = relation.isOuterLink() ? 'unlinkVia' : 'unlinkInternal';
59 await this[method](relation, model, deletion);
60 this.unsetUnlinked(name, model, relation);
61 return PromiseHelper.setImmediate();
62 }
63
64 async unlinkInternal (relation, model) {
65 const ref = model.get(relation.refKey);
66 const link = this.owner.get(relation.linkKey);
67 relation.isBackRef()
68 ? await QueryHelper.unlinkInternal(ref, link, model, relation.refKey)
69 : await QueryHelper.unlinkInternal(link, ref, this.owner, relation.linkKey);
70 }
71
72 unlinkVia (relation, model, deletion = true) {
73 const via = relation.getViaTable() || relation.getViaRelation();
74 const condition = {
75 [via.refKey]: this.owner.get(via.linkKey),
76 [relation.linkKey]: model.get(relation.refKey)
77 };
78 const nulls = {
79 [via.refKey]: null,
80 [relation.linkKey]: null
81 };
82 if (relation.getViaTable()) {
83 return deletion
84 ? this.owner.getDb().delete(via.getTable(), condition)
85 : this.owner.getDb().update(via.getTable(), condition, nulls);
86 }
87 this.owner.unsetRelated(relation.getViaRelationName());
88 return deletion
89 ? via.model.find(condition).delete()
90 : via.model.find(condition).updateAll(nulls);
91 }
92
93 async unlinkAll (name, deletion) {
94 const relation = this.owner.getRelation(name);
95 if (relation) {
96 const method = relation.isOuterLink() ? 'unlinkViaAll' : 'unlinkInternalAll';
97 await this[method](relation, deletion);
98 this.owner.unsetRelated(name);
99 }
100 }
101
102 async unlinkViaAll (relation, deletion = true) {
103 if (relation.getViaRelation()) {
104 this.owner.unsetRelated(relation.getViaRelationName());
105 }
106 const via = relation.getViaTable() || relation.getViaRelation();
107 let condition = {[via.refKey]: this.owner.get(via.linkKey)};
108 if (via.getWhere()) {
109 condition = ['AND', condition, via.getWhere()];
110 }
111 let nulls = {[via.refKey]: null};
112 if (relation.getViaTable()) {
113 condition = this.owner.getDb().buildCondition(condition);
114 deletion ? await this.owner.getDb().delete(via.getTable(), condition)
115 : await this.owner.getDb().update(via.getTable(), condition, nulls);
116 } else if (deletion) {
117 for (const model of await via.model.find(condition).all()) {
118 await model.delete();
119 }
120 } else {
121 await via.model.find(condition).updateAll(nulls);
122 }
123 }
124
125 async unlinkInternalAll (relation) {
126 // relation via array valued attribute
127 if (Array.isArray(this.owner.get(relation.linkKey))) {
128 this.owner.set(relation.linkKey, []);
129 return this.owner.forceSave();
130 }
131 let condition = {[relation.refKey]: this.owner.get(relation.linkKey)};
132 if (relation.getWhere()) {
133 condition = ['AND', condition, relation.getWhere()];
134 }
135 relation.getViaArray()
136 ? await relation.model.getDb().updateAllPull(relation.model.getTable(), {}, condition)
137 : await relation.model.find(condition).updateAll({[relation.refKey]: null});
138 }
139
140 unsetUnlinked (name, model, relation) {
141 if (!relation.isMultiple()) {
142 return this.owner.unsetRelated(name);
143 }
144 const models = this.owner.getRelated(name);
145 if (Array.isArray(models)) {
146 const result = models.filter(target => !CommonHelper.isEqual(model.getId(), target.getId()));
147 this.owner.populateRelation(name, result);
148 }
149 }
150
151 bindModels (foreignKey, primaryKey, foreignModel, primaryModel, relation) {
152 const value = primaryModel.get(primaryKey);
153 if (!value) {
154 throw new Error(this.wrapMessage('Primary key is null'));
155 }
156 if (!relation.getViaArray()) {
157 foreignModel.set(foreignKey, value);
158 return foreignModel.forceSave();
159 }
160 if (!Array.isArray(foreignModel.get(foreignKey))) {
161 foreignModel.set(foreignKey, []);
162 }
163 if (!ArrayHelper.includes(value, foreignModel.get(foreignKey))) {
164 foreignModel.get(foreignKey).push(value);
165 return foreignModel.forceSave();
166 }
167 }
168
169 wrapMessage (message) {
170 return `${this.constructor.name}: ${this.owner.wrapMessage(message)}`;
171 }
172};
173
174const ArrayHelper = require('../helper/ArrayHelper');
175const CommonHelper = require('../helper/CommonHelper');
176const PromiseHelper = require('../helper/PromiseHelper');
177const QueryHelper = require('../helper/QueryHelper');
\No newline at end of file