1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | Object.defineProperty(exports, "__esModule", { value: true });
|
7 | exports.DefaultTransactionalRepository = exports.DefaultCrudRepository = exports.ensurePromise = exports.bindModel = exports.juggler = void 0;
|
8 | const tslib_1 = require("tslib");
|
9 | const assert_1 = tslib_1.__importDefault(require("assert"));
|
10 | const loopback_datasource_juggler_1 = tslib_1.__importDefault(require("loopback-datasource-juggler"));
|
11 | const errors_1 = require("../errors");
|
12 | const model_1 = require("../model");
|
13 | const relations_1 = require("../relations");
|
14 | const type_resolver_1 = require("../type-resolver");
|
15 | var juggler;
|
16 | (function (juggler) {
|
17 | juggler.DataSource = loopback_datasource_juggler_1.default.DataSource;
|
18 | juggler.ModelBase = loopback_datasource_juggler_1.default.ModelBase;
|
19 | juggler.PersistedModel = loopback_datasource_juggler_1.default.PersistedModel;
|
20 | juggler.KeyValueModel = loopback_datasource_juggler_1.default.KeyValueModel;
|
21 |
|
22 | juggler.IsolationLevel = loopback_datasource_juggler_1.default.IsolationLevel;
|
23 | })(juggler || (exports.juggler = juggler = {}));
|
24 | function isModelClass(propertyType) {
|
25 | return (!(0, type_resolver_1.isTypeResolver)(propertyType) &&
|
26 | typeof propertyType === 'function' &&
|
27 | typeof propertyType.definition === 'object' &&
|
28 | propertyType.toString().startsWith('class '));
|
29 | }
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | function bindModel(modelClass, ds) {
|
38 | const BoundModelClass = class extends modelClass {
|
39 | };
|
40 | BoundModelClass.attachTo(ds);
|
41 | return BoundModelClass;
|
42 | }
|
43 | exports.bindModel = bindModel;
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | function ensurePromise(p) {
|
49 | if (p && p instanceof Promise) {
|
50 | return p;
|
51 | }
|
52 | else {
|
53 | return Promise.reject(new Error('The value should be a Promise: ' + p));
|
54 | }
|
55 | }
|
56 | exports.ensurePromise = ensurePromise;
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | class DefaultCrudRepository {
|
62 | |
63 |
|
64 |
|
65 |
|
66 |
|
67 | constructor(
|
68 | // entityClass should have type "typeof T", but that's not supported by TSC
|
69 | entityClass, dataSource) {
|
70 | this.entityClass = entityClass;
|
71 | this.dataSource = dataSource;
|
72 | this.inclusionResolvers = new Map();
|
73 | const definition = entityClass.definition;
|
74 | (0, assert_1.default)(!!definition, `Entity ${entityClass.name} must have valid model definition.`);
|
75 | (0, assert_1.default)(definition.idProperties().length > 0, `Entity ${entityClass.name} must have at least one id/pk property.`);
|
76 | this.modelClass = this.ensurePersistedModel(entityClass);
|
77 | }
|
78 |
|
79 | ensurePersistedModel(entityClass) {
|
80 | const definition = entityClass.definition;
|
81 | (0, assert_1.default)(!!definition, `Entity ${entityClass.name} must have valid model definition.`);
|
82 | const dataSource = this.dataSource;
|
83 | const model = dataSource.getModel(definition.name);
|
84 | if (model) {
|
85 |
|
86 | return model;
|
87 | }
|
88 | return this.definePersistedModel(entityClass);
|
89 | }
|
90 | |
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | definePersistedModel(entityClass) {
|
97 | const dataSource = this.dataSource;
|
98 | const definition = entityClass.definition;
|
99 |
|
100 |
|
101 | dataSource.getModel(definition.name, true );
|
102 |
|
103 |
|
104 | const properties = {};
|
105 |
|
106 |
|
107 | Object.entries(definition.properties).forEach(([key, value]) => {
|
108 |
|
109 |
|
110 | if (value.type === 'array' || value.type === Array) {
|
111 | value = Object.assign({}, value, {
|
112 | type: [value.itemType && this.resolvePropertyType(value.itemType)],
|
113 | });
|
114 | delete value.itemType;
|
115 | }
|
116 | else {
|
117 | value = Object.assign({}, value, {
|
118 | type: this.resolvePropertyType(value.type),
|
119 | });
|
120 | }
|
121 | properties[key] = Object.assign({}, value);
|
122 | });
|
123 | const modelClass = dataSource.createModel(definition.name, properties, Object.assign(
|
124 |
|
125 | { strict: true },
|
126 |
|
127 | definition.settings,
|
128 |
|
129 | { strictDelete: false }));
|
130 | modelClass.attachTo(dataSource);
|
131 | return modelClass;
|
132 | }
|
133 | resolvePropertyType(type) {
|
134 | const resolved = (0, type_resolver_1.resolveType)(type);
|
135 | return isModelClass(resolved)
|
136 | ? this.ensurePersistedModel(resolved)
|
137 | : resolved;
|
138 | }
|
139 | |
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | _createHasManyRepositoryFactoryFor(relationName, targetRepositoryGetter) {
|
149 | return this.createHasManyRepositoryFactoryFor(relationName, targetRepositoryGetter);
|
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 | createHasManyRepositoryFactoryFor(relationName, targetRepositoryGetter) {
|
180 | const meta = this.entityClass.definition.relations[relationName];
|
181 | return (0, relations_1.createHasManyRepositoryFactory)(meta, targetRepositoryGetter);
|
182 | }
|
183 | |
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 | createHasManyThroughRepositoryFactoryFor(relationName, targetRepositoryGetter, throughRepositoryGetter) {
|
214 | const meta = this.entityClass.definition.relations[relationName];
|
215 | return (0, relations_1.createHasManyThroughRepositoryFactory)(meta, targetRepositoryGetter, throughRepositoryGetter);
|
216 | }
|
217 | |
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | _createBelongsToAccessorFor(relationName, targetRepositoryGetter) {
|
227 | return this.createBelongsToAccessorFor(relationName, targetRepositoryGetter);
|
228 | }
|
229 | |
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | createBelongsToAccessorFor(relationName, targetRepositoryGetter) {
|
236 | const meta = this.entityClass.definition.relations[relationName];
|
237 | return (0, relations_1.createBelongsToAccessor)(meta, targetRepositoryGetter, this);
|
238 | }
|
239 | |
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 | _createHasOneRepositoryFactoryFor(relationName, targetRepositoryGetter) {
|
247 | return this.createHasOneRepositoryFactoryFor(relationName, targetRepositoryGetter);
|
248 | }
|
249 | |
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 | createHasOneRepositoryFactoryFor(relationName, targetRepositoryGetter) {
|
256 | const meta = this.entityClass.definition.relations[relationName];
|
257 | return (0, relations_1.createHasOneRepositoryFactory)(meta, targetRepositoryGetter);
|
258 | }
|
259 | |
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 | _createReferencesManyAccessorFor(relationName, targetRepoGetter) {
|
269 | return this.createReferencesManyAccessorFor(relationName, targetRepoGetter);
|
270 | }
|
271 | |
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 | createReferencesManyAccessorFor(relationName, targetRepoGetter) {
|
278 | const meta = this.entityClass.definition.relations[relationName];
|
279 | return (0, relations_1.createReferencesManyAccessor)(meta, targetRepoGetter, this);
|
280 | }
|
281 | async create(entity, options) {
|
282 |
|
283 | const data = await this.entityToData(entity, options);
|
284 | const model = await ensurePromise(this.modelClass.create(data, options));
|
285 | return this.toEntity(model);
|
286 | }
|
287 | async createAll(entities, options) {
|
288 |
|
289 | const data = await Promise.all(entities.map(e => this.entityToData(e, options)));
|
290 | const models = await ensurePromise(this.modelClass.createAll(data, options));
|
291 | return this.toEntities(models);
|
292 | }
|
293 | async save(entity, options) {
|
294 | const id = this.entityClass.getIdOf(entity);
|
295 | if (id == null) {
|
296 | return this.create(entity, options);
|
297 | }
|
298 | else {
|
299 | await this.replaceById(id, entity, options);
|
300 | return new this.entityClass(entity.toObject());
|
301 | }
|
302 | }
|
303 | async find(filter, options) {
|
304 | const include = filter === null || filter === void 0 ? void 0 : filter.include;
|
305 | const models = await ensurePromise(this.modelClass.find(this.normalizeFilter(filter), options));
|
306 | const entities = this.toEntities(models);
|
307 | return this.includeRelatedModels(entities, include, options);
|
308 | }
|
309 | async findOne(filter, options) {
|
310 | const model = await ensurePromise(this.modelClass.findOne(this.normalizeFilter(filter), options));
|
311 | if (!model)
|
312 | return null;
|
313 | const entity = this.toEntity(model);
|
314 | const include = filter === null || filter === void 0 ? void 0 : filter.include;
|
315 | const resolved = await this.includeRelatedModels([entity], include, options);
|
316 | return resolved[0];
|
317 | }
|
318 | async findById(id, filter, options) {
|
319 | const include = filter === null || filter === void 0 ? void 0 : filter.include;
|
320 | const model = await ensurePromise(this.modelClass.findById(id, this.normalizeFilter(filter), options));
|
321 | if (!model) {
|
322 | throw new errors_1.EntityNotFoundError(this.entityClass, id);
|
323 | }
|
324 | const entity = this.toEntity(model);
|
325 | const resolved = await this.includeRelatedModels([entity], include, options);
|
326 | return resolved[0];
|
327 | }
|
328 | update(entity, options) {
|
329 | return this.updateById(entity.getId(), entity, options);
|
330 | }
|
331 | async delete(entity, options) {
|
332 |
|
333 | await this.entityToData(entity, options);
|
334 | return this.deleteById(entity.getId(), options);
|
335 | }
|
336 | async updateAll(data, where, options) {
|
337 | where = where !== null && where !== void 0 ? where : {};
|
338 | const persistedData = await this.entityToData(data, options);
|
339 | const result = await ensurePromise(this.modelClass.updateAll(where, persistedData, options));
|
340 | return { count: result.count };
|
341 | }
|
342 | async updateById(id, data, options) {
|
343 | if (!Object.keys(data).length) {
|
344 | throw new errors_1.InvalidBodyError(this.entityClass, id);
|
345 | }
|
346 | if (id === undefined) {
|
347 | throw new Error('Invalid Argument: id cannot be undefined');
|
348 | }
|
349 | const idProp = this.modelClass.definition.idName();
|
350 | const where = {};
|
351 | where[idProp] = id;
|
352 | const result = await this.updateAll(data, where, options);
|
353 | if (result.count === 0) {
|
354 | throw new errors_1.EntityNotFoundError(this.entityClass, id);
|
355 | }
|
356 | }
|
357 | async replaceById(id, data, options) {
|
358 | try {
|
359 | const payload = await this.entityToData(data, options);
|
360 | await ensurePromise(this.modelClass.replaceById(id, payload, options));
|
361 | }
|
362 | catch (err) {
|
363 | if (err.statusCode === 404) {
|
364 | throw new errors_1.EntityNotFoundError(this.entityClass, id);
|
365 | }
|
366 | throw err;
|
367 | }
|
368 | }
|
369 | async deleteAll(where, options) {
|
370 | const result = await ensurePromise(this.modelClass.deleteAll(where, options));
|
371 | return { count: result.count };
|
372 | }
|
373 | async deleteById(id, options) {
|
374 | const result = await ensurePromise(this.modelClass.deleteById(id, options));
|
375 | if (result.count === 0) {
|
376 | throw new errors_1.EntityNotFoundError(this.entityClass, id);
|
377 | }
|
378 | }
|
379 | async count(where, options) {
|
380 | const result = await ensurePromise(this.modelClass.count(where, options));
|
381 | return { count: result };
|
382 | }
|
383 | exists(id, options) {
|
384 | return ensurePromise(this.modelClass.exists(id, options));
|
385 | }
|
386 | async execute(...args) {
|
387 | return ensurePromise(this.dataSource.execute(...args));
|
388 | }
|
389 | toEntity(model) {
|
390 | return new this.entityClass(model.toObject());
|
391 | }
|
392 | toEntities(models) {
|
393 | return models.map(m => this.toEntity(m));
|
394 | }
|
395 | |
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 | registerInclusionResolver(relationName, resolver) {
|
402 | this.inclusionResolvers.set(relationName, resolver);
|
403 | }
|
404 | |
405 |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 | async includeRelatedModels(entities, include, options) {
|
413 | return (0, relations_1.includeRelatedModels)(this, entities, include, options);
|
414 | }
|
415 | |
416 |
|
417 |
|
418 |
|
419 |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 |
|
426 | async entityToData(entity, options = {}) {
|
427 | return this.ensurePersistable(entity, options);
|
428 | }
|
429 | |
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 | ensurePersistable(entity, options = {}) {
|
436 |
|
437 |
|
438 |
|
439 |
|
440 | |
441 |
|
442 |
|
443 |
|
444 | const data = new this.entityClass(entity);
|
445 | (0, model_1.rejectNavigationalPropertiesInData)(this.entityClass, data);
|
446 | return data;
|
447 | }
|
448 | |
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 | normalizeFilter(filter) {
|
455 | if (!filter)
|
456 | return undefined;
|
457 | return { ...filter, include: undefined };
|
458 | }
|
459 | }
|
460 | exports.DefaultCrudRepository = DefaultCrudRepository;
|
461 |
|
462 |
|
463 |
|
464 |
|
465 |
|
466 | class DefaultTransactionalRepository extends DefaultCrudRepository {
|
467 | async beginTransaction(options) {
|
468 | const dsOptions = options !== null && options !== void 0 ? options : {};
|
469 |
|
470 |
|
471 |
|
472 | return (await this.dataSource.beginTransaction(dsOptions));
|
473 | }
|
474 | }
|
475 | exports.DefaultTransactionalRepository = DefaultTransactionalRepository;
|
476 |
|
\ | No newline at end of file |