@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 +16 -0
- package/dist/common-types.d.ts +5 -3
- package/dist/common-types.js +9 -3
- package/dist/common-types.js.map +1 -1
- package/dist/mixins/repository.mixin.d.ts +6 -2
- package/dist/relations/has-many/has-many-through-repository.factory.d.ts +8 -2
- package/dist/relations/has-many/has-many-through-repository.factory.js +6 -0
- package/dist/relations/has-many/has-many-through-repository.factory.js.map +1 -1
- package/dist/relations/has-many/has-many-through.inclusion.resolver.d.ts +16 -0
- package/dist/relations/has-many/has-many-through.inclusion.resolver.js +74 -0
- package/dist/relations/has-many/has-many-through.inclusion.resolver.js.map +1 -0
- package/dist/relations/relation.helpers.d.ts +1 -1
- package/dist/relations/relation.helpers.js +1 -1
- package/package.json +11 -11
- package/src/common-types.ts +10 -4
- package/src/relations/has-many/has-many-through-repository.factory.ts +20 -3
- package/src/relations/has-many/has-many-through.inclusion.resolver.ts +135 -0
- package/src/relations/relation.helpers.ts +1 -1
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
|
package/dist/common-types.d.ts
CHANGED
|
@@ -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
|
|
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:
|
|
80
|
+
type: "object";
|
|
79
81
|
title: string;
|
|
80
82
|
'x-typescript-type': string;
|
|
81
83
|
properties: {
|
|
82
84
|
count: {
|
|
83
|
-
type:
|
|
85
|
+
type: "number";
|
|
84
86
|
};
|
|
85
87
|
};
|
|
86
88
|
};
|
package/dist/common-types.js
CHANGED
|
@@ -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
|
|
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: {
|
|
18
|
+
properties: {
|
|
19
|
+
count: {
|
|
20
|
+
type: 'number',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
17
23
|
};
|
|
18
24
|
//# sourceMappingURL=common-types.js.map
|
package/dist/common-types.js.map
CHANGED
|
@@ -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
|
|
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: (
|
|
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> =
|
|
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":";;;
|
|
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
|
|
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
|
|
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
|
|
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": "
|
|
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.
|
|
25
|
+
"@loopback/core": "^2.11.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@loopback/build": "^6.2.
|
|
29
|
-
"@loopback/core": "^2.
|
|
30
|
-
"@loopback/eslint-config": "^10.0.
|
|
31
|
-
"@loopback/testlab": "^3.2.
|
|
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.
|
|
39
|
+
"@loopback/filter": "^1.1.2",
|
|
40
40
|
"@types/debug": "^4.1.5",
|
|
41
|
-
"debug": "^4.
|
|
41
|
+
"debug": "^4.2.0",
|
|
42
42
|
"lodash": "^4.17.20",
|
|
43
43
|
"loopback-datasource-juggler": "^4.24.0",
|
|
44
|
-
"tslib": "^2.0.
|
|
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": "
|
|
57
|
+
"gitHead": "390f2794d10eea3d969ae417963af815ce1bc417"
|
|
58
58
|
}
|
package/src/common-types.ts
CHANGED
|
@@ -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
|
|
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: {
|
|
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
|
-
|
|
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
|
|
27
|
+
* @param scope - Additional scope constraints
|
|
28
28
|
* @param options - Options for the operations
|
|
29
29
|
*/
|
|
30
30
|
export async function findByForeignKeys<
|