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