@loopback/repository 4.1.2 → 5.0.2
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/LICENSE +1 -1
- package/dist/connectors/connector.js +1 -1
- package/dist/connectors/connector.js.map +1 -1
- package/dist/connectors/crud.connector.js +1 -1
- package/dist/connectors/crud.connector.js.map +1 -1
- package/dist/connectors/index.js +1 -1
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/kv.connector.js +1 -1
- package/dist/connectors/kv.connector.js.map +1 -1
- package/dist/datasource.js +1 -1
- package/dist/datasource.js.map +1 -1
- package/dist/decorators/index.js +1 -1
- package/dist/decorators/index.js.map +1 -1
- package/dist/decorators/metadata.js +1 -1
- package/dist/decorators/metadata.js.map +1 -1
- package/dist/decorators/model.decorator.js +1 -1
- package/dist/decorators/model.decorator.js.map +1 -1
- package/dist/decorators/repository.decorator.js +1 -1
- package/dist/decorators/repository.decorator.js.map +1 -1
- package/dist/define-model-class.js +1 -1
- package/dist/define-model-class.js.map +1 -1
- package/dist/define-repository-class.js +1 -1
- package/dist/define-repository-class.js.map +1 -1
- package/dist/errors/entity-not-found.error.js +1 -1
- package/dist/errors/entity-not-found.error.js.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +2 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/invalid-polymorphism.error.d.ts +5 -0
- package/dist/errors/invalid-polymorphism.error.js +22 -0
- package/dist/errors/invalid-polymorphism.error.js.map +1 -0
- package/dist/errors/invalid-relation.error.d.ts +1 -1
- package/dist/errors/invalid-relation.error.js +1 -1
- package/dist/errors/invalid-relation.error.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mixins/index.js +1 -1
- package/dist/mixins/index.js.map +1 -1
- package/dist/mixins/repository.mixin.d.ts +49 -50
- package/dist/mixins/repository.mixin.js +1 -1
- package/dist/mixins/repository.mixin.js.map +1 -1
- package/dist/model.d.ts +7 -1
- package/dist/model.js +15 -1
- package/dist/model.js.map +1 -1
- package/dist/relations/belongs-to/belongs-to.accessor.d.ts +6 -2
- package/dist/relations/belongs-to/belongs-to.accessor.js +19 -6
- package/dist/relations/belongs-to/belongs-to.accessor.js.map +1 -1
- package/dist/relations/belongs-to/belongs-to.decorator.js +1 -1
- package/dist/relations/belongs-to/belongs-to.decorator.js.map +1 -1
- package/dist/relations/belongs-to/belongs-to.helpers.d.ts +3 -0
- package/dist/relations/belongs-to/belongs-to.helpers.js +33 -9
- package/dist/relations/belongs-to/belongs-to.helpers.js.map +1 -1
- package/dist/relations/belongs-to/belongs-to.inclusion-resolver.d.ts +5 -2
- package/dist/relations/belongs-to/belongs-to.inclusion-resolver.js +82 -9
- package/dist/relations/belongs-to/belongs-to.inclusion-resolver.js.map +1 -1
- package/dist/relations/belongs-to/belongs-to.repository.d.ts +28 -5
- package/dist/relations/belongs-to/belongs-to.repository.js +50 -11
- package/dist/relations/belongs-to/belongs-to.repository.js.map +1 -1
- package/dist/relations/belongs-to/index.d.ts +2 -2
- package/dist/relations/belongs-to/index.js +3 -3
- package/dist/relations/belongs-to/index.js.map +1 -1
- package/dist/relations/has-many/has-many-through.helpers.d.ts +3 -0
- package/dist/relations/has-many/has-many-through.helpers.js +26 -2
- package/dist/relations/has-many/has-many-through.helpers.js.map +1 -1
- package/dist/relations/has-many/has-many-through.inclusion-resolver.d.ts +3 -1
- package/dist/relations/has-many/has-many-through.inclusion-resolver.js +93 -22
- package/dist/relations/has-many/has-many-through.inclusion-resolver.js.map +1 -1
- package/dist/relations/has-many/has-many-through.repository-factory.d.ts +3 -1
- package/dist/relations/has-many/has-many-through.repository-factory.js +8 -2
- package/dist/relations/has-many/has-many-through.repository-factory.js.map +1 -1
- package/dist/relations/has-many/has-many-through.repository.d.ts +66 -11
- package/dist/relations/has-many/has-many-through.repository.js +212 -36
- package/dist/relations/has-many/has-many-through.repository.js.map +1 -1
- package/dist/relations/has-many/has-many.decorator.js +1 -1
- package/dist/relations/has-many/has-many.decorator.js.map +1 -1
- package/dist/relations/has-many/has-many.helpers.js +1 -1
- package/dist/relations/has-many/has-many.helpers.js.map +1 -1
- package/dist/relations/has-many/has-many.inclusion-resolver.js +1 -1
- package/dist/relations/has-many/has-many.inclusion-resolver.js.map +1 -1
- package/dist/relations/has-many/has-many.repository-factory.js +1 -1
- package/dist/relations/has-many/has-many.repository-factory.js.map +1 -1
- package/dist/relations/has-many/has-many.repository.js +1 -1
- package/dist/relations/has-many/has-many.repository.js.map +1 -1
- package/dist/relations/has-many/index.d.ts +2 -2
- package/dist/relations/has-many/index.js +3 -3
- package/dist/relations/has-many/index.js.map +1 -1
- package/dist/relations/has-one/has-one.decorator.js +1 -1
- package/dist/relations/has-one/has-one.decorator.js.map +1 -1
- package/dist/relations/has-one/has-one.helpers.d.ts +3 -0
- package/dist/relations/has-one/has-one.helpers.js +35 -9
- package/dist/relations/has-one/has-one.helpers.js.map +1 -1
- package/dist/relations/has-one/has-one.inclusion-resolver.d.ts +6 -3
- package/dist/relations/has-one/has-one.inclusion-resolver.js +83 -8
- package/dist/relations/has-one/has-one.inclusion-resolver.js.map +1 -1
- package/dist/relations/has-one/has-one.repository-factory.d.ts +9 -3
- package/dist/relations/has-one/has-one.repository-factory.js +14 -4
- package/dist/relations/has-one/has-one.repository-factory.js.map +1 -1
- package/dist/relations/has-one/has-one.repository.d.ts +58 -11
- package/dist/relations/has-one/has-one.repository.js +119 -16
- package/dist/relations/has-one/has-one.repository.js.map +1 -1
- package/dist/relations/has-one/index.js +1 -1
- package/dist/relations/has-one/index.js.map +1 -1
- package/dist/relations/index.d.ts +2 -0
- package/dist/relations/index.js +3 -1
- package/dist/relations/index.js.map +1 -1
- package/dist/relations/references-many/index.d.ts +4 -0
- package/dist/relations/references-many/index.js +12 -0
- package/dist/relations/references-many/index.js.map +1 -0
- package/dist/relations/references-many/references-many.accessor.d.ts +17 -0
- package/dist/relations/references-many/references-many.accessor.js +40 -0
- package/dist/relations/references-many/references-many.accessor.js.map +1 -0
- package/dist/relations/references-many/references-many.decorator.d.ts +11 -0
- package/dist/relations/references-many/references-many.decorator.js +73 -0
- package/dist/relations/references-many/references-many.decorator.js.map +1 -0
- package/dist/relations/references-many/references-many.helpers.d.ts +17 -0
- package/dist/relations/references-many/references-many.helpers.js +63 -0
- package/dist/relations/references-many/references-many.helpers.js.map +1 -0
- package/dist/relations/references-many/references-many.inclusion-resolver.d.ts +14 -0
- package/dist/relations/references-many/references-many.inclusion-resolver.js +42 -0
- package/dist/relations/references-many/references-many.inclusion-resolver.js.map +1 -0
- package/dist/relations/references-many/references-many.repository.d.ts +28 -0
- package/dist/relations/references-many/references-many.repository.js +33 -0
- package/dist/relations/references-many/references-many.repository.js.map +1 -0
- package/dist/relations/relation.decorator.d.ts +0 -6
- package/dist/relations/relation.decorator.js +2 -14
- package/dist/relations/relation.decorator.js.map +1 -1
- package/dist/relations/relation.filter.solver.d.ts +2 -0
- package/dist/relations/relation.filter.solver.js +57 -0
- package/dist/relations/relation.filter.solver.js.map +1 -0
- package/dist/relations/relation.helpers.js +18 -3
- package/dist/relations/relation.helpers.js.map +1 -1
- package/dist/relations/relation.types.d.ts +52 -1
- package/dist/relations/relation.types.js +1 -1
- package/dist/relations/relation.types.js.map +1 -1
- package/dist/repositories/constraint-utils.js +1 -1
- package/dist/repositories/constraint-utils.js.map +1 -1
- package/dist/repositories/index.d.ts +2 -2
- package/dist/repositories/index.js +3 -3
- package/dist/repositories/index.js.map +1 -1
- package/dist/repositories/kv.repository.bridge.js +1 -1
- package/dist/repositories/kv.repository.bridge.js.map +1 -1
- package/dist/repositories/kv.repository.d.ts +2 -2
- package/dist/repositories/kv.repository.js +1 -1
- package/dist/repositories/kv.repository.js.map +1 -1
- package/dist/repositories/legacy-juggler-bridge.d.ts +36 -9
- package/dist/repositories/legacy-juggler-bridge.js +38 -16
- package/dist/repositories/legacy-juggler-bridge.js.map +1 -1
- package/dist/repositories/repository.js +1 -1
- package/dist/repositories/repository.js.map +1 -1
- package/dist/type-resolver.js +1 -1
- package/dist/type-resolver.js.map +1 -1
- package/dist/types/any.js +1 -1
- package/dist/types/any.js.map +1 -1
- package/dist/types/array.js +1 -1
- package/dist/types/array.js.map +1 -1
- package/dist/types/boolean.js +1 -1
- package/dist/types/boolean.js.map +1 -1
- package/dist/types/buffer.js +1 -1
- package/dist/types/buffer.js.map +1 -1
- package/dist/types/date.js +1 -1
- package/dist/types/date.js.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/model.js +1 -1
- package/dist/types/model.js.map +1 -1
- package/dist/types/null.js +1 -1
- package/dist/types/null.js.map +1 -1
- package/dist/types/number.js +1 -1
- package/dist/types/number.js.map +1 -1
- package/dist/types/object.js +1 -1
- package/dist/types/object.js.map +1 -1
- package/dist/types/string.js +1 -1
- package/dist/types/string.js.map +1 -1
- package/dist/types/type.js +1 -1
- package/dist/types/type.js.map +1 -1
- package/dist/types/union.js +1 -1
- package/dist/types/union.js.map +1 -1
- package/package.json +15 -15
- package/src/connectors/connector.ts +1 -1
- package/src/connectors/crud.connector.ts +1 -1
- package/src/connectors/index.ts +1 -1
- package/src/connectors/kv.connector.ts +1 -1
- package/src/datasource.ts +1 -1
- package/src/decorators/index.ts +1 -1
- package/src/decorators/metadata.ts +1 -1
- package/src/decorators/model.decorator.ts +1 -1
- package/src/decorators/repository.decorator.ts +1 -1
- package/src/define-model-class.ts +1 -1
- package/src/define-repository-class.ts +1 -1
- package/src/errors/entity-not-found.error.ts +1 -1
- package/src/errors/index.ts +2 -1
- package/src/errors/invalid-polymorphism.error.ts +28 -0
- package/src/errors/invalid-relation.error.ts +2 -2
- package/src/index.ts +1 -1
- package/src/mixins/index.ts +1 -1
- package/src/mixins/repository.mixin.ts +1 -6
- package/src/model.ts +20 -1
- package/src/relations/belongs-to/belongs-to.accessor.ts +36 -7
- package/src/relations/belongs-to/belongs-to.decorator.ts +2 -2
- package/src/relations/belongs-to/belongs-to.helpers.ts +37 -10
- package/src/relations/belongs-to/belongs-to.inclusion-resolver.ts +109 -18
- package/src/relations/belongs-to/belongs-to.repository.ts +78 -18
- package/src/relations/belongs-to/index.ts +3 -3
- package/src/relations/has-many/has-many-through.helpers.ts +28 -2
- package/src/relations/has-many/has-many-through.inclusion-resolver.ts +118 -27
- package/src/relations/has-many/has-many-through.repository-factory.ts +22 -4
- package/src/relations/has-many/has-many-through.repository.ts +344 -77
- package/src/relations/has-many/has-many.decorator.ts +1 -1
- package/src/relations/has-many/has-many.helpers.ts +1 -1
- package/src/relations/has-many/has-many.inclusion-resolver.ts +1 -1
- package/src/relations/has-many/has-many.repository-factory.ts +1 -1
- package/src/relations/has-many/has-many.repository.ts +1 -1
- package/src/relations/has-many/index.ts +3 -3
- package/src/relations/has-one/has-one.decorator.ts +1 -1
- package/src/relations/has-one/has-one.helpers.ts +41 -14
- package/src/relations/has-one/has-one.inclusion-resolver.ts +110 -16
- package/src/relations/has-one/has-one.repository-factory.ts +35 -7
- package/src/relations/has-one/has-one.repository.ts +189 -36
- package/src/relations/has-one/index.ts +1 -1
- package/src/relations/index.ts +3 -1
- package/src/relations/references-many/index.ts +9 -0
- package/src/relations/references-many/references-many.accessor.ts +76 -0
- package/src/relations/references-many/references-many.decorator.ts +100 -0
- package/src/relations/references-many/references-many.helpers.ts +82 -0
- package/src/relations/references-many/references-many.inclusion-resolver.ts +80 -0
- package/src/relations/references-many/references-many.repository.ts +55 -0
- package/src/relations/relation.decorator.ts +1 -13
- package/src/relations/relation.filter.solver.ts +56 -0
- package/src/relations/relation.helpers.ts +18 -3
- package/src/relations/relation.types.ts +52 -1
- package/src/repositories/constraint-utils.ts +1 -1
- package/src/repositories/index.ts +3 -3
- package/src/repositories/kv.repository.bridge.ts +1 -1
- package/src/repositories/kv.repository.ts +3 -3
- package/src/repositories/legacy-juggler-bridge.ts +80 -16
- package/src/repositories/repository.ts +1 -1
- package/src/type-resolver.ts +1 -1
- package/src/types/any.ts +1 -1
- package/src/types/array.ts +1 -1
- package/src/types/boolean.ts +1 -1
- package/src/types/buffer.ts +1 -1
- package/src/types/date.ts +1 -1
- package/src/types/index.ts +1 -1
- package/src/types/model.ts +1 -1
- package/src/types/null.ts +1 -1
- package/src/types/number.ts +1 -1
- package/src/types/object.ts +1 -1
- package/src/types/string.ts +1 -1
- package/src/types/type.ts +1 -1
- package/src/types/union.ts +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 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
6
|
import {Getter} from '@loopback/core';
|
|
7
|
+
import {cloneDeep} from 'lodash';
|
|
8
|
+
import {EntityNotFoundError, TypeResolver} from '../../';
|
|
7
9
|
import {DataObject, Options} from '../../common-types';
|
|
8
|
-
import {EntityNotFoundError} from '../../errors';
|
|
9
10
|
import {Entity} from '../../model';
|
|
10
11
|
import {constrainFilter, EntityCrudRepository} from '../../repositories';
|
|
11
|
-
|
|
12
12
|
/**
|
|
13
13
|
* CRUD operations for a target repository of a BelongsTo relation
|
|
14
14
|
*/
|
|
@@ -16,10 +16,16 @@ export interface BelongsToRepository<Target extends Entity> {
|
|
|
16
16
|
/**
|
|
17
17
|
* Gets the target model instance
|
|
18
18
|
* @param options
|
|
19
|
+
* options.polymorphicType - a string or a string array of polymorphic type names
|
|
20
|
+
* to specify which repositories should are expected to be searched
|
|
21
|
+
* It is highly recommended to contain this param especially for
|
|
22
|
+
* datasources using deplicated ids across tables
|
|
19
23
|
* @returns A promise resolved with the target object or rejected
|
|
20
24
|
* with an EntityNotFoundError when target model instance was not found.
|
|
21
25
|
*/
|
|
22
|
-
get(
|
|
26
|
+
get(
|
|
27
|
+
options?: Options & {polymorphicType?: string | string[]},
|
|
28
|
+
): Promise<Target>;
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
export class DefaultBelongsToRepository<
|
|
@@ -30,26 +36,80 @@ export class DefaultBelongsToRepository<
|
|
|
30
36
|
{
|
|
31
37
|
/**
|
|
32
38
|
* Constructor of DefaultBelongsToEntityCrudRepository
|
|
33
|
-
* @param getTargetRepository -
|
|
39
|
+
* @param getTargetRepository - either a dictionary of target model type - target repository instance
|
|
40
|
+
* or a single target repository instance
|
|
41
|
+
* e.g. if the target is of a non-polymorphic type "Student", put the studentRepositoryGetterInstance
|
|
42
|
+
* if the target is of a polymorphic type "Person" which can be either a "Student" or a "Teacher"
|
|
43
|
+
* then put "{Student: studentRepositoryGetterInstance, Teacher: teacherRepositoryGetterInstance}"
|
|
34
44
|
* @param constraint - the key value pair representing foreign key name to constrain
|
|
35
45
|
* the target repository instance
|
|
46
|
+
* @param targetResolver - () => Target to resolve the target class
|
|
47
|
+
* e.g. if the target is of type "Student", then put "() => Student"
|
|
36
48
|
*/
|
|
49
|
+
|
|
37
50
|
constructor(
|
|
38
|
-
public getTargetRepository:
|
|
51
|
+
public getTargetRepository:
|
|
52
|
+
| Getter<TargetRepository>
|
|
53
|
+
| {
|
|
54
|
+
[repoType: string]: Getter<TargetRepository>;
|
|
55
|
+
},
|
|
39
56
|
public constraint: DataObject<TargetEntity>,
|
|
40
|
-
|
|
57
|
+
public targetResolver: TypeResolver<Entity, typeof Entity>,
|
|
58
|
+
) {
|
|
59
|
+
if (typeof getTargetRepository === 'function') {
|
|
60
|
+
this.getTargetRepositoryDict = {
|
|
61
|
+
[targetResolver().name]:
|
|
62
|
+
getTargetRepository as Getter<TargetRepository>,
|
|
63
|
+
};
|
|
64
|
+
} else {
|
|
65
|
+
this.getTargetRepositoryDict = getTargetRepository as {
|
|
66
|
+
[repoType: string]: Getter<TargetRepository>;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public getTargetRepositoryDict: {
|
|
72
|
+
[repoType: string]: Getter<TargetRepository>;
|
|
73
|
+
};
|
|
41
74
|
|
|
42
|
-
async get(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
75
|
+
async get(
|
|
76
|
+
options?: Options & {polymorphicType?: string | string[]},
|
|
77
|
+
): Promise<TargetEntity> {
|
|
78
|
+
let polymorphicTypes = options?.polymorphicType;
|
|
79
|
+
let allKeys: string[];
|
|
80
|
+
if (Object.keys(this.getTargetRepositoryDict).length <= 1) {
|
|
81
|
+
allKeys = Object.keys(this.getTargetRepositoryDict);
|
|
82
|
+
} else if (!polymorphicTypes || polymorphicTypes.length === 0) {
|
|
83
|
+
console.warn(
|
|
84
|
+
'It is highly recommended to specify the polymorphicTypes param when using polymorphic types.',
|
|
85
|
+
);
|
|
86
|
+
allKeys = Object.keys(this.getTargetRepositoryDict);
|
|
87
|
+
} else {
|
|
88
|
+
if (typeof polymorphicTypes === 'string') {
|
|
89
|
+
polymorphicTypes = [polymorphicTypes];
|
|
90
|
+
}
|
|
91
|
+
allKeys = [];
|
|
92
|
+
new Set(polymorphicTypes!).forEach(element => {
|
|
93
|
+
if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
|
|
94
|
+
allKeys.push(element);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
let result: TargetEntity[] = [];
|
|
99
|
+
for (const key of allKeys) {
|
|
100
|
+
const targetRepository = await this.getTargetRepositoryDict[key]();
|
|
101
|
+
result = result.concat(
|
|
102
|
+
await targetRepository.find(
|
|
103
|
+
constrainFilter(undefined, this.constraint),
|
|
104
|
+
Object.assign(cloneDeep(options ?? {}), {polymorphicType: key}),
|
|
105
|
+
),
|
|
106
|
+
);
|
|
107
|
+
if (result.length >= 1) {
|
|
108
|
+
return result[0];
|
|
109
|
+
}
|
|
52
110
|
}
|
|
53
|
-
|
|
111
|
+
// We don't have a direct access to the foreign key value here :(
|
|
112
|
+
const id = 'constraint ' + JSON.stringify(this.constraint);
|
|
113
|
+
throw new EntityNotFoundError(this.targetResolver().name, id);
|
|
54
114
|
}
|
|
55
115
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 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
|
-
export * from './belongs-to.decorator';
|
|
7
|
-
export * from './belongs-to.repository';
|
|
8
6
|
export * from './belongs-to.accessor';
|
|
7
|
+
export * from './belongs-to.decorator';
|
|
9
8
|
export * from './belongs-to.inclusion-resolver';
|
|
9
|
+
export * from './belongs-to.repository';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2020. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 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
|
|
@@ -25,6 +25,7 @@ export type HasManyThroughResolvedDefinition = HasManyDefinition & {
|
|
|
25
25
|
through: {
|
|
26
26
|
keyTo: string;
|
|
27
27
|
keyFrom: string;
|
|
28
|
+
polymorphic: false | {discriminator: string};
|
|
28
29
|
};
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -308,7 +309,10 @@ export function resolveHasManyThroughMetadata(
|
|
|
308
309
|
relationMeta.through.keyFrom &&
|
|
309
310
|
throughModelProperties[relationMeta.through.keyFrom] &&
|
|
310
311
|
relationMeta.keyTo &&
|
|
311
|
-
targetModelProperties[relationMeta.keyTo]
|
|
312
|
+
targetModelProperties[relationMeta.keyTo] &&
|
|
313
|
+
(relationMeta.through.polymorphic === false ||
|
|
314
|
+
(typeof relationMeta.through.polymorphic === 'object' &&
|
|
315
|
+
relationMeta.through.polymorphic.discriminator.length > 0))
|
|
312
316
|
) {
|
|
313
317
|
// The explicit cast is needed because of a limitation of type inference
|
|
314
318
|
return relationMeta as HasManyThroughResolvedDefinition;
|
|
@@ -349,6 +353,27 @@ export function resolveHasManyThroughMetadata(
|
|
|
349
353
|
throw new InvalidRelationError(reason, relationMeta);
|
|
350
354
|
}
|
|
351
355
|
|
|
356
|
+
let throughPolymorphic: false | {discriminator: string};
|
|
357
|
+
if (
|
|
358
|
+
relationMeta.through.polymorphic === undefined ||
|
|
359
|
+
relationMeta.through.polymorphic === false ||
|
|
360
|
+
!relationMeta.through.polymorphic
|
|
361
|
+
) {
|
|
362
|
+
const polymorphicFalse = false as const;
|
|
363
|
+
throughPolymorphic = polymorphicFalse;
|
|
364
|
+
} else {
|
|
365
|
+
if (relationMeta.through.polymorphic === true) {
|
|
366
|
+
const polymorphicObject: {discriminator: string} = {
|
|
367
|
+
discriminator: camelCase(relationMeta.target().name + '_type'),
|
|
368
|
+
};
|
|
369
|
+
throughPolymorphic = polymorphicObject;
|
|
370
|
+
} else {
|
|
371
|
+
const polymorphicObject: {discriminator: string} = relationMeta.through
|
|
372
|
+
.polymorphic as {discriminator: string};
|
|
373
|
+
throughPolymorphic = polymorphicObject;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
352
377
|
return Object.assign(relationMeta, {
|
|
353
378
|
keyTo: targetPrimaryKey,
|
|
354
379
|
keyFrom: relationMeta.keyFrom!,
|
|
@@ -356,6 +381,7 @@ export function resolveHasManyThroughMetadata(
|
|
|
356
381
|
...relationMeta.through,
|
|
357
382
|
keyTo: targetFkName,
|
|
358
383
|
keyFrom: sourceFkName,
|
|
384
|
+
polymorphic: throughPolymorphic,
|
|
359
385
|
},
|
|
360
386
|
});
|
|
361
387
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2020. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 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
6
|
import {Filter, InclusionFilter} from '@loopback/filter';
|
|
7
7
|
import debugFactory from 'debug';
|
|
8
|
+
import {InvalidPolymorphismError} from '../..';
|
|
8
9
|
import {AnyObject, Options} from '../../common-types';
|
|
9
10
|
import {Entity} from '../../model';
|
|
10
11
|
import {EntityCrudRepository} from '../../repositories';
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
StringKeyOf,
|
|
15
16
|
} from '../relation.helpers';
|
|
16
17
|
import {Getter, HasManyDefinition, InclusionResolver} from '../relation.types';
|
|
17
|
-
import {
|
|
18
|
+
import {resolveHasManyThroughMetadata} from './has-many-through.helpers';
|
|
18
19
|
|
|
19
20
|
const debug = debugFactory(
|
|
20
21
|
'loopback:repository:relations:has-many-through:inclusion-resolver',
|
|
@@ -44,17 +45,25 @@ export function createHasManyThroughInclusionResolver<
|
|
|
44
45
|
getThroughRepo: Getter<
|
|
45
46
|
EntityCrudRepository<Through, ThroughID, ThroughRelations>
|
|
46
47
|
>,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
getTargetRepoDict: {
|
|
49
|
+
[repoType: string]: Getter<
|
|
50
|
+
EntityCrudRepository<Target, TargetID, TargetRelations>
|
|
51
|
+
>;
|
|
52
|
+
},
|
|
50
53
|
): InclusionResolver<Entity, Target> {
|
|
51
|
-
const relationMeta =
|
|
54
|
+
const relationMeta = resolveHasManyThroughMetadata(meta);
|
|
52
55
|
|
|
53
56
|
return async function fetchHasManyThroughModels(
|
|
54
57
|
entities: Entity[],
|
|
55
58
|
inclusion: InclusionFilter,
|
|
56
59
|
options?: Options,
|
|
57
60
|
): Promise<((Target & TargetRelations)[] | undefined)[]> {
|
|
61
|
+
if (!relationMeta.through) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`relationMeta.through must be defined on ${relationMeta}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
58
67
|
if (!entities.length) return [];
|
|
59
68
|
|
|
60
69
|
debug('Fetching target models for entities:', entities);
|
|
@@ -85,7 +94,6 @@ export function createHasManyThroughInclusionResolver<
|
|
|
85
94
|
);
|
|
86
95
|
|
|
87
96
|
const throughRepo = await getThroughRepo();
|
|
88
|
-
const targetRepo = await getTargetRepo();
|
|
89
97
|
|
|
90
98
|
// find through models
|
|
91
99
|
const throughFound = await findByForeignKeys(
|
|
@@ -102,34 +110,117 @@ export function createHasManyThroughInclusionResolver<
|
|
|
102
110
|
throughKeyFrom,
|
|
103
111
|
);
|
|
104
112
|
|
|
105
|
-
const result = [];
|
|
106
|
-
|
|
107
113
|
const scope =
|
|
108
114
|
typeof inclusion === 'string' ? {} : (inclusion.scope as Filter<Target>);
|
|
109
115
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
// whether the polymorphism is configured
|
|
117
|
+
const targetDiscriminator: keyof (Through & ThroughRelations) | undefined =
|
|
118
|
+
relationMeta.through!.polymorphic
|
|
119
|
+
? (relationMeta.through!.polymorphic.discriminator as keyof (Through &
|
|
120
|
+
ThroughRelations))
|
|
121
|
+
: undefined;
|
|
122
|
+
if (targetDiscriminator) {
|
|
123
|
+
// put through results into arrays based on the target polymorphic types
|
|
124
|
+
const throughArrayByTargetType: {
|
|
125
|
+
[targetType: string]: (Through & ThroughRelations)[];
|
|
126
|
+
} = {};
|
|
127
|
+
for (const throughArray of throughResult) {
|
|
128
|
+
if (throughArray) {
|
|
129
|
+
for (const throughItem of throughArray) {
|
|
130
|
+
const targetType = String(throughItem[targetDiscriminator]);
|
|
131
|
+
if (!getTargetRepoDict[targetType]) {
|
|
132
|
+
throw new InvalidPolymorphismError(
|
|
133
|
+
targetType,
|
|
134
|
+
String(targetDiscriminator),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (!throughArrayByTargetType[targetType]) {
|
|
138
|
+
throughArrayByTargetType[targetType] = [];
|
|
139
|
+
}
|
|
140
|
+
throughArrayByTargetType[targetType].push(throughItem);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// get targets based on their polymorphic types
|
|
145
|
+
const targetOfTypes: {
|
|
146
|
+
[targetType: string]: (Target & TargetRelations)[];
|
|
147
|
+
} = {};
|
|
148
|
+
for (const targetType of Object.keys(throughArrayByTargetType)) {
|
|
149
|
+
const targetIds = throughArrayByTargetType[targetType].map(
|
|
150
|
+
throughItem => throughItem[throughKeyTo],
|
|
151
|
+
);
|
|
152
|
+
const targetRepo = await getTargetRepoDict[targetType]();
|
|
117
153
|
const targetEntityList = await findByForeignKeys<
|
|
118
154
|
Target,
|
|
119
155
|
TargetRelations,
|
|
120
156
|
StringKeyOf<Target>
|
|
121
|
-
>(targetRepo, targetKey, targetIds as unknown as [], scope,
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
157
|
+
>(targetRepo, targetKey, targetIds as unknown as [], scope, options);
|
|
158
|
+
targetOfTypes[targetType] = targetEntityList;
|
|
159
|
+
}
|
|
160
|
+
// put targets into arrays reflecting their throughs
|
|
161
|
+
// Why the order is correct:
|
|
162
|
+
// e.g. through model = T(target instance), target model 1 = a, target model 2 = b
|
|
163
|
+
// all entities: [S1, S2, S2]
|
|
164
|
+
// through-result: [[T(b-11), T(a-12), T(b-13), T(b-14)], [T(a-21), T(a-22), T(b-23)], [T(b-31), T(b-32), T(a-33)]]
|
|
165
|
+
// through-array-by-target-type: {a:[T(a-12), T(a-21), T(a-22), T(a-33)] b: [T(b-11), T(b-13), T(b-14), T(b-23), T(b-31), T(b-32)]}
|
|
166
|
+
// target-array-by-target-type: {a:[a-12, a-21, a-22, a-33] b: [b-11, b-13, b-14, b-23, b-31, b-32]}
|
|
167
|
+
// merged:
|
|
168
|
+
// through-result[0][0]->b => targets: [[b-11 from b.shift()]]
|
|
169
|
+
// through-result[0][1]->a => targets: [[b-11, a-12 from a.shift()]]
|
|
170
|
+
// through-result[0][2]->b => targets: [[b-11, a-12, b-13 from b.shift()]]
|
|
171
|
+
// through-result[0][3]->b => targets: [[b-11, a-12, b-13, b-14 from b.shift()]]
|
|
172
|
+
// through-result[1][0]->a => targets: [[b-11, a-12, b-13, b-14], [a-21, from a.shift()]]
|
|
173
|
+
// through-result[1][1]->a => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22 from a.shift()]]
|
|
174
|
+
// through-result[1][2]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23 from b.shift()]]
|
|
175
|
+
// through-result[2][0]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23], [b-31, from b.shift()]]
|
|
176
|
+
// through-result[2][1]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23], [b-31, b-32 from b.shift()]]
|
|
177
|
+
// through-result[2][1]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23], [b-31, b-32, a-33 from a.shift()]]
|
|
178
|
+
const allTargetsOfThrough: ((Target & TargetRelations)[] | undefined)[] =
|
|
179
|
+
[];
|
|
180
|
+
for (const throughArray of throughResult) {
|
|
181
|
+
if (throughArray && throughArray.length > 0) {
|
|
182
|
+
const currentTargetThroughArray: (Target & TargetRelations)[] = [];
|
|
183
|
+
for (const throughItem of throughArray) {
|
|
184
|
+
const itemToAdd =
|
|
185
|
+
targetOfTypes[String(throughItem[targetDiscriminator])].shift();
|
|
186
|
+
if (itemToAdd) {
|
|
187
|
+
currentTargetThroughArray.push(itemToAdd);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
allTargetsOfThrough.push(currentTargetThroughArray);
|
|
191
|
+
} else {
|
|
192
|
+
allTargetsOfThrough.push(undefined);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return allTargetsOfThrough;
|
|
196
|
+
} else {
|
|
197
|
+
const targetRepo = await getTargetRepoDict[relationMeta.target().name]();
|
|
198
|
+
const result = [];
|
|
199
|
+
|
|
200
|
+
// convert from through entities to the target entities
|
|
201
|
+
for (const entityList of throughResult) {
|
|
202
|
+
if (entityList) {
|
|
203
|
+
// get target ids from the through entities by foreign key
|
|
204
|
+
const targetIds = entityList.map(entity => entity[throughKeyTo]);
|
|
205
|
+
|
|
206
|
+
// the explicit types and casts are needed
|
|
207
|
+
const targetEntityList = await findByForeignKeys<
|
|
208
|
+
Target,
|
|
209
|
+
TargetRelations,
|
|
210
|
+
StringKeyOf<Target>
|
|
211
|
+
>(targetRepo, targetKey, targetIds as unknown as [], scope, {
|
|
212
|
+
...options,
|
|
213
|
+
isThroughModelInclude: true,
|
|
214
|
+
});
|
|
215
|
+
result.push(targetEntityList);
|
|
216
|
+
} else {
|
|
217
|
+
// no entities found, add undefined to results
|
|
218
|
+
result.push(entityList);
|
|
219
|
+
}
|
|
129
220
|
}
|
|
130
|
-
}
|
|
131
221
|
|
|
132
|
-
|
|
133
|
-
|
|
222
|
+
debug('fetchHasManyThroughModels result', result);
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
134
225
|
};
|
|
135
226
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2020. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 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
|
|
@@ -59,10 +59,22 @@ export function createHasManyThroughRepositoryFactory<
|
|
|
59
59
|
SourceID,
|
|
60
60
|
>(
|
|
61
61
|
relationMetadata: HasManyDefinition,
|
|
62
|
-
targetRepositoryGetter:
|
|
62
|
+
targetRepositoryGetter:
|
|
63
|
+
| Getter<EntityCrudRepository<Target, TargetID>>
|
|
64
|
+
| {
|
|
65
|
+
[repoType: string]: Getter<EntityCrudRepository<Target, TargetID>>;
|
|
66
|
+
},
|
|
63
67
|
throughRepositoryGetter: Getter<EntityCrudRepository<Through, ThroughID>>,
|
|
64
68
|
): HasManyThroughRepositoryFactory<Target, TargetID, Through, SourceID> {
|
|
65
69
|
const meta = resolveHasManyThroughMetadata(relationMetadata);
|
|
70
|
+
// resolve the repositoryGetter into a dictionary
|
|
71
|
+
if (typeof targetRepositoryGetter === 'function') {
|
|
72
|
+
targetRepositoryGetter = {
|
|
73
|
+
[meta.target().name]: targetRepositoryGetter as Getter<
|
|
74
|
+
EntityCrudRepository<Target, TargetID>
|
|
75
|
+
>,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
66
78
|
const result = function (fkValue: SourceID) {
|
|
67
79
|
function getTargetConstraintFromThroughModels(
|
|
68
80
|
throughInstances: Through[],
|
|
@@ -103,19 +115,25 @@ export function createHasManyThroughRepositoryFactory<
|
|
|
103
115
|
ThroughID,
|
|
104
116
|
EntityCrudRepository<Through, ThroughID>
|
|
105
117
|
>(
|
|
106
|
-
targetRepositoryGetter
|
|
118
|
+
targetRepositoryGetter as {
|
|
119
|
+
[repoType: string]: Getter<EntityCrudRepository<Target, TargetID>>;
|
|
120
|
+
},
|
|
107
121
|
throughRepositoryGetter,
|
|
108
122
|
getTargetConstraintFromThroughModels,
|
|
109
123
|
getTargetKeys,
|
|
110
124
|
getThroughConstraintFromSource,
|
|
111
125
|
getTargetIds,
|
|
112
126
|
getThroughConstraintFromTarget,
|
|
127
|
+
relationMetadata.target,
|
|
128
|
+
relationMetadata.through!.model,
|
|
113
129
|
);
|
|
114
130
|
};
|
|
115
131
|
result.inclusionResolver = createHasManyThroughInclusionResolver(
|
|
116
132
|
meta,
|
|
117
133
|
throughRepositoryGetter,
|
|
118
|
-
targetRepositoryGetter
|
|
134
|
+
targetRepositoryGetter as {
|
|
135
|
+
[repoType: string]: Getter<EntityCrudRepository<Target, TargetID>>;
|
|
136
|
+
},
|
|
119
137
|
);
|
|
120
138
|
return result;
|
|
121
139
|
}
|