@loopback/repository 2.5.1 → 2.9.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 (81) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/decorators/metadata.d.ts +1 -1
  3. package/dist/decorators/metadata.js +6 -6
  4. package/dist/decorators/metadata.js.map +1 -1
  5. package/dist/decorators/model.decorator.d.ts +1 -1
  6. package/dist/decorators/model.decorator.js +10 -10
  7. package/dist/decorators/model.decorator.js.map +1 -1
  8. package/dist/decorators/repository.decorator.js +4 -4
  9. package/dist/decorators/repository.decorator.js.map +1 -1
  10. package/dist/define-model-class.d.ts +2 -2
  11. package/dist/mixins/repository.mixin.d.ts +82 -43
  12. package/dist/mixins/repository.mixin.js +52 -15
  13. package/dist/mixins/repository.mixin.js.map +1 -1
  14. package/dist/model.js +3 -2
  15. package/dist/model.js.map +1 -1
  16. package/dist/query.d.ts +30 -0
  17. package/dist/query.js +50 -0
  18. package/dist/query.js.map +1 -1
  19. package/dist/relations/belongs-to/belongs-to.decorator.js +2 -2
  20. package/dist/relations/belongs-to/belongs-to.decorator.js.map +1 -1
  21. package/dist/relations/belongs-to/belongs-to.repository.d.ts +1 -1
  22. package/dist/relations/has-many/has-many-through-repository.factory.d.ts +11 -0
  23. package/dist/relations/has-many/has-many-through-repository.factory.js +28 -0
  24. package/dist/relations/has-many/has-many-through-repository.factory.js.map +1 -0
  25. package/dist/relations/has-many/has-many-through.helpers.d.ts +87 -14
  26. package/dist/relations/has-many/has-many-through.helpers.js +114 -20
  27. package/dist/relations/has-many/has-many-through.helpers.js.map +1 -1
  28. package/dist/relations/has-many/has-many-through.repository.d.ts +38 -2
  29. package/dist/relations/has-many/has-many-through.repository.js +71 -0
  30. package/dist/relations/has-many/has-many-through.repository.js.map +1 -1
  31. package/dist/relations/has-many/has-many.helpers.js +3 -2
  32. package/dist/relations/has-many/has-many.helpers.js.map +1 -1
  33. package/dist/relations/has-many/has-many.repository.d.ts +1 -1
  34. package/dist/relations/has-many/index.d.ts +4 -2
  35. package/dist/relations/has-many/index.js +4 -2
  36. package/dist/relations/has-many/index.js.map +1 -1
  37. package/dist/relations/has-one/has-one.helpers.js +2 -1
  38. package/dist/relations/has-one/has-one.helpers.js.map +1 -1
  39. package/dist/relations/has-one/has-one.repository.d.ts +1 -1
  40. package/dist/relations/relation.decorator.js +7 -7
  41. package/dist/relations/relation.decorator.js.map +1 -1
  42. package/dist/relations/relation.types.d.ts +1 -1
  43. package/dist/relations/relation.types.js +2 -2
  44. package/dist/relations/relation.types.js.map +1 -1
  45. package/dist/repositories/constraint-utils.d.ts +10 -0
  46. package/dist/repositories/constraint-utils.js +16 -1
  47. package/dist/repositories/constraint-utils.js.map +1 -1
  48. package/dist/repositories/legacy-juggler-bridge.d.ts +33 -2
  49. package/dist/repositories/legacy-juggler-bridge.js +34 -0
  50. package/dist/repositories/legacy-juggler-bridge.js.map +1 -1
  51. package/dist/type-resolver.js +2 -1
  52. package/dist/type-resolver.js.map +1 -1
  53. package/dist/types/index.js +1 -1
  54. package/dist/types/index.js.map +1 -1
  55. package/dist/types/null.js +1 -1
  56. package/dist/types/null.js.map +1 -1
  57. package/package.json +14 -12
  58. package/src/decorators/metadata.ts +1 -1
  59. package/src/decorators/model.decorator.ts +1 -1
  60. package/src/decorators/repository.decorator.ts +1 -1
  61. package/src/define-model-class.ts +2 -2
  62. package/src/mixins/repository.mixin.ts +70 -41
  63. package/src/model.ts +2 -2
  64. package/src/query.ts +55 -0
  65. package/src/relations/belongs-to/belongs-to.decorator.ts +1 -1
  66. package/src/relations/belongs-to/belongs-to.repository.ts +1 -1
  67. package/src/relations/has-many/has-many-through-repository.factory.ts +100 -0
  68. package/src/relations/has-many/has-many-through.helpers.ts +138 -21
  69. package/src/relations/has-many/has-many-through.repository.ts +174 -2
  70. package/src/relations/has-many/has-many.helpers.ts +2 -3
  71. package/src/relations/has-many/has-many.repository.ts +1 -1
  72. package/src/relations/has-many/index.ts +4 -2
  73. package/src/relations/has-one/has-one.helpers.ts +1 -2
  74. package/src/relations/has-one/has-one.repository.ts +1 -1
  75. package/src/relations/relation.decorator.ts +2 -2
  76. package/src/relations/relation.types.ts +1 -1
  77. package/src/repositories/constraint-utils.ts +17 -0
  78. package/src/repositories/legacy-juggler-bridge.ts +59 -1
  79. package/src/type-resolver.ts +2 -1
  80. package/src/types/index.ts +1 -1
  81. package/src/types/null.ts +1 -1
@@ -3,7 +3,20 @@
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 {Count, DataObject, Entity, Filter, Options, Where} from '../..';
6
+ import {
7
+ constrainDataObject,
8
+ constrainFilter,
9
+ constrainWhere,
10
+ constrainWhereOr,
11
+ Count,
12
+ DataObject,
13
+ Entity,
14
+ EntityCrudRepository,
15
+ Filter,
16
+ Getter,
17
+ Options,
18
+ Where,
19
+ } from '../..';
7
20
 
8
21
  /**
9
22
  * CRUD operations for a target repository of a HasManyThrough relation
@@ -83,7 +96,7 @@ export interface HasManyThroughRepository<
83
96
  throughData?: DataObject<Through>;
84
97
  throughOptions?: Options;
85
98
  },
86
- ): Promise<Target>;
99
+ ): Promise<void>;
87
100
 
88
101
  /**
89
102
  * Removes an association to an existing target model instance
@@ -98,3 +111,162 @@ export interface HasManyThroughRepository<
98
111
  },
99
112
  ): Promise<void>;
100
113
  }
114
+
115
+ /**
116
+ * a class for CRUD operations for hasManyThrough relation.
117
+ *
118
+ * Warning: The hasManyThrough interface is experimental and is subject to change.
119
+ * If backwards-incompatible changes are made, a new major version may not be
120
+ * released.
121
+ */
122
+ export class DefaultHasManyThroughRepository<
123
+ TargetEntity extends Entity,
124
+ TargetID,
125
+ TargetRepository extends EntityCrudRepository<TargetEntity, TargetID>,
126
+ ThroughEntity extends Entity,
127
+ ThroughID,
128
+ ThroughRepository extends EntityCrudRepository<ThroughEntity, ThroughID>
129
+ > implements HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity> {
130
+ constructor(
131
+ public getTargetRepository: Getter<TargetRepository>,
132
+ public getThroughRepository: Getter<ThroughRepository>,
133
+ public getTargetConstraintFromThroughModels: (
134
+ throughInstances: ThroughEntity[],
135
+ ) => DataObject<TargetEntity>,
136
+ public getTargetKeys: (throughInstances: ThroughEntity[]) => TargetID[],
137
+ public getThroughConstraintFromSource: () => DataObject<ThroughEntity>,
138
+ public getThroughConstraintFromTarget: (
139
+ targetID: TargetID[],
140
+ ) => DataObject<ThroughEntity>,
141
+ ) {}
142
+
143
+ async create(
144
+ targetModelData: DataObject<TargetEntity>,
145
+ options?: Options & {
146
+ throughData?: DataObject<ThroughEntity>;
147
+ throughOptions?: Options;
148
+ },
149
+ ): Promise<TargetEntity> {
150
+ const targetRepository = await this.getTargetRepository();
151
+ const targetInstance = await targetRepository.create(
152
+ targetModelData,
153
+ options,
154
+ );
155
+ await this.link(targetInstance.getId(), options);
156
+ return targetInstance;
157
+ }
158
+
159
+ async find(
160
+ filter?: Filter<TargetEntity>,
161
+ options?: Options & {
162
+ throughOptions?: Options;
163
+ },
164
+ ): Promise<TargetEntity[]> {
165
+ const targetRepository = await this.getTargetRepository();
166
+ const throughRepository = await this.getThroughRepository();
167
+ const sourceConstraint = this.getThroughConstraintFromSource();
168
+ const throughInstances = await throughRepository.find(
169
+ constrainFilter(undefined, sourceConstraint),
170
+ options?.throughOptions,
171
+ );
172
+ const targetConstraint = this.getTargetConstraintFromThroughModels(
173
+ throughInstances,
174
+ );
175
+ return targetRepository.find(
176
+ constrainFilter(filter, targetConstraint),
177
+ options,
178
+ );
179
+ }
180
+
181
+ async delete(
182
+ where?: Where<TargetEntity>,
183
+ options?: Options & {
184
+ throughOptions?: Options;
185
+ },
186
+ ): Promise<Count> {
187
+ const targetRepository = await this.getTargetRepository();
188
+ const throughRepository = await this.getThroughRepository();
189
+ const sourceConstraint = this.getThroughConstraintFromSource();
190
+ const throughInstances = await throughRepository.find(
191
+ constrainFilter(undefined, sourceConstraint),
192
+ options?.throughOptions,
193
+ );
194
+ const targetFkValues = this.getTargetKeys(throughInstances);
195
+ // delete through instances that have the targets that are going to be deleted
196
+ const throughFkConstraint = this.getThroughConstraintFromTarget(
197
+ targetFkValues,
198
+ );
199
+ await throughRepository.deleteAll(
200
+ constrainWhereOr({}, [sourceConstraint, throughFkConstraint]),
201
+ );
202
+
203
+ // delete target(s)
204
+ const targetConstraint = this.getTargetConstraintFromThroughModels(
205
+ throughInstances,
206
+ );
207
+ return targetRepository.deleteAll(
208
+ constrainWhere(where, targetConstraint as Where<TargetEntity>),
209
+ options,
210
+ );
211
+ }
212
+ // only allows patch target instances for now
213
+ async patch(
214
+ dataObject: DataObject<TargetEntity>,
215
+ where?: Where<TargetEntity>,
216
+ options?: Options & {
217
+ throughOptions?: Options;
218
+ },
219
+ ): Promise<Count> {
220
+ const targetRepository = await this.getTargetRepository();
221
+ const throughRepository = await this.getThroughRepository();
222
+ const sourceConstraint = this.getThroughConstraintFromSource();
223
+ const throughInstances = await throughRepository.find(
224
+ constrainFilter(undefined, sourceConstraint),
225
+ options?.throughOptions,
226
+ );
227
+ const targetConstraint = this.getTargetConstraintFromThroughModels(
228
+ throughInstances,
229
+ );
230
+ return targetRepository.updateAll(
231
+ constrainDataObject(dataObject, targetConstraint),
232
+ constrainWhere(where, targetConstraint as Where<TargetEntity>),
233
+ options,
234
+ );
235
+ }
236
+
237
+ async link(
238
+ targetId: TargetID,
239
+ options?: Options & {
240
+ throughData?: DataObject<ThroughEntity>;
241
+ throughOptions?: Options;
242
+ },
243
+ ): Promise<void> {
244
+ const throughRepository = await this.getThroughRepository();
245
+ const sourceConstraint = this.getThroughConstraintFromSource();
246
+ const targetConstraint = this.getThroughConstraintFromTarget([targetId]);
247
+ const constraints = {...targetConstraint, ...sourceConstraint};
248
+ await throughRepository.create(
249
+ constrainDataObject(
250
+ options?.throughData ?? {},
251
+ constraints as DataObject<ThroughEntity>,
252
+ ),
253
+ options?.throughOptions,
254
+ );
255
+ }
256
+
257
+ async unlink(
258
+ targetId: TargetID,
259
+ options?: Options & {
260
+ throughOptions?: Options;
261
+ },
262
+ ): Promise<void> {
263
+ const throughRepository = await this.getThroughRepository();
264
+ const sourceConstraint = this.getThroughConstraintFromSource();
265
+ const targetConstraint = this.getThroughConstraintFromTarget([targetId]);
266
+ const constraints = {...targetConstraint, ...sourceConstraint};
267
+ await throughRepository.deleteAll(
268
+ constrainDataObject({}, constraints as DataObject<ThroughEntity>),
269
+ options?.throughOptions,
270
+ );
271
+ }
272
+ }
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2019. All Rights Reserved.
1
+ // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -34,8 +34,7 @@ export function resolveHasManyMetadata(
34
34
  relationMeta = resolveHasManyMetaHelper(relationMeta);
35
35
 
36
36
  const targetModel = relationMeta.target();
37
- const targetModelProperties =
38
- targetModel.definition && targetModel.definition.properties;
37
+ const targetModelProperties = targetModel.definition?.properties;
39
38
 
40
39
  const sourceModel = relationMeta.source;
41
40
 
@@ -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 {Getter} from '@loopback/context';
6
+ import {Getter} from '@loopback/core';
7
7
  import {Count, DataObject, Options} from '../../common-types';
8
8
  import {Entity} from '../../model';
9
9
  import {Filter, Where} from '../../query';
@@ -3,7 +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
- export * from './has-many.decorator';
7
- export * from './has-many.repository';
8
6
  export * from './has-many-repository.factory';
7
+ export * from './has-many-through-repository.factory';
8
+ export * from './has-many-through.repository';
9
+ export * from './has-many.decorator';
9
10
  export * from './has-many.inclusion-resolver';
11
+ export * from './has-many.repository';
@@ -41,8 +41,7 @@ export function resolveHasOneMetadata(
41
41
  }
42
42
 
43
43
  const targetModel = relationMeta.target();
44
- const targetModelProperties =
45
- targetModel.definition && targetModel.definition.properties;
44
+ const targetModelProperties = targetModel.definition?.properties;
46
45
 
47
46
  const sourceModel = relationMeta.source;
48
47
  if (!sourceModel || !sourceModel.modelName) {
@@ -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 {Getter} from '@loopback/context';
6
+ import {Getter} from '@loopback/core';
7
7
  import {Count, DataObject, Options} from '../../common-types';
8
8
  import {EntityNotFoundError} from '../../errors';
9
9
  import {Entity} from '../../model';
@@ -1,9 +1,9 @@
1
- // Copyright IBM Corp. 2018,2019. All Rights Reserved.
1
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
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 {PropertyDecoratorFactory} from '@loopback/context';
6
+ import {PropertyDecoratorFactory} from '@loopback/core';
7
7
  import {buildModelDefinition} from '../decorators';
8
8
  import {Model, RelationDefinitionMap} from '../model';
9
9
  import {RelationType} from './relation.types';
@@ -155,7 +155,7 @@ export type RelationMetadata =
155
155
  | RelationDefinitionBase;
156
156
 
157
157
  // Re-export Getter so that users don't have to import from @loopback/context
158
- export {Getter} from '@loopback/context';
158
+ export {Getter} from '@loopback/core';
159
159
 
160
160
  /**
161
161
  * @returns An array of resolved values, the items must be ordered in the same
@@ -41,6 +41,23 @@ export function constrainWhere<T extends object>(
41
41
  const builder = new WhereBuilder<T>(where);
42
42
  return builder.impose(constraint).build();
43
43
  }
44
+ /**
45
+ * A utility function which takes a where filter and enforces constraint(s)
46
+ * on it with OR clause
47
+ * @param originalWhere - the where filter to apply the constrain(s) to
48
+ * @param constraint - the constraint which is to be applied on the filter with
49
+ * or clause
50
+ * @returns Filter the modified filter with the constraint, otherwise
51
+ * the original filter
52
+ */
53
+ export function constrainWhereOr<T extends object>(
54
+ originalWhere: Where<T> | undefined,
55
+ constraint: Where<T>[],
56
+ ): Where<T> {
57
+ const where = cloneDeep(originalWhere);
58
+ const builder = new WhereBuilder<T>(where);
59
+ return builder.or(constraint).build();
60
+ }
44
61
  /**
45
62
  * A utility function which takes a model instance data and enforces constraint(s)
46
63
  * on it
@@ -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 {Getter} from '@loopback/context';
6
+ import {Getter} from '@loopback/core';
7
7
  import assert from 'assert';
8
8
  import legacy from 'loopback-datasource-juggler';
9
9
  import {
@@ -29,9 +29,11 @@ import {
29
29
  BelongsToDefinition,
30
30
  createBelongsToAccessor,
31
31
  createHasManyRepositoryFactory,
32
+ createHasManyThroughRepositoryFactory,
32
33
  createHasOneRepositoryFactory,
33
34
  HasManyDefinition,
34
35
  HasManyRepositoryFactory,
36
+ HasManyThroughRepositoryFactory,
35
37
  HasOneDefinition,
36
38
  HasOneRepositoryFactory,
37
39
  includeRelatedModels,
@@ -283,6 +285,62 @@ export class DefaultCrudRepository<
283
285
  );
284
286
  }
285
287
 
288
+ /**
289
+ * Function to create a constrained hasManyThrough relation repository factory
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * class CustomerRepository extends DefaultCrudRepository<
294
+ * Customer,
295
+ * typeof Customer.prototype.id,
296
+ * CustomerRelations
297
+ * > {
298
+ * public readonly cartItems: HasManyRepositoryFactory<CartItem, typeof Customer.prototype.id>;
299
+ *
300
+ * constructor(
301
+ * protected db: juggler.DataSource,
302
+ * cartItemRepository: EntityCrudRepository<CartItem, typeof, CartItem.prototype.id>,
303
+ * throughRepository: EntityCrudRepository<Through, typeof Through.prototype.id>,
304
+ * ) {
305
+ * super(Customer, db);
306
+ * this.cartItems = this.createHasManyThroughRepositoryFactoryFor(
307
+ * 'cartItems',
308
+ * cartItemRepository,
309
+ * );
310
+ * }
311
+ * }
312
+ * ```
313
+ *
314
+ * @param relationName - Name of the relation defined on the source model
315
+ * @param targetRepo - Target repository instance
316
+ * @param throughRepo - Through repository instance
317
+ */
318
+ protected createHasManyThroughRepositoryFactoryFor<
319
+ Target extends Entity,
320
+ TargetID,
321
+ Through extends Entity,
322
+ ThroughID,
323
+ ForeignKeyType
324
+ >(
325
+ relationName: string,
326
+ targetRepoGetter: Getter<EntityCrudRepository<Target, TargetID>>,
327
+ throughRepoGetter: Getter<EntityCrudRepository<Through, ThroughID>>,
328
+ ): HasManyThroughRepositoryFactory<
329
+ Target,
330
+ TargetID,
331
+ Through,
332
+ ForeignKeyType
333
+ > {
334
+ const meta = this.entityClass.definition.relations[relationName];
335
+ return createHasManyThroughRepositoryFactory<
336
+ Target,
337
+ TargetID,
338
+ Through,
339
+ ThroughID,
340
+ ForeignKeyType
341
+ >(meta as HasManyDefinition, targetRepoGetter, throughRepoGetter);
342
+ }
343
+
286
344
  /**
287
345
  * @deprecated
288
346
  * Function to create a belongs to accessor
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2018,2019. All Rights Reserved.
1
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -54,6 +54,7 @@ export function isTypeResolver<T extends object>(
54
54
  /**
55
55
  * A boxed type for `null`
56
56
  */
57
+ // eslint-disable-next-line @typescript-eslint/naming-convention
57
58
  export function Null() {
58
59
  return null;
59
60
  }
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2017. All Rights Reserved.
1
+ // Copyright IBM Corp. 2017,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
package/src/types/null.ts CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2017,2019. All Rights Reserved.
1
+ // Copyright IBM Corp. 2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT