1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | Object.defineProperty(exports, "__esModule", { value: true });
|
7 | exports.createHasManyThroughInclusionResolver = void 0;
|
8 | const tslib_1 = require("tslib");
|
9 | const filter_1 = require("@loopback/filter");
|
10 | const debug_1 = tslib_1.__importDefault(require("debug"));
|
11 | const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
12 | const __1 = require("../..");
|
13 | const relation_helpers_1 = require("../relation.helpers");
|
14 | const has_many_through_helpers_1 = require("./has-many-through.helpers");
|
15 | const debug = (0, debug_1.default)('loopback:repository:relations:has-many-through:inclusion-resolver');
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | function createHasManyThroughInclusionResolver(meta, getThroughRepo, getTargetRepoDict) {
|
29 | const relationMeta = (0, has_many_through_helpers_1.resolveHasManyThroughMetadata)(meta);
|
30 | return async function fetchHasManyThroughModels(entities, inclusion, options) {
|
31 | var _a, _b;
|
32 | if (!relationMeta.through) {
|
33 | throw new Error(`relationMeta.through must be defined on ${relationMeta}`);
|
34 | }
|
35 | if (!entities.length)
|
36 | return [];
|
37 | debug('Fetching target models for entities:', entities);
|
38 | debug('Relation metadata:', relationMeta);
|
39 | const sourceKey = relationMeta.keyFrom;
|
40 | const sourceIds = entities.map(e => e[sourceKey]);
|
41 | const targetKey = relationMeta.keyTo;
|
42 | if (!relationMeta.through) {
|
43 | throw new Error(`relationMeta.through must be defined on ${relationMeta}`);
|
44 | }
|
45 | const throughKeyTo = relationMeta.through.keyTo;
|
46 | const throughKeyFrom = relationMeta.through.keyFrom;
|
47 | debug('Parameters:', {
|
48 | sourceKey,
|
49 | sourceIds,
|
50 | targetKey,
|
51 | throughKeyTo,
|
52 | throughKeyFrom,
|
53 | });
|
54 | debug('sourceId types', sourceIds.map(i => typeof i));
|
55 | const throughRepo = await getThroughRepo();
|
56 |
|
57 | const throughFound = await (0, relation_helpers_1.findByForeignKeys)(throughRepo, throughKeyFrom, sourceIds, {},
|
58 | options);
|
59 | const throughResult = (0, relation_helpers_1.flattenTargetsOfOneToManyRelation)(sourceIds, throughFound, throughKeyFrom);
|
60 | const scope = typeof inclusion === 'string'
|
61 | ? {}
|
62 | : inclusion.scope;
|
63 |
|
64 | const targetDiscriminator = relationMeta.through.polymorphic
|
65 | ? relationMeta.through.polymorphic.discriminator
|
66 | : undefined;
|
67 | if (targetDiscriminator) {
|
68 |
|
69 | const throughArrayByTargetType = {};
|
70 | for (const throughArray of throughResult) {
|
71 | if (throughArray) {
|
72 | for (const throughItem of throughArray) {
|
73 | const targetType = String(throughItem[targetDiscriminator]);
|
74 | if (!getTargetRepoDict[targetType]) {
|
75 | throw new __1.InvalidPolymorphismError(targetType, String(targetDiscriminator));
|
76 | }
|
77 | if (!throughArrayByTargetType[targetType]) {
|
78 | throughArrayByTargetType[targetType] = [];
|
79 | }
|
80 | throughArrayByTargetType[targetType].push(throughItem);
|
81 | }
|
82 | }
|
83 | }
|
84 |
|
85 | const targetOfTypes = {};
|
86 | for (const targetType of Object.keys(throughArrayByTargetType)) {
|
87 | const targetIds = throughArrayByTargetType[targetType].map(throughItem => throughItem[throughKeyTo]);
|
88 | const targetRepo = await getTargetRepoDict[targetType]();
|
89 | const targetEntityList = await (0, relation_helpers_1.findByForeignKeys)(targetRepo, targetKey, targetIds, scope, options);
|
90 | targetOfTypes[targetType] = targetEntityList;
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 | const allTargetsOfThrough = [];
|
111 | for (const throughArray of throughResult) {
|
112 | if (throughArray && throughArray.length > 0) {
|
113 | const currentTargetThroughArray = [];
|
114 | for (const throughItem of throughArray) {
|
115 | const itemToAdd = targetOfTypes[String(throughItem[targetDiscriminator])].shift();
|
116 | if (itemToAdd) {
|
117 | currentTargetThroughArray.push(itemToAdd);
|
118 | }
|
119 | }
|
120 | allTargetsOfThrough.push(currentTargetThroughArray);
|
121 | }
|
122 | else {
|
123 | allTargetsOfThrough.push(undefined);
|
124 | }
|
125 | }
|
126 | return allTargetsOfThrough;
|
127 | }
|
128 | else {
|
129 | const targetRepo = await getTargetRepoDict[relationMeta.target().name]();
|
130 | const result = [];
|
131 |
|
132 | const filterBuilder = new filter_1.FilterBuilder();
|
133 | const fieldFilter = filterBuilder.fields((_a = scope === null || scope === void 0 ? void 0 : scope.fields) !== null && _a !== void 0 ? _a : {}).filter
|
134 | .fields;
|
135 |
|
136 |
|
137 |
|
138 |
|
139 | const omitTargetKeyFromFields = (Object.values(fieldFilter).includes(true) &&
|
140 | fieldFilter[targetKey] !== true) ||
|
141 | fieldFilter[targetKey] === false;
|
142 | if (omitTargetKeyFromFields) {
|
143 | if (fieldFilter[targetKey] === false) {
|
144 |
|
145 | delete fieldFilter[targetKey];
|
146 | }
|
147 | else {
|
148 |
|
149 | fieldFilter[targetKey] = true;
|
150 | }
|
151 | }
|
152 |
|
153 | const allIds = lodash_1.default.uniq(throughResult
|
154 | .filter(throughEntitySet => throughEntitySet !== undefined)
|
155 | .map(throughEntitySet => throughEntitySet === null || throughEntitySet === void 0 ? void 0 : throughEntitySet.map(entity => entity[throughKeyTo]))
|
156 | .flat());
|
157 |
|
158 | const targetEntityList = await (0, relation_helpers_1.findByForeignKeys)(targetRepo, targetKey, allIds, { ...lodash_1.default.omit(scope !== null && scope !== void 0 ? scope : {}, ['limit', 'fields']), fields: fieldFilter }, {
|
159 | ...options,
|
160 | isThroughModelInclude: true,
|
161 | });
|
162 | const targetEntityIds = targetEntityList.map(targetEntity => { var _a, _b; return (_b = (_a = targetEntity[targetKey]) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : targetEntity[targetKey]; });
|
163 | const targetEntityMap = Object.fromEntries(targetEntityList.map(x => [
|
164 | x[targetKey],
|
165 | omitTargetKeyFromFields ? lodash_1.default.omit(x, [targetKey]) : x,
|
166 | ]));
|
167 |
|
168 | for (const entityList of throughResult) {
|
169 | if (entityList) {
|
170 | const relatedIds = entityList.map(x => { var _a, _b; return (_b = (_a = x[throughKeyTo]) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : x[throughKeyTo]; });
|
171 |
|
172 | const sortedIds = lodash_1.default.intersection(targetEntityIds, relatedIds).slice(0, (_b = scope === null || scope === void 0 ? void 0 : scope.limit) !== null && _b !== void 0 ? _b : entityList.length);
|
173 |
|
174 | result.push(lodash_1.default.cloneDeep(sortedIds.map(x => targetEntityMap[x])));
|
175 | }
|
176 | else {
|
177 |
|
178 | result.push(entityList);
|
179 | }
|
180 | }
|
181 | debug('fetchHasManyThroughModels result', result);
|
182 | return result;
|
183 | }
|
184 | };
|
185 | }
|
186 | exports.createHasManyThroughInclusionResolver = createHasManyThroughInclusionResolver;
|
187 |
|
\ | No newline at end of file |