@loopback/repository 3.0.1 → 3.1.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.1.0](https://github.com/strongloop/loopback-next/compare/@loopback/repository@3.0.1...@loopback/repository@3.1.0) (2020-10-07)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * tidy up type inferences for OpenAPI SchemaObject ([013bb7e](https://github.com/strongloop/loopback-next/commit/013bb7e4c0f7499a7f77c152dea7caa14e19b7cc))
12
+
13
+
14
+ ### Features
15
+
16
+ * **repository:** implement hasManyThrough resolver ([8e7767d](https://github.com/strongloop/loopback-next/commit/8e7767df0a4679c8c70ad524e56aea9783def521))
17
+
18
+
19
+
20
+
21
+
6
22
  ## [3.0.1](https://github.com/strongloop/loopback-next/compare/@loopback/repository@3.0.0...@loopback/repository@3.0.1) (2020-09-17)
7
23
 
8
24
  **Note:** Version bump only for package @loopback/repository
@@ -72,15 +72,17 @@ export interface Count {
72
72
  }
73
73
  /**
74
74
  * JSON Schema describing the Count interface. It's the response type for
75
- * REST calls to APIs which return Count
75
+ * REST calls to APIs which return `count`. The type is compatible with
76
+ * `SchemaObject` from `@loopback/openapi-v3`, which is not an explicit
77
+ * dependency for `@loopback/repository`.
76
78
  */
77
79
  export declare const CountSchema: {
78
- type: string;
80
+ type: "object";
79
81
  title: string;
80
82
  'x-typescript-type': string;
81
83
  properties: {
82
84
  count: {
83
- type: string;
85
+ type: "number";
84
86
  };
85
87
  };
86
88
  };
@@ -7,12 +7,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.CountSchema = void 0;
8
8
  /**
9
9
  * JSON Schema describing the Count interface. It's the response type for
10
- * REST calls to APIs which return Count
10
+ * REST calls to APIs which return `count`. The type is compatible with
11
+ * `SchemaObject` from `@loopback/openapi-v3`, which is not an explicit
12
+ * dependency for `@loopback/repository`.
11
13
  */
12
- exports.CountSchema = {
14
+ exports.CountSchema /* :SchemaObject */ = {
13
15
  type: 'object',
14
16
  title: 'loopback.Count',
15
17
  'x-typescript-type': '@loopback/repository#Count',
16
- properties: { count: { type: 'number' } },
18
+ properties: {
19
+ count: {
20
+ type: 'number',
21
+ },
22
+ },
17
23
  };
18
24
  //# sourceMappingURL=common-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"common-types.js","sourceRoot":"","sources":["../src/common-types.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,oCAAoC;AACpC,+CAA+C;AAC/C,gEAAgE;;;AA6FhE;;;GAGG;AACU,QAAA,WAAW,GAAG;IACzB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,gBAAgB;IACvB,mBAAmB,EAAE,4BAA4B;IACjD,UAAU,EAAE,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAC;CACtC,CAAC"}
1
+ {"version":3,"file":"common-types.js","sourceRoot":"","sources":["../src/common-types.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,oCAAoC;AACpC,+CAA+C;AAC/C,gEAAgE;;;AA6FhE;;;;;GAKG;AACU,QAAA,WAAW,CAAC,mBAAmB,GAAG;IAC7C,IAAI,EAAE,QAAiB;IACvB,KAAK,EAAE,gBAAgB;IACvB,mBAAmB,EAAE,4BAA4B;IACjD,UAAU,EAAE;QACV,KAAK,EAAE;YACL,IAAI,EAAE,QAAiB;SACxB;KACF;CACF,CAAC"}
@@ -1,4 +1,4 @@
1
- import { Binding, BindingFromClassOptions } from '@loopback/core';
1
+ import { Binding, BindingFromClassOptions, BindingScope } from '@loopback/core';
2
2
  import { Application, Component, Constructor, MixinTarget } from '@loopback/core';
3
3
  import { Class } from '../common-types';
4
4
  import { SchemaMigrationOptions } from '../datasource';
@@ -164,6 +164,7 @@ export declare function RepositoryMixin<T extends MixinTarget<Application>>(supe
164
164
  interceptor: (interceptor: loopbackContext.Interceptor | Constructor<loopbackContext.Provider<loopbackContext.Interceptor>>, nameOrOptions?: string | loopbackContext.InterceptorBindingOptions | undefined) => Binding<loopbackContext.Interceptor>;
165
165
  readonly name: string;
166
166
  readonly subscriptionManager: loopbackContext.ContextSubscriptionManager;
167
+ scope: BindingScope;
167
168
  readonly parent: loopbackContext.Context | undefined;
168
169
  emitEvent: <T_6 extends loopbackContext.ContextEvent>(type: string, event: T_6) => void;
169
170
  emitError: (err: unknown) => void;
@@ -181,7 +182,10 @@ export declare function RepositoryMixin<T extends MixinTarget<Application>>(supe
181
182
  createView: <T_7 = unknown>(filter: loopbackContext.BindingFilter, comparator?: loopbackContext.BindingComparator | undefined) => loopbackContext.ContextView<T_7>;
182
183
  contains: (key: loopbackContext.BindingAddress<unknown>) => boolean;
183
184
  isBound: (key: loopbackContext.BindingAddress<unknown>) => boolean;
184
- getOwnerContext: (key: loopbackContext.BindingAddress<unknown>) => loopbackContext.Context | undefined;
185
+ getOwnerContext: (keyOrBinding: string | loopbackContext.BindingKey<unknown> | Readonly<Binding<unknown>>) => loopbackContext.Context | undefined;
186
+ getScopedContext: (scope: BindingScope.APPLICATION | BindingScope.SERVER | BindingScope.REQUEST) => loopbackContext.Context | undefined;
187
+ getResolutionContext: (binding: Readonly<Binding<unknown>>) => loopbackContext.Context | undefined;
188
+ isVisibleTo: (ctx: loopbackContext.Context) => boolean;
185
189
  find: <ValueType_1 = any>(pattern?: string | RegExp | loopbackContext.BindingFilter | undefined) => Readonly<Binding<ValueType_1>>[];
186
190
  findByTag: <ValueType_2 = any>(tagFilter: string | RegExp | Record<string, any>) => Readonly<Binding<ValueType_2>>[];
187
191
  get: {
@@ -1,4 +1,4 @@
1
- import { Entity, EntityCrudRepository, Getter, HasManyDefinition } from '../..';
1
+ import { Entity, EntityCrudRepository, Getter, HasManyDefinition, InclusionResolver } from '../..';
2
2
  import { HasManyThroughRepository } from './has-many-through.repository';
3
3
  /**
4
4
  * a factory to generate hasManyThrough repository class.
@@ -7,5 +7,11 @@ import { HasManyThroughRepository } from './has-many-through.repository';
7
7
  * If backwards-incompatible changes are made, a new major version may not be
8
8
  * released.
9
9
  */
10
- export declare type HasManyThroughRepositoryFactory<TargetEntity extends Entity, TargetID, ThroughEntity extends Entity, SourceID> = (fkValue: SourceID) => HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity>;
10
+ export declare type HasManyThroughRepositoryFactory<TargetEntity extends Entity, TargetID, ThroughEntity extends Entity, SourceID> = {
11
+ (fkValue: SourceID): HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity>;
12
+ /**
13
+ * Use `resolver` property to obtain an InclusionResolver for this relation.
14
+ */
15
+ inclusionResolver: InclusionResolver<Entity, TargetEntity>;
16
+ };
11
17
  export declare function createHasManyThroughRepositoryFactory<Target extends Entity, TargetID, Through extends Entity, ThroughID, SourceID>(relationMetadata: HasManyDefinition, targetRepositoryGetter: Getter<EntityCrudRepository<Target, TargetID>>, throughRepositoryGetter: Getter<EntityCrudRepository<Through, ThroughID>>): HasManyThroughRepositoryFactory<Target, TargetID, Through, SourceID>;
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
+ // Copyright IBM Corp. 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
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
7
  exports.createHasManyThroughRepositoryFactory = void 0;
4
8
  const has_many_through_helpers_1 = require("./has-many-through.helpers");
9
+ const has_many_through_inclusion_resolver_1 = require("./has-many-through.inclusion.resolver");
5
10
  const has_many_through_repository_1 = require("./has-many-through.repository");
6
11
  function createHasManyThroughRepositoryFactory(relationMetadata, targetRepositoryGetter, throughRepositoryGetter) {
7
12
  const meta = has_many_through_helpers_1.resolveHasManyThroughMetadata(relationMetadata);
@@ -25,6 +30,7 @@ function createHasManyThroughRepositoryFactory(relationMetadata, targetRepositor
25
30
  }
26
31
  return new has_many_through_repository_1.DefaultHasManyThroughRepository(targetRepositoryGetter, throughRepositoryGetter, getTargetConstraintFromThroughModels, getTargetKeys, getThroughConstraintFromSource, getTargetIds, getThroughConstraintFromTarget);
27
32
  };
33
+ result.inclusionResolver = has_many_through_inclusion_resolver_1.createHasManyThroughInclusionResolver(meta, throughRepositoryGetter, targetRepositoryGetter);
28
34
  return result;
29
35
  }
30
36
  exports.createHasManyThroughRepositoryFactory = createHasManyThroughRepositoryFactory;
@@ -1 +1 @@
1
- {"version":3,"file":"has-many-through-repository.factory.js","sourceRoot":"","sources":["../../../src/relations/has-many/has-many-through-repository.factory.ts"],"names":[],"mappings":";;;AAWA,yEAOoC;AACpC,+EAGuC;AAmBvC,SAAgB,qCAAqC,CAOnD,gBAAmC,EACnC,sBAAsE,EACtE,uBAAyE;IAEzE,MAAM,IAAI,GAAG,wDAA6B,CAAC,gBAAgB,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,UAAU,OAAiB;QACxC,SAAS,oCAAoC,CAC3C,gBAA2B;YAE3B,OAAO,4DAAiC,CACtC,IAAI,EACJ,gBAAgB,CACjB,CAAC;QACJ,CAAC;QACD,SAAS,aAAa,CAAC,gBAA2B;YAChD,OAAO,yDAA8B,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAChE,CAAC;QACD,SAAS,8BAA8B;YACrC,MAAM,UAAU,GAAwB,4DAAiC,CAGvE,IAAI,EAAE,OAAO,CAAC,CAAC;YACjB,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,SAAS,YAAY,CAAC,eAAyB;YAC7C,OAAO,uDAA4B,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC7D,CAAC;QACD,SAAS,8BAA8B,CACrC,QAAoB;YAEpB,MAAM,UAAU,GAAwB,4DAAiC,CAGvE,IAAI,EAAE,QAAQ,CAAC,CAAC;YAClB,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,OAAO,IAAI,6DAA+B,CAQxC,sBAAsB,EACtB,uBAAuB,EACvB,oCAAoC,EACpC,aAAa,EACb,8BAA8B,EAC9B,YAAY,EACZ,8BAA8B,CAC/B,CAAC;IACJ,CAAC,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AA9DD,sFA8DC"}
1
+ {"version":3,"file":"has-many-through-repository.factory.js","sourceRoot":"","sources":["../../../src/relations/has-many/has-many-through-repository.factory.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,oCAAoC;AACpC,+CAA+C;AAC/C,gEAAgE;;;AAUhE,yEAOoC;AACpC,+FAA4F;AAC5F,+EAGuC;AA4BvC,SAAgB,qCAAqC,CAOnD,gBAAmC,EACnC,sBAAsE,EACtE,uBAAyE;IAEzE,MAAM,IAAI,GAAG,wDAA6B,CAAC,gBAAgB,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,UAAU,OAAiB;QACxC,SAAS,oCAAoC,CAC3C,gBAA2B;YAE3B,OAAO,4DAAiC,CACtC,IAAI,EACJ,gBAAgB,CACjB,CAAC;QACJ,CAAC;QACD,SAAS,aAAa,CAAC,gBAA2B;YAChD,OAAO,yDAA8B,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAChE,CAAC;QACD,SAAS,8BAA8B;YACrC,MAAM,UAAU,GAAwB,4DAAiC,CAGvE,IAAI,EAAE,OAAO,CAAC,CAAC;YACjB,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,SAAS,YAAY,CAAC,eAAyB;YAC7C,OAAO,uDAA4B,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC7D,CAAC;QACD,SAAS,8BAA8B,CACrC,QAAoB;YAEpB,MAAM,UAAU,GAAwB,4DAAiC,CAGvE,IAAI,EAAE,QAAQ,CAAC,CAAC;YAClB,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,OAAO,IAAI,6DAA+B,CAQxC,sBAAsB,EACtB,uBAAuB,EACvB,oCAAoC,EACpC,aAAa,EACb,8BAA8B,EAC9B,YAAY,EACZ,8BAA8B,CAC/B,CAAC;IACJ,CAAC,CAAC;IACF,MAAM,CAAC,iBAAiB,GAAG,2EAAqC,CAC9D,IAAI,EACJ,uBAAuB,EACvB,sBAAsB,CACvB,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAnED,sFAmEC"}
@@ -0,0 +1,16 @@
1
+ import { Entity } from '../../model';
2
+ import { EntityCrudRepository } from '../../repositories/repository';
3
+ import { Getter, HasManyDefinition, InclusionResolver } from '../relation.types';
4
+ /**
5
+ * Creates InclusionResolver for HasManyThrough relation.
6
+ * Notice that this function only generates the inclusionResolver.
7
+ * It doesn't register it for the source repository.
8
+ *
9
+ *
10
+ * @param meta - metadata of the hasMany relation (including through)
11
+ * @param getThroughRepo - through repository getter i.e. where through
12
+ * instances are
13
+ * @param getTargetRepo - target repository getter i.e where target instances
14
+ * are
15
+ */
16
+ export declare function createHasManyThroughInclusionResolver<Through extends Entity, ThroughID, ThroughRelations extends object, Target extends Entity, TargetID, TargetRelations extends object>(meta: HasManyDefinition, getThroughRepo: Getter<EntityCrudRepository<Through, ThroughID, ThroughRelations>>, getTargetRepo: Getter<EntityCrudRepository<Target, TargetID, TargetRelations>>): InclusionResolver<Entity, Target>;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 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
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createHasManyThroughInclusionResolver = void 0;
8
+ const tslib_1 = require("tslib");
9
+ const debug_1 = tslib_1.__importDefault(require("debug"));
10
+ const relation_helpers_1 = require("../relation.helpers");
11
+ const has_many_helpers_1 = require("./has-many.helpers");
12
+ const debug = debug_1.default('loopback:repository:has-many-through-inclusion-resolver');
13
+ /**
14
+ * Creates InclusionResolver for HasManyThrough relation.
15
+ * Notice that this function only generates the inclusionResolver.
16
+ * It doesn't register it for the source repository.
17
+ *
18
+ *
19
+ * @param meta - metadata of the hasMany relation (including through)
20
+ * @param getThroughRepo - through repository getter i.e. where through
21
+ * instances are
22
+ * @param getTargetRepo - target repository getter i.e where target instances
23
+ * are
24
+ */
25
+ function createHasManyThroughInclusionResolver(meta, getThroughRepo, getTargetRepo) {
26
+ const relationMeta = has_many_helpers_1.resolveHasManyMetadata(meta);
27
+ return async function fetchHasManyThroughModels(entities, inclusion, options) {
28
+ if (!entities.length)
29
+ return [];
30
+ debug('Fetching target models for entities:', entities);
31
+ debug('Relation metadata:', relationMeta);
32
+ const sourceKey = relationMeta.keyFrom;
33
+ const sourceIds = entities.map(e => e[sourceKey]);
34
+ const targetKey = relationMeta.keyTo;
35
+ if (!relationMeta.through) {
36
+ throw new Error(`relationMeta.through must be defined on ${relationMeta}`);
37
+ }
38
+ const throughKeyTo = relationMeta.through.keyTo;
39
+ const throughKeyFrom = relationMeta.through.keyFrom;
40
+ debug('Parameters:', {
41
+ sourceKey,
42
+ sourceIds,
43
+ targetKey,
44
+ throughKeyTo,
45
+ throughKeyFrom,
46
+ });
47
+ debug('sourceId types', sourceIds.map(i => typeof i));
48
+ const throughRepo = await getThroughRepo();
49
+ const targetRepo = await getTargetRepo();
50
+ // find through models
51
+ const throughFound = await relation_helpers_1.findByForeignKeys(throughRepo, throughKeyFrom, sourceIds, {}, // scope will be applied at the target level
52
+ options);
53
+ const throughResult = relation_helpers_1.flattenTargetsOfOneToManyRelation(sourceIds, throughFound, throughKeyFrom);
54
+ const result = [];
55
+ // convert from through entities to the target entities
56
+ for (const entityList of throughResult) {
57
+ if (entityList) {
58
+ // get target ids from the through entities by foreign key
59
+ const targetIds = entityList.map(entity => entity[throughKeyTo]);
60
+ // the explicit types and casts are needed
61
+ const targetEntityList = await relation_helpers_1.findByForeignKeys(targetRepo, targetKey, targetIds, inclusion.scope, options);
62
+ result.push(targetEntityList);
63
+ }
64
+ else {
65
+ // no entities found, add undefined to results
66
+ result.push(entityList);
67
+ }
68
+ }
69
+ debug('fetchHasManyThroughModels result', result);
70
+ return result;
71
+ };
72
+ }
73
+ exports.createHasManyThroughInclusionResolver = createHasManyThroughInclusionResolver;
74
+ //# sourceMappingURL=has-many-through.inclusion.resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"has-many-through.inclusion.resolver.js","sourceRoot":"","sources":["../../../src/relations/has-many/has-many-through.inclusion.resolver.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,oCAAoC;AACpC,+CAA+C;AAC/C,gEAAgE;;;;AAGhE,0DAAiC;AAIjC,0DAI6B;AAE7B,yDAA0D;AAE1D,MAAM,KAAK,GAAG,eAAY,CACxB,yDAAyD,CAC1D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,SAAgB,qCAAqC,CAQnD,IAAuB,EACvB,cAEC,EACD,aAEC;IAED,MAAM,YAAY,GAAG,yCAAsB,CAAC,IAAI,CAAC,CAAC;IAElD,OAAO,KAAK,UAAU,yBAAyB,CAC7C,QAAkB,EAClB,SAAoB,EACpB,OAAiB;QAEjB,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEhC,KAAK,CAAC,sCAAsC,EAAE,QAAQ,CAAC,CAAC;QACxD,KAAK,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAAC;QAE1C,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAE,CAAe,CAAC,SAAS,CAAC,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,YAAY,CAAC,KAA4B,CAAC;QAC5D,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE;YACzB,MAAM,IAAI,KAAK,CACb,2CAA2C,YAAY,EAAE,CAC1D,CAAC;SACH;QACD,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,KAA6B,CAAC;QACxE,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,OAA+B,CAAC;QAE5E,KAAK,CAAC,aAAa,EAAE;YACnB,SAAS;YACT,SAAS;YACT,SAAS;YACT,YAAY;YACZ,cAAc;SACf,CAAC,CAAC;QAEH,KAAK,CACH,gBAAgB,EAChB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAC7B,CAAC;QAEF,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAC;QAEzC,sBAAsB;QACtB,MAAM,YAAY,GAAG,MAAM,oCAAiB,CAC1C,WAAW,EACX,cAAc,EACd,SAAS,EACT,EAAE,EAAE,4CAA4C;QAChD,OAAO,CACR,CAAC;QAEF,MAAM,aAAa,GAAG,oDAAiC,CACrD,SAAS,EACT,YAAY,EACZ,cAAc,CACf,CAAC;QAEF,MAAM,MAAM,GAAG,EAAE,CAAC;QAElB,uDAAuD;QACvD,KAAK,MAAM,UAAU,IAAI,aAAa,EAAE;YACtC,IAAI,UAAU,EAAE;gBACd,0DAA0D;gBAC1D,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;gBAEjE,0CAA0C;gBAC1C,MAAM,gBAAgB,GAAG,MAAM,oCAAiB,CAK9C,UAAU,EACV,SAAS,EACR,SAA2B,EAC5B,SAAS,CAAC,KAAuB,EACjC,OAAO,CACR,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;aAC/B;iBAAM;gBACL,8CAA8C;gBAC9C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;aACzB;SACF;QAED,KAAK,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC;QAClD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AApGD,sFAoGC"}
@@ -5,7 +5,7 @@ import { AnyObject, Entity, EntityCrudRepository, Filter, Inclusion, Options } f
5
5
  * @param targetRepository - The target repository where the related model instances are found
6
6
  * @param fkName - Name of the foreign key
7
7
  * @param fkValues - One value or array of values of the foreign key to be included
8
- * @param scope - Additional scope constraints (not currently supported)
8
+ * @param scope - Additional scope constraints
9
9
  * @param options - Options for the operations
10
10
  */
11
11
  export declare function findByForeignKeys<Target extends Entity, TargetRelations extends object, ForeignKey extends StringKeyOf<Target>>(targetRepository: EntityCrudRepository<Target, unknown, TargetRelations>, fkName: ForeignKey, fkValues: Target[ForeignKey][] | Target[ForeignKey], scope?: Filter<Target>, options?: Options): Promise<(Target & TargetRelations)[]>;
@@ -17,7 +17,7 @@ const debug = debug_1.default('loopback:repository:relation-helpers');
17
17
  * @param targetRepository - The target repository where the related model instances are found
18
18
  * @param fkName - Name of the foreign key
19
19
  * @param fkValues - One value or array of values of the foreign key to be included
20
- * @param scope - Additional scope constraints (not currently supported)
20
+ * @param scope - Additional scope constraints
21
21
  * @param options - Options for the operations
22
22
  */
23
23
  async function findByForeignKeys(targetRepository, fkName, fkValues, scope, options) {
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@loopback/repository",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Define and implement a common set of interfaces for interacting with databases",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "engines": {
8
- "node": ">=10.16"
8
+ "node": "^10.16 || 12 || 14"
9
9
  },
10
10
  "scripts": {
11
11
  "acceptance": "lb-mocha \"dist/__tests__/acceptance/**/*.js\"",
@@ -22,13 +22,13 @@
22
22
  "access": "public"
23
23
  },
24
24
  "peerDependencies": {
25
- "@loopback/core": "^2.10.1"
25
+ "@loopback/core": "^2.11.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@loopback/build": "^6.2.4",
29
- "@loopback/core": "^2.10.1",
30
- "@loopback/eslint-config": "^10.0.0",
31
- "@loopback/testlab": "^3.2.6",
28
+ "@loopback/build": "^6.2.5",
29
+ "@loopback/core": "^2.11.0",
30
+ "@loopback/eslint-config": "^10.0.1",
31
+ "@loopback/testlab": "^3.2.7",
32
32
  "@types/bson": "^4.0.2",
33
33
  "@types/json-schema": "^7.0.6",
34
34
  "@types/lodash": "^4.14.161",
@@ -36,12 +36,12 @@
36
36
  "bson": "4.1.0"
37
37
  },
38
38
  "dependencies": {
39
- "@loopback/filter": "^1.1.1",
39
+ "@loopback/filter": "^1.1.2",
40
40
  "@types/debug": "^4.1.5",
41
- "debug": "^4.1.1",
41
+ "debug": "^4.2.0",
42
42
  "lodash": "^4.17.20",
43
43
  "loopback-datasource-juggler": "^4.24.0",
44
- "tslib": "^2.0.1"
44
+ "tslib": "^2.0.2"
45
45
  },
46
46
  "files": [
47
47
  "README.md",
@@ -54,5 +54,5 @@
54
54
  "url": "https://github.com/strongloop/loopback-next.git",
55
55
  "directory": "packages/repository"
56
56
  },
57
- "gitHead": "79327fd7e68ebb05be0aa689f4986b54e2a99a6b"
57
+ "gitHead": "390f2794d10eea3d969ae417963af815ce1bc417"
58
58
  }
@@ -96,13 +96,19 @@ export interface Count {
96
96
 
97
97
  /**
98
98
  * JSON Schema describing the Count interface. It's the response type for
99
- * REST calls to APIs which return Count
99
+ * REST calls to APIs which return `count`. The type is compatible with
100
+ * `SchemaObject` from `@loopback/openapi-v3`, which is not an explicit
101
+ * dependency for `@loopback/repository`.
100
102
  */
101
- export const CountSchema = {
102
- type: 'object',
103
+ export const CountSchema /* :SchemaObject */ = {
104
+ type: 'object' as const, // Force to be `object` type instead of `string`
103
105
  title: 'loopback.Count',
104
106
  'x-typescript-type': '@loopback/repository#Count',
105
- properties: {count: {type: 'number'}},
107
+ properties: {
108
+ count: {
109
+ type: 'number' as const, // Force to be `number` type instead of `string`
110
+ },
111
+ },
106
112
  };
107
113
 
108
114
  /**
@@ -2,12 +2,14 @@
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 {
6
7
  DataObject,
7
8
  Entity,
8
9
  EntityCrudRepository,
9
10
  Getter,
10
11
  HasManyDefinition,
12
+ InclusionResolver,
11
13
  } from '../..';
12
14
  import {
13
15
  createTargetConstraintFromThrough,
@@ -17,6 +19,7 @@ import {
17
19
  getTargetKeysFromThroughModels,
18
20
  resolveHasManyThroughMetadata,
19
21
  } from './has-many-through.helpers';
22
+ import {createHasManyThroughInclusionResolver} from './has-many-through.inclusion.resolver';
20
23
  import {
21
24
  DefaultHasManyThroughRepository,
22
25
  HasManyThroughRepository,
@@ -35,9 +38,18 @@ export type HasManyThroughRepositoryFactory<
35
38
  TargetID,
36
39
  ThroughEntity extends Entity,
37
40
  SourceID
38
- > = (
39
- fkValue: SourceID,
40
- ) => HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity>;
41
+ > = {
42
+ (fkValue: SourceID): HasManyThroughRepository<
43
+ TargetEntity,
44
+ TargetID,
45
+ ThroughEntity
46
+ >;
47
+
48
+ /**
49
+ * Use `resolver` property to obtain an InclusionResolver for this relation.
50
+ */
51
+ inclusionResolver: InclusionResolver<Entity, TargetEntity>;
52
+ };
41
53
 
42
54
  export function createHasManyThroughRepositoryFactory<
43
55
  Target extends Entity,
@@ -100,5 +112,10 @@ export function createHasManyThroughRepositoryFactory<
100
112
  getThroughConstraintFromTarget,
101
113
  );
102
114
  };
115
+ result.inclusionResolver = createHasManyThroughInclusionResolver(
116
+ meta,
117
+ throughRepositoryGetter,
118
+ targetRepositoryGetter,
119
+ );
103
120
  return result;
104
121
  }
@@ -0,0 +1,135 @@
1
+ // Copyright IBM Corp. 2020. All Rights Reserved.
2
+ // Node module: @loopback/repository
3
+ // This file is licensed under the MIT License.
4
+ // License text available at https://opensource.org/licenses/MIT
5
+
6
+ import {Filter, Inclusion} from '@loopback/filter';
7
+ import debugFactory from 'debug';
8
+ import {AnyObject, Options} from '../../common-types';
9
+ import {Entity} from '../../model';
10
+ import {EntityCrudRepository} from '../../repositories/repository';
11
+ import {
12
+ findByForeignKeys,
13
+ flattenTargetsOfOneToManyRelation,
14
+ StringKeyOf,
15
+ } from '../relation.helpers';
16
+ import {Getter, HasManyDefinition, InclusionResolver} from '../relation.types';
17
+ import {resolveHasManyMetadata} from './has-many.helpers';
18
+
19
+ const debug = debugFactory(
20
+ 'loopback:repository:has-many-through-inclusion-resolver',
21
+ );
22
+
23
+ /**
24
+ * Creates InclusionResolver for HasManyThrough relation.
25
+ * Notice that this function only generates the inclusionResolver.
26
+ * It doesn't register it for the source repository.
27
+ *
28
+ *
29
+ * @param meta - metadata of the hasMany relation (including through)
30
+ * @param getThroughRepo - through repository getter i.e. where through
31
+ * instances are
32
+ * @param getTargetRepo - target repository getter i.e where target instances
33
+ * are
34
+ */
35
+ export function createHasManyThroughInclusionResolver<
36
+ Through extends Entity,
37
+ ThroughID,
38
+ ThroughRelations extends object,
39
+ Target extends Entity,
40
+ TargetID,
41
+ TargetRelations extends object
42
+ >(
43
+ meta: HasManyDefinition,
44
+ getThroughRepo: Getter<
45
+ EntityCrudRepository<Through, ThroughID, ThroughRelations>
46
+ >,
47
+ getTargetRepo: Getter<
48
+ EntityCrudRepository<Target, TargetID, TargetRelations>
49
+ >,
50
+ ): InclusionResolver<Entity, Target> {
51
+ const relationMeta = resolveHasManyMetadata(meta);
52
+
53
+ return async function fetchHasManyThroughModels(
54
+ entities: Entity[],
55
+ inclusion: Inclusion,
56
+ options?: Options,
57
+ ): Promise<((Target & TargetRelations)[] | undefined)[]> {
58
+ if (!entities.length) return [];
59
+
60
+ debug('Fetching target models for entities:', entities);
61
+ debug('Relation metadata:', relationMeta);
62
+
63
+ const sourceKey = relationMeta.keyFrom;
64
+ const sourceIds = entities.map(e => (e as AnyObject)[sourceKey]);
65
+ const targetKey = relationMeta.keyTo as StringKeyOf<Target>;
66
+ if (!relationMeta.through) {
67
+ throw new Error(
68
+ `relationMeta.through must be defined on ${relationMeta}`,
69
+ );
70
+ }
71
+ const throughKeyTo = relationMeta.through.keyTo as StringKeyOf<Through>;
72
+ const throughKeyFrom = relationMeta.through.keyFrom as StringKeyOf<Through>;
73
+
74
+ debug('Parameters:', {
75
+ sourceKey,
76
+ sourceIds,
77
+ targetKey,
78
+ throughKeyTo,
79
+ throughKeyFrom,
80
+ });
81
+
82
+ debug(
83
+ 'sourceId types',
84
+ sourceIds.map(i => typeof i),
85
+ );
86
+
87
+ const throughRepo = await getThroughRepo();
88
+ const targetRepo = await getTargetRepo();
89
+
90
+ // find through models
91
+ const throughFound = await findByForeignKeys(
92
+ throughRepo,
93
+ throughKeyFrom,
94
+ sourceIds,
95
+ {}, // scope will be applied at the target level
96
+ options,
97
+ );
98
+
99
+ const throughResult = flattenTargetsOfOneToManyRelation(
100
+ sourceIds,
101
+ throughFound,
102
+ throughKeyFrom,
103
+ );
104
+
105
+ const result = [];
106
+
107
+ // convert from through entities to the target entities
108
+ for (const entityList of throughResult) {
109
+ if (entityList) {
110
+ // get target ids from the through entities by foreign key
111
+ const targetIds = entityList.map(entity => entity[throughKeyTo]);
112
+
113
+ // the explicit types and casts are needed
114
+ const targetEntityList = await findByForeignKeys<
115
+ Target,
116
+ TargetRelations,
117
+ StringKeyOf<Target>
118
+ >(
119
+ targetRepo,
120
+ targetKey,
121
+ (targetIds as unknown) as [],
122
+ inclusion.scope as Filter<Target>,
123
+ options,
124
+ );
125
+ result.push(targetEntityList);
126
+ } else {
127
+ // no entities found, add undefined to results
128
+ result.push(entityList);
129
+ }
130
+ }
131
+
132
+ debug('fetchHasManyThroughModels result', result);
133
+ return result;
134
+ };
135
+ }
@@ -24,7 +24,7 @@ const debug = debugFactory('loopback:repository:relation-helpers');
24
24
  * @param targetRepository - The target repository where the related model instances are found
25
25
  * @param fkName - Name of the foreign key
26
26
  * @param fkValues - One value or array of values of the foreign key to be included
27
- * @param scope - Additional scope constraints (not currently supported)
27
+ * @param scope - Additional scope constraints
28
28
  * @param options - Options for the operations
29
29
  */
30
30
  export async function findByForeignKeys<