1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import debugFactory from 'debug';
|
7 | import {camelCase} from 'lodash';
|
8 | import {InvalidRelationError} from '../../errors';
|
9 | import {isTypeResolver} from '../../type-resolver';
|
10 | import {HasManyDefinition, RelationType} from '../relation.types';
|
11 |
|
12 | const debug = debugFactory('loopback:repository:relations:has-many:helpers');
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | export type HasManyResolvedDefinition = HasManyDefinition & {
|
19 | keyFrom: string;
|
20 | keyTo: string;
|
21 | };
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | export function resolveHasManyMetadata(
|
31 | relationMeta: HasManyDefinition,
|
32 | ): HasManyResolvedDefinition {
|
33 |
|
34 | relationMeta = resolveHasManyMetaHelper(relationMeta);
|
35 |
|
36 | const targetModel = relationMeta.target();
|
37 | const targetModelProperties = targetModel.definition?.properties;
|
38 |
|
39 | const sourceModel = relationMeta.source;
|
40 |
|
41 | if (relationMeta.keyTo && targetModelProperties[relationMeta.keyTo]) {
|
42 |
|
43 | return relationMeta as HasManyResolvedDefinition;
|
44 | }
|
45 |
|
46 | debug(
|
47 | 'Resolved model %s from given metadata: %o',
|
48 | targetModel.modelName,
|
49 | targetModel,
|
50 | );
|
51 | const defaultFkName = camelCase(sourceModel.modelName + '_id');
|
52 | const hasDefaultFkProperty = targetModelProperties[defaultFkName];
|
53 |
|
54 | if (!hasDefaultFkProperty) {
|
55 | const reason = `target model ${targetModel.name} is missing definition of foreign key ${defaultFkName}`;
|
56 | throw new InvalidRelationError(reason, relationMeta);
|
57 | }
|
58 |
|
59 | return Object.assign(relationMeta, {
|
60 | keyTo: defaultFkName,
|
61 | } as HasManyResolvedDefinition);
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | export function resolveHasManyMetaHelper(
|
73 | relationMeta: HasManyDefinition,
|
74 | ): HasManyDefinition {
|
75 | if ((relationMeta.type as RelationType) !== RelationType.hasMany) {
|
76 | const reason = 'relation type must be HasMany';
|
77 | throw new InvalidRelationError(reason, relationMeta);
|
78 | }
|
79 |
|
80 | if (!isTypeResolver(relationMeta.target)) {
|
81 | const reason = 'target must be a type resolver';
|
82 | throw new InvalidRelationError(reason, relationMeta);
|
83 | }
|
84 |
|
85 | const sourceModel = relationMeta.source;
|
86 | if (!sourceModel?.modelName) {
|
87 | const reason = 'source model must be defined';
|
88 | throw new InvalidRelationError(reason, relationMeta);
|
89 | }
|
90 | let keyFrom;
|
91 | if (
|
92 | relationMeta.keyFrom &&
|
93 | relationMeta.source.definition.properties[relationMeta.keyFrom]
|
94 | ) {
|
95 | keyFrom = relationMeta.keyFrom;
|
96 | } else {
|
97 | keyFrom = sourceModel.getIdProperties()[0];
|
98 | }
|
99 | return Object.assign(relationMeta, {keyFrom}) as HasManyDefinition;
|
100 | }
|