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 {BelongsToDefinition, RelationType} from '../relation.types';
|
11 |
|
12 | const debug = debugFactory('loopback:repository:relations:belongs-to:helpers');
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | export type BelongsToResolvedDefinition = BelongsToDefinition & {
|
19 | keyFrom: string;
|
20 | keyTo: string;
|
21 | polymorphic: false | {discriminator: string};
|
22 | };
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | export function resolveBelongsToMetadata(
|
32 | relationMeta: BelongsToDefinition,
|
33 | ): BelongsToResolvedDefinition {
|
34 | if ((relationMeta.type as RelationType) !== RelationType.belongsTo) {
|
35 | const reason = 'relation type must be BelongsTo';
|
36 | throw new InvalidRelationError(reason, relationMeta);
|
37 | }
|
38 |
|
39 | if (!isTypeResolver(relationMeta.target)) {
|
40 | const reason = 'target must be a type resolver';
|
41 | throw new InvalidRelationError(reason, relationMeta);
|
42 | }
|
43 |
|
44 | const sourceModel = relationMeta.source;
|
45 | if (!sourceModel?.modelName) {
|
46 | const reason = 'source model must be defined';
|
47 | throw new InvalidRelationError(reason, relationMeta);
|
48 | }
|
49 |
|
50 | const targetModel = relationMeta.target();
|
51 | const targetName = targetModel.modelName;
|
52 | debug('Resolved model %s from given metadata: %o', targetName, targetModel);
|
53 |
|
54 | let keyFrom;
|
55 | if (
|
56 | relationMeta.keyFrom &&
|
57 | relationMeta.source.definition.properties[relationMeta.keyFrom]
|
58 | ) {
|
59 | keyFrom = relationMeta.keyFrom;
|
60 | } else {
|
61 | keyFrom = camelCase(targetName + '_id');
|
62 | }
|
63 |
|
64 | const targetProperties = targetModel.definition.properties;
|
65 | debug('relation metadata from %o: %o', targetName, targetProperties);
|
66 |
|
67 | let keyTo;
|
68 | if (relationMeta.keyTo && targetProperties[relationMeta.keyTo]) {
|
69 |
|
70 | keyTo = relationMeta.keyTo;
|
71 | } else {
|
72 | keyTo = targetModel.definition.idProperties()[0];
|
73 | if (!keyTo) {
|
74 | const reason = `${targetName} does not have any primary key (id property)`;
|
75 | throw new InvalidRelationError(reason, relationMeta);
|
76 | }
|
77 | }
|
78 |
|
79 | let polymorphic: false | {discriminator: string};
|
80 | if (
|
81 | relationMeta.polymorphic === undefined ||
|
82 | relationMeta.polymorphic === false ||
|
83 | !relationMeta.polymorphic
|
84 | ) {
|
85 | const polymorphicFalse = false as const;
|
86 | polymorphic = polymorphicFalse;
|
87 | } else {
|
88 | if (relationMeta.polymorphic === true) {
|
89 | const polymorphicObject: {discriminator: string} = {
|
90 | discriminator: camelCase(relationMeta.target().name + '_type'),
|
91 | };
|
92 | polymorphic = polymorphicObject;
|
93 | } else {
|
94 | const polymorphicObject: {discriminator: string} =
|
95 | relationMeta.polymorphic as {discriminator: string};
|
96 | polymorphic = polymorphicObject;
|
97 | }
|
98 | }
|
99 |
|
100 | return Object.assign(relationMeta, {
|
101 | keyFrom,
|
102 | keyTo: keyTo,
|
103 | polymorphic: polymorphic,
|
104 | });
|
105 | }
|