@loopback/repository 1.15.3 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/common-types.d.ts +11 -2
  3. package/dist/common-types.js +1 -0
  4. package/dist/common-types.js.map +1 -1
  5. package/dist/decorators/model.decorator.js +7 -6
  6. package/dist/decorators/model.decorator.js.map +1 -1
  7. package/dist/decorators/repository.decorator.js +5 -2
  8. package/dist/decorators/repository.decorator.js.map +1 -1
  9. package/dist/define-model-class.d.ts +55 -0
  10. package/dist/define-model-class.js +60 -0
  11. package/dist/define-model-class.js.map +1 -0
  12. package/dist/errors/invalid-relation.error.js +2 -1
  13. package/dist/errors/invalid-relation.error.js.map +1 -1
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +1 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/mixins/repository.mixin.js +11 -9
  18. package/dist/mixins/repository.mixin.js.map +1 -1
  19. package/dist/model.d.ts +1 -1
  20. package/dist/model.js +2 -2
  21. package/dist/model.js.map +1 -1
  22. package/dist/query.d.ts +1 -1
  23. package/dist/query.js +8 -5
  24. package/dist/query.js.map +1 -1
  25. package/dist/relations/belongs-to/belongs-to-accessor.js +12 -3
  26. package/dist/relations/belongs-to/belongs-to-accessor.js.map +1 -1
  27. package/dist/relations/belongs-to/belongs-to.helpers.js +5 -2
  28. package/dist/relations/belongs-to/belongs-to.helpers.js.map +1 -1
  29. package/dist/relations/has-many/has-many-repository.factory.js +5 -2
  30. package/dist/relations/has-many/has-many-repository.factory.js.map +1 -1
  31. package/dist/relations/has-many/has-many.helpers.js +18 -4
  32. package/dist/relations/has-many/has-many.helpers.js.map +1 -1
  33. package/dist/relations/has-many/has-many.inclusion-resolver.js +5 -2
  34. package/dist/relations/has-many/has-many.inclusion-resolver.js.map +1 -1
  35. package/dist/relations/has-one/has-one-repository.factory.js +5 -2
  36. package/dist/relations/has-one/has-one-repository.factory.js.map +1 -1
  37. package/dist/relations/has-one/has-one.helpers.js +14 -3
  38. package/dist/relations/has-one/has-one.helpers.js.map +1 -1
  39. package/dist/relations/has-one/has-one.inclusion-resolver.js.map +1 -1
  40. package/dist/relations/relation.decorator.js +2 -1
  41. package/dist/relations/relation.decorator.js.map +1 -1
  42. package/dist/relations/relation.helpers.d.ts +1 -1
  43. package/dist/relations/relation.helpers.js +18 -13
  44. package/dist/relations/relation.helpers.js.map +1 -1
  45. package/dist/relations/relation.types.d.ts +52 -5
  46. package/dist/relations/relation.types.js.map +1 -1
  47. package/dist/repositories/kv.repository.bridge.d.ts +3 -3
  48. package/dist/repositories/kv.repository.bridge.js +1 -1
  49. package/dist/repositories/kv.repository.bridge.js.map +1 -1
  50. package/dist/repositories/legacy-juggler-bridge.d.ts +20 -1
  51. package/dist/repositories/legacy-juggler-bridge.js +75 -20
  52. package/dist/repositories/legacy-juggler-bridge.js.map +1 -1
  53. package/dist/types/array.js +5 -2
  54. package/dist/types/array.js.map +1 -1
  55. package/dist/types/buffer.d.ts +1 -1
  56. package/dist/types/buffer.js +8 -4
  57. package/dist/types/buffer.js.map +1 -1
  58. package/dist/types/date.js +5 -2
  59. package/dist/types/date.js.map +1 -1
  60. package/dist/types/number.js +5 -2
  61. package/dist/types/number.js.map +1 -1
  62. package/dist/types/object.d.ts +1 -1
  63. package/dist/types/object.js +5 -2
  64. package/dist/types/object.js.map +1 -1
  65. package/dist/types/union.js +5 -2
  66. package/dist/types/union.js.map +1 -1
  67. package/package.json +11 -11
  68. package/src/common-types.ts +15 -5
  69. package/src/decorators/model.decorator.ts +5 -5
  70. package/src/decorators/repository.decorator.ts +1 -1
  71. package/src/define-model-class.ts +88 -0
  72. package/src/errors/invalid-relation.error.ts +1 -1
  73. package/src/index.ts +1 -0
  74. package/src/mixins/repository.mixin.ts +7 -9
  75. package/src/model.ts +2 -2
  76. package/src/query.ts +14 -4
  77. package/src/relations/belongs-to/belongs-to-accessor.ts +8 -2
  78. package/src/relations/belongs-to/belongs-to.helpers.ts +1 -1
  79. package/src/relations/has-many/has-many-repository.factory.ts +1 -1
  80. package/src/relations/has-many/has-many.helpers.ts +15 -4
  81. package/src/relations/has-many/has-many.inclusion-resolver.ts +6 -3
  82. package/src/relations/has-one/has-one-repository.factory.ts +1 -1
  83. package/src/relations/has-one/has-one.helpers.ts +11 -2
  84. package/src/relations/has-one/has-one.inclusion-resolver.ts +1 -1
  85. package/src/relations/relation.decorator.ts +1 -1
  86. package/src/relations/relation.helpers.ts +17 -13
  87. package/src/relations/relation.types.ts +58 -4
  88. package/src/repositories/kv.repository.bridge.ts +5 -8
  89. package/src/repositories/legacy-juggler-bridge.ts +75 -13
  90. package/src/types/array.ts +1 -1
  91. package/src/types/buffer.ts +4 -4
  92. package/src/types/date.ts +1 -1
  93. package/src/types/number.ts +1 -1
  94. package/src/types/object.ts +2 -2
  95. package/src/types/union.ts +1 -1
@@ -4,8 +4,8 @@
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
6
  import {Getter} from '@loopback/context';
7
- import * as assert from 'assert';
8
- import * as legacy from 'loopback-datasource-juggler';
7
+ import assert from 'assert';
8
+ import legacy from 'loopback-datasource-juggler';
9
9
  import {
10
10
  AnyObject,
11
11
  Command,
@@ -339,14 +339,18 @@ export class DefaultCrudRepository<
339
339
  }
340
340
 
341
341
  async create(entity: DataObject<T>, options?: Options): Promise<T> {
342
- const model = await ensurePromise(this.modelClass.create(entity, options));
342
+ // perform persist hook
343
+ const data = await this.entityToData(entity, options);
344
+ const model = await ensurePromise(this.modelClass.create(data, options));
343
345
  return this.toEntity(model);
344
346
  }
345
347
 
346
348
  async createAll(entities: DataObject<T>[], options?: Options): Promise<T[]> {
347
- const models = await ensurePromise(
348
- this.modelClass.create(entities, options),
349
+ // perform persist hook
350
+ const data = await Promise.all(
351
+ entities.map(e => this.entityToData(e, options)),
349
352
  );
353
+ const models = await ensurePromise(this.modelClass.create(data, options));
350
354
  return this.toEntities(models);
351
355
  }
352
356
 
@@ -364,7 +368,7 @@ export class DefaultCrudRepository<
364
368
  filter?: Filter<T>,
365
369
  options?: Options,
366
370
  ): Promise<(T & Relations)[]> {
367
- const include = filter && filter.include;
371
+ const include = filter?.include;
368
372
  const models = await ensurePromise(
369
373
  this.modelClass.find(this.normalizeFilter(filter), options),
370
374
  );
@@ -381,7 +385,7 @@ export class DefaultCrudRepository<
381
385
  );
382
386
  if (!model) return null;
383
387
  const entity = this.toEntity(model);
384
- const include = filter && filter.include;
388
+ const include = filter?.include;
385
389
  const resolved = await this.includeRelatedModels(
386
390
  [entity],
387
391
  include,
@@ -395,7 +399,7 @@ export class DefaultCrudRepository<
395
399
  filter?: Filter<T>,
396
400
  options?: Options,
397
401
  ): Promise<T & Relations> {
398
- const include = filter && filter.include;
402
+ const include = filter?.include;
399
403
  const model = await ensurePromise(
400
404
  this.modelClass.findById(id, this.normalizeFilter(filter), options),
401
405
  );
@@ -415,7 +419,9 @@ export class DefaultCrudRepository<
415
419
  return this.updateById(entity.getId(), entity, options);
416
420
  }
417
421
 
418
- delete(entity: T, options?: Options): Promise<void> {
422
+ async delete(entity: T, options?: Options): Promise<void> {
423
+ // perform persist hook
424
+ await this.entityToData(entity, options);
419
425
  return this.deleteById(entity.getId(), options);
420
426
  }
421
427
 
@@ -424,9 +430,10 @@ export class DefaultCrudRepository<
424
430
  where?: Where<T>,
425
431
  options?: Options,
426
432
  ): Promise<Count> {
427
- where = where || {};
433
+ where = where ?? {};
434
+ const persistedData = await this.entityToData(data, options);
428
435
  const result = await ensurePromise(
429
- this.modelClass.updateAll(where, data, options),
436
+ this.modelClass.updateAll(where, persistedData, options),
430
437
  );
431
438
  return {count: result.count};
432
439
  }
@@ -451,7 +458,8 @@ export class DefaultCrudRepository<
451
458
  options?: Options,
452
459
  ): Promise<void> {
453
460
  try {
454
- await ensurePromise(this.modelClass.replaceById(id, data, options));
461
+ const payload = await this.entityToData(data, options);
462
+ await ensurePromise(this.modelClass.replaceById(id, payload, options));
455
463
  } catch (err) {
456
464
  if (err.statusCode === 404) {
457
465
  throw new EntityNotFoundError(this.entityClass, id);
@@ -528,6 +536,60 @@ export class DefaultCrudRepository<
528
536
  return includeRelatedModels<T, Relations>(this, entities, include, options);
529
537
  }
530
538
 
539
+ /**
540
+ * This function works as a persist hook.
541
+ * It converts an entity from the CRUD operations' caller
542
+ * to a persistable data that can will be stored in the
543
+ * back-end database.
544
+ *
545
+ * User can extend `DefaultCrudRepository` then override this
546
+ * function to execute custom persist hook.
547
+ * @param entity The entity passed from CRUD operations' caller.
548
+ * @param options
549
+ */
550
+ protected async entityToData<R extends T>(
551
+ entity: R | DataObject<R>,
552
+ options = {},
553
+ ): Promise<legacy.ModelData<legacy.PersistedModel>> {
554
+ return this.ensurePersistable(entity, options);
555
+ }
556
+
557
+ /** Converts an entity object to a JSON object to check if it contains navigational property.
558
+ * Throws an error if `entity` contains navigational property.
559
+ *
560
+ * @param entity The entity passed from CRUD operations' caller.
561
+ * @param options
562
+ */
563
+ protected ensurePersistable<R extends T>(
564
+ entity: R | DataObject<R>,
565
+ options = {},
566
+ ): legacy.ModelData<legacy.PersistedModel> {
567
+ // FIXME(bajtos) Ideally, we should call toJSON() to convert R to data object
568
+ // Unfortunately that breaks replaceById for MongoDB connector, where we
569
+ // would call replaceId with id *argument* set to ObjectID value but
570
+ // id *property* set to string value.
571
+ /*
572
+ const data: AnyObject =
573
+ typeof entity.toJSON === 'function' ? entity.toJSON() : {...entity};
574
+ */
575
+
576
+ // proposal solution from agnes: delete the id property in the
577
+ // target data when runs replaceById
578
+
579
+ const data: AnyObject = new this.entityClass(entity);
580
+
581
+ const def = this.entityClass.definition;
582
+ for (const r in def.relations) {
583
+ const relName = def.relations[r].name;
584
+ if (relName in data) {
585
+ throw new Error(
586
+ `Navigational properties are not allowed in model data (model "${this.entityClass.modelName}" property "${relName}")`,
587
+ );
588
+ }
589
+ }
590
+ return data;
591
+ }
592
+
531
593
  /**
532
594
  * Removes juggler's "include" filter as it does not apply to LoopBack 4
533
595
  * relations.
@@ -555,7 +617,7 @@ export class DefaultTransactionalRepository<
555
617
  async beginTransaction(
556
618
  options?: IsolationLevel | Options,
557
619
  ): Promise<Transaction> {
558
- const dsOptions: juggler.IsolationLevel | Options = options || {};
620
+ const dsOptions: juggler.IsolationLevel | Options = options ?? {};
559
621
  // juggler.Transaction still has the Promise/Callback variants of the
560
622
  // Transaction methods
561
623
  // so we need it cast it back
@@ -3,8 +3,8 @@
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
+ import util from 'util';
6
7
  import {Type} from './type';
7
- import * as util from 'util';
8
8
 
9
9
  /* eslint-disable @typescript-eslint/no-explicit-any */
10
10
 
@@ -3,9 +3,9 @@
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
- import * as util from 'util';
7
- import {Type} from './type';
6
+ import util from 'util';
8
7
  import {Options} from '../common-types';
8
+ import {Type} from './type';
9
9
 
10
10
  /* eslint-disable @typescript-eslint/no-explicit-any */
11
11
 
@@ -35,7 +35,7 @@ export class BufferType implements Type<Buffer> {
35
35
  if (value == null) return value;
36
36
  if (Buffer.isBuffer(value)) return value as Buffer;
37
37
  if (typeof value === 'string') {
38
- options = options || {};
38
+ options = options ?? {};
39
39
  const encoding = options.encoding || 'utf-8';
40
40
  return Buffer.from(value, encoding);
41
41
  } else if (Array.isArray(value)) {
@@ -47,7 +47,7 @@ export class BufferType implements Type<Buffer> {
47
47
 
48
48
  serialize(value: Buffer | null | undefined, options?: Options) {
49
49
  if (value == null) return value;
50
- const encoding = (options && options.encoding) || 'base64';
50
+ const encoding = options?.encoding || 'base64';
51
51
  return value.toString(encoding);
52
52
  }
53
53
  }
package/src/types/date.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
- import * as util from 'util';
6
+ import util from 'util';
7
7
  import {Type} from './type';
8
8
 
9
9
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -3,7 +3,7 @@
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
- import * as util from 'util';
6
+ import util from 'util';
7
7
  import {Type} from './type';
8
8
 
9
9
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -3,8 +3,8 @@
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
- import * as util from 'util';
7
- import {Class, AnyObject} from '../common-types';
6
+ import util from 'util';
7
+ import {AnyObject, Class} from '../common-types';
8
8
  import {Type} from './type';
9
9
 
10
10
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -3,7 +3,7 @@
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
- import * as util from 'util';
6
+ import util from 'util';
7
7
  import {Type} from './type';
8
8
 
9
9
  /* eslint-disable @typescript-eslint/no-explicit-any */