UNPKG

15.9 kBJavaScriptView Raw
1"use strict";
2// Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved.
3// Node module: @loopback/repository
4// This file is licensed under the MIT License.
5// License text available at https://opensource.org/licenses/MIT
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.DefaultHasManyThroughRepository = void 0;
8const __1 = require("../..");
9/**
10 * a class for CRUD operations for hasManyThrough relation.
11 *
12 * Warning: The hasManyThrough interface is experimental and is subject to change.
13 * If backwards-incompatible changes are made, a new major version may not be
14 * released.
15 */
16class DefaultHasManyThroughRepository {
17 constructor(getTargetRepository, getThroughRepository, getTargetConstraintFromThroughModels, getTargetKeys, getThroughConstraintFromSource, getTargetIds, getThroughConstraintFromTarget, targetResolver, throughResolver) {
18 this.getTargetRepository = getTargetRepository;
19 this.getThroughRepository = getThroughRepository;
20 this.getTargetConstraintFromThroughModels = getTargetConstraintFromThroughModels;
21 this.getTargetKeys = getTargetKeys;
22 this.getThroughConstraintFromSource = getThroughConstraintFromSource;
23 this.getTargetIds = getTargetIds;
24 this.getThroughConstraintFromTarget = getThroughConstraintFromTarget;
25 this.targetResolver = targetResolver;
26 this.throughResolver = throughResolver;
27 if (typeof getTargetRepository === 'function') {
28 this.getTargetRepositoryDict = {
29 [targetResolver().name]: getTargetRepository,
30 };
31 }
32 else {
33 this.getTargetRepositoryDict = getTargetRepository;
34 }
35 }
36 async create(targetModelData, options) {
37 let targetPolymorphicTypeName = options === null || options === void 0 ? void 0 : options.polymorphicType;
38 if (targetPolymorphicTypeName) {
39 if (!this.getTargetRepositoryDict[targetPolymorphicTypeName]) {
40 throw new __1.InvalidPolymorphismError(targetPolymorphicTypeName);
41 }
42 }
43 else {
44 if (Object.keys(this.getTargetRepositoryDict).length > 1) {
45 console.warn('It is highly recommended to specify the polymorphicTypes param when using polymorphic types.');
46 }
47 targetPolymorphicTypeName = this.targetResolver().name;
48 if (!this.getTargetRepositoryDict[targetPolymorphicTypeName]) {
49 throw new __1.InvalidPolymorphismError(targetPolymorphicTypeName);
50 }
51 }
52 const targetRepository = await this.getTargetRepositoryDict[targetPolymorphicTypeName]();
53 const targetInstance = await targetRepository.create(targetModelData, options);
54 await this.link(targetInstance.getId(), options);
55 return targetInstance;
56 }
57 async find(filter, options) {
58 var _a;
59 const targetDiscriminatorOnThrough = (_a = options === null || options === void 0 ? void 0 : options.throughOptions) === null || _a === void 0 ? void 0 : _a.discriminator;
60 let targetPolymorphicTypes = options === null || options === void 0 ? void 0 : options.polymorphicType;
61 let allKeys;
62 if (Object.keys(this.getTargetRepositoryDict).length <= 1) {
63 allKeys = Object.keys(this.getTargetRepositoryDict);
64 }
65 else {
66 if (!targetDiscriminatorOnThrough) {
67 console.warn('It is highly recommended to specify the targetDiscriminatorOnThrough param when using polymorphic types.');
68 }
69 if (!targetPolymorphicTypes || targetPolymorphicTypes.length === 0) {
70 console.warn('It is highly recommended to specify the polymorphicTypes param when using polymorphic types.');
71 allKeys = Object.keys(this.getTargetRepositoryDict);
72 }
73 else {
74 if (typeof targetPolymorphicTypes === 'string') {
75 targetPolymorphicTypes = [targetPolymorphicTypes];
76 }
77 allKeys = [];
78 new Set(targetPolymorphicTypes).forEach(element => {
79 if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
80 allKeys.push(element);
81 }
82 });
83 }
84 }
85 const sourceConstraint = this.getThroughConstraintFromSource();
86 const throughCategorized = {};
87 const throughRepository = await this.getThroughRepository();
88 (await throughRepository.find((0, __1.constrainFilter)(undefined, sourceConstraint), options === null || options === void 0 ? void 0 : options.throughOptions)).forEach(element => {
89 let concreteTargetType;
90 if (!targetDiscriminatorOnThrough) {
91 concreteTargetType = this.targetResolver().name;
92 }
93 else {
94 concreteTargetType = String(element[targetDiscriminatorOnThrough]);
95 }
96 if (!allKeys.includes(concreteTargetType)) {
97 return;
98 }
99 if (!this.getTargetRepositoryDict[concreteTargetType]) {
100 throw new __1.InvalidPolymorphismError(concreteTargetType, targetDiscriminatorOnThrough);
101 }
102 if (!throughCategorized[concreteTargetType]) {
103 throughCategorized[concreteTargetType] = [];
104 }
105 throughCategorized[concreteTargetType].push(element);
106 });
107 let allTargets = [];
108 for (const key of Object.keys(throughCategorized)) {
109 const targetRepository = await this.getTargetRepositoryDict[key]();
110 const targetConstraint = this.getTargetConstraintFromThroughModels(throughCategorized[key]);
111 allTargets = allTargets.concat(await targetRepository.find((0, __1.constrainFilter)(filter, targetConstraint), {
112 ...options,
113 polymorphicType: key,
114 }));
115 }
116 return allTargets;
117 }
118 async delete(where, options) {
119 var _a, _b, _c;
120 const targetDiscriminatorOnThrough = (_a = options === null || options === void 0 ? void 0 : options.throughOptions) === null || _a === void 0 ? void 0 : _a.discriminator;
121 let targetPolymorphicTypes = options === null || options === void 0 ? void 0 : options.polymorphicType;
122 let allKeys;
123 if (Object.keys(this.getTargetRepositoryDict).length <= 1) {
124 allKeys = Object.keys(this.getTargetRepositoryDict);
125 }
126 else {
127 if (!targetDiscriminatorOnThrough) {
128 console.warn('It is highly recommended to specify the targetDiscriminatorOnThrough param when using polymorphic types.');
129 }
130 if (!targetPolymorphicTypes || targetPolymorphicTypes.length === 0) {
131 console.warn('It is highly recommended to specify the polymorphicTypes param when using polymorphic types.');
132 allKeys = Object.keys(this.getTargetRepositoryDict);
133 }
134 else {
135 if (typeof targetPolymorphicTypes === 'string') {
136 targetPolymorphicTypes = [targetPolymorphicTypes];
137 }
138 allKeys = [];
139 new Set(targetPolymorphicTypes).forEach(element => {
140 if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
141 allKeys.push(element);
142 }
143 });
144 }
145 }
146 const sourceConstraint = this.getThroughConstraintFromSource();
147 let totalCount = 0;
148 const throughCategorized = {};
149 const throughRepository = await this.getThroughRepository();
150 (await throughRepository.find((0, __1.constrainFilter)(undefined, sourceConstraint), options === null || options === void 0 ? void 0 : options.throughOptions)).forEach(element => {
151 let concreteTargetType;
152 if (!targetDiscriminatorOnThrough) {
153 concreteTargetType = this.targetResolver().name;
154 }
155 else {
156 concreteTargetType = String(element[targetDiscriminatorOnThrough]);
157 }
158 if (!allKeys.includes(concreteTargetType)) {
159 return;
160 }
161 if (!this.getTargetRepositoryDict[concreteTargetType]) {
162 throw new __1.InvalidPolymorphismError(concreteTargetType, targetDiscriminatorOnThrough);
163 }
164 if (!throughCategorized[concreteTargetType]) {
165 throughCategorized[concreteTargetType] = [];
166 }
167 throughCategorized[concreteTargetType].push(element);
168 });
169 for (const targetKey of Object.keys(throughCategorized)) {
170 const targetRepository = await this.getTargetRepositoryDict[targetKey]();
171 if (where) {
172 // only delete related through models
173 // TODO(Agnes): this performance can be improved by only fetching related data
174 // TODO: add target ids to the `where` constraint
175 const targets = await targetRepository.find({ where });
176 const targetIds = this.getTargetIds(targets);
177 if (targetIds.length > 0) {
178 const targetConstraint = this.getThroughConstraintFromTarget(targetIds);
179 const constraints = { ...targetConstraint, ...sourceConstraint };
180 await throughRepository.deleteAll((0, __1.constrainDataObject)({}, constraints), options === null || options === void 0 ? void 0 : options.throughOptions);
181 }
182 }
183 else {
184 // otherwise, delete through models that relate to the sourceId
185 const targetFkValues = this.getTargetKeys(throughCategorized[targetKey]);
186 // delete through instances that have the targets that are going to be deleted
187 const throughFkConstraint = this.getThroughConstraintFromTarget(targetFkValues);
188 await throughRepository.deleteAll((0, __1.constrainWhereOr)({}, [
189 sourceConstraint,
190 throughFkConstraint,
191 ]));
192 }
193 // delete target(s)
194 const targetConstraint = this.getTargetConstraintFromThroughModels(throughCategorized[targetKey]);
195 totalCount +=
196 (_c = (_b = (await targetRepository.deleteAll((0, __1.constrainWhere)(where, targetConstraint), options))) === null || _b === void 0 ? void 0 : _b.count) !== null && _c !== void 0 ? _c : 0;
197 }
198 return { count: totalCount };
199 }
200 // only allows patch target instances for now
201 async patch(dataObject, where, options) {
202 var _a, _b, _c;
203 const targetDiscriminatorOnThrough = (_a = options === null || options === void 0 ? void 0 : options.throughOptions) === null || _a === void 0 ? void 0 : _a.discriminator;
204 const isMultipleTypes = options === null || options === void 0 ? void 0 : options.isPolymorphic;
205 let allKeys;
206 if (!targetDiscriminatorOnThrough) {
207 if (Object.keys(this.getTargetRepositoryDict).length > 1) {
208 console.warn('It is highly recommended to specify the targetDiscriminatorOnThrough param when using polymorphic types.');
209 }
210 }
211 if (!isMultipleTypes) {
212 if (Object.keys(this.getTargetRepositoryDict).length > 1) {
213 console.warn('It is highly recommended to specify the isMultipleTypes param and pass in a dictionary of dataobjects when using polymorphic types.');
214 }
215 allKeys = Object.keys(this.getTargetRepositoryDict);
216 }
217 else {
218 allKeys = [];
219 new Set(Object.keys(dataObject)).forEach(element => {
220 if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
221 allKeys.push(element);
222 }
223 });
224 }
225 const sourceConstraint = this.getThroughConstraintFromSource();
226 const throughCategorized = {};
227 const throughRepository = await this.getThroughRepository();
228 (await throughRepository.find((0, __1.constrainFilter)(undefined, sourceConstraint), options === null || options === void 0 ? void 0 : options.throughOptions)).forEach(element => {
229 let concreteTargetType;
230 if (!targetDiscriminatorOnThrough) {
231 concreteTargetType = this.targetResolver().name;
232 }
233 else {
234 concreteTargetType = String(element[targetDiscriminatorOnThrough]);
235 }
236 if (!allKeys.includes(concreteTargetType)) {
237 return;
238 }
239 if (!this.getTargetRepositoryDict[concreteTargetType]) {
240 throw new __1.InvalidPolymorphismError(concreteTargetType, targetDiscriminatorOnThrough);
241 }
242 if (!throughCategorized[concreteTargetType]) {
243 throughCategorized[concreteTargetType] = [];
244 }
245 throughCategorized[concreteTargetType].push(element);
246 });
247 let updatedCount = 0;
248 for (const key of Object.keys(throughCategorized)) {
249 const targetRepository = await this.getTargetRepositoryDict[key]();
250 const targetConstraint = this.getTargetConstraintFromThroughModels(throughCategorized[key]);
251 updatedCount +=
252 (_c = (_b = (await targetRepository.updateAll((0, __1.constrainDataObject)(isMultipleTypes
253 ? dataObject[key]
254 : dataObject, targetConstraint), (0, __1.constrainWhere)(where, targetConstraint), options))) === null || _b === void 0 ? void 0 : _b.count) !== null && _c !== void 0 ? _c : 0;
255 }
256 return { count: updatedCount };
257 }
258 async link(targetId, options) {
259 var _a;
260 const throughRepository = await this.getThroughRepository();
261 const sourceConstraint = this.getThroughConstraintFromSource();
262 const targetConstraint = this.getThroughConstraintFromTarget([targetId]);
263 const constraints = { ...targetConstraint, ...sourceConstraint };
264 await throughRepository.create((0, __1.constrainDataObject)((_a = options === null || options === void 0 ? void 0 : options.throughData) !== null && _a !== void 0 ? _a : {}, constraints), options === null || options === void 0 ? void 0 : options.throughOptions);
265 }
266 async unlink(targetId, options) {
267 const throughRepository = await this.getThroughRepository();
268 const sourceConstraint = this.getThroughConstraintFromSource();
269 const targetConstraint = this.getThroughConstraintFromTarget([targetId]);
270 const constraints = { ...targetConstraint, ...sourceConstraint };
271 await throughRepository.deleteAll((0, __1.constrainDataObject)({}, constraints), options === null || options === void 0 ? void 0 : options.throughOptions);
272 }
273 async unlinkAll(options) {
274 const throughRepository = await this.getThroughRepository();
275 const sourceConstraint = this.getThroughConstraintFromSource();
276 const throughInstances = await throughRepository.find((0, __1.constrainFilter)(undefined, sourceConstraint), options === null || options === void 0 ? void 0 : options.throughOptions);
277 const targetFkValues = this.getTargetKeys(throughInstances);
278 const targetConstraint = this.getThroughConstraintFromTarget(targetFkValues);
279 const constraints = { ...targetConstraint, ...sourceConstraint };
280 await throughRepository.deleteAll((0, __1.constrainDataObject)({}, constraints), options === null || options === void 0 ? void 0 : options.throughOptions);
281 }
282}
283exports.DefaultHasManyThroughRepository = DefaultHasManyThroughRepository;
284//# sourceMappingURL=has-many-through.repository.js.map
\No newline at end of file