1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import debugFactory from 'debug';
|
7 | import {DataObject} from '../../common-types';
|
8 | import {Entity} from '../../model';
|
9 | import {EntityCrudRepository} from '../../repositories/repository';
|
10 | import {
|
11 | BelongsToDefinition,
|
12 | Getter,
|
13 | InclusionResolver,
|
14 | } from '../relation.types';
|
15 | import {resolveBelongsToMetadata} from './belongs-to.helpers';
|
16 | import {createBelongsToInclusionResolver} from './belongs-to.inclusion-resolver';
|
17 | import {DefaultBelongsToRepository} from './belongs-to.repository';
|
18 |
|
19 | const debug = debugFactory('loopback:repository:relations:belongs-to:accessor');
|
20 |
|
21 | export interface BelongsToAccessor<Target extends Entity, SourceId> {
|
22 | |
23 |
|
24 |
|
25 | (sourceId: SourceId, polymorphicTypes?: string | string[]): Promise<Target>;
|
26 |
|
27 | |
28 |
|
29 |
|
30 | inclusionResolver: InclusionResolver<Entity, Target>;
|
31 | }
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | export function createBelongsToAccessor<
|
39 | Target extends Entity,
|
40 | TargetId,
|
41 | Source extends Entity,
|
42 | SourceId,
|
43 | >(
|
44 | belongsToMetadata: BelongsToDefinition,
|
45 | targetRepositoryGetter:
|
46 | | Getter<EntityCrudRepository<Target, TargetId>>
|
47 | | {
|
48 | [repoType: string]: Getter<EntityCrudRepository<Target, TargetId>>;
|
49 | },
|
50 | sourceRepository: EntityCrudRepository<Source, SourceId>,
|
51 | ): BelongsToAccessor<Target, SourceId> {
|
52 | const meta = resolveBelongsToMetadata(belongsToMetadata);
|
53 |
|
54 | if (typeof targetRepositoryGetter === 'function') {
|
55 | targetRepositoryGetter = {
|
56 | [meta.target().name]: targetRepositoryGetter as Getter<
|
57 | EntityCrudRepository<Target, TargetId>
|
58 | >,
|
59 | };
|
60 | }
|
61 | debug('Resolved BelongsTo relation metadata: %o', meta);
|
62 | const result: BelongsToAccessor<Target, SourceId> =
|
63 | async function getTargetInstanceOfBelongsTo(
|
64 | sourceId: SourceId,
|
65 | polymorphicTypes?: string | string[],
|
66 | ) {
|
67 | if (meta.polymorphic !== false) {
|
68 | if (!polymorphicTypes || polymorphicTypes.length === 0) {
|
69 | console.warn(
|
70 | 'It is highly recommended to specify the polymorphicTypes param when using polymorphic types.',
|
71 | );
|
72 | }
|
73 | }
|
74 | const foreignKey = meta.keyFrom;
|
75 | const primaryKey = meta.keyTo;
|
76 | const sourceModel = await sourceRepository.findById(sourceId);
|
77 | const foreignKeyValue = sourceModel[foreignKey as keyof Source];
|
78 |
|
79 |
|
80 |
|
81 | if (!foreignKeyValue) {
|
82 | return undefined as unknown as Target;
|
83 | }
|
84 |
|
85 | const constraint: any = {[primaryKey]: foreignKeyValue};
|
86 | const constrainedRepo = new DefaultBelongsToRepository(
|
87 | targetRepositoryGetter as {
|
88 | [repoType: string]: Getter<EntityCrudRepository<Target, TargetId>>;
|
89 | },
|
90 | constraint as DataObject<Target>,
|
91 | belongsToMetadata.target,
|
92 | );
|
93 | return constrainedRepo.get({polymorphicType: polymorphicTypes});
|
94 | };
|
95 |
|
96 | result.inclusionResolver = createBelongsToInclusionResolver(
|
97 | meta,
|
98 | targetRepositoryGetter as {
|
99 | [repoType: string]: Getter<EntityCrudRepository<Target, TargetId>>;
|
100 | },
|
101 | );
|
102 | return result;
|
103 | }
|