UNPKG

@loopback/repository

Version:

Define and implement a common set of interfaces for interacting with databases

110 lines 5.47 kB
"use strict"; // Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved. // Node module: @loopback/repository // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT Object.defineProperty(exports, "__esModule", { value: true }); exports.createHasOneInclusionResolver = void 0; const lodash_1 = require("lodash"); const __1 = require("../../"); const relation_helpers_1 = require("../relation.helpers"); const has_one_helpers_1 = require("./has-one.helpers"); /** * Creates InclusionResolver for HasOne relation. * Notice that this function only generates the inclusionResolver. * It doesn't register it for the source repository. * * Notice: scope field for inclusion is not supported yet. * * @param meta - resolved HasOneMetadata * @param getTargetRepoDict - dictionary of target model type - target repository * i.e where related instances for different types are */ function createHasOneInclusionResolver(meta, getTargetRepoDict) { const relationMeta = (0, has_one_helpers_1.resolveHasOneMetadata)(meta); return async function fetchHasOneModel(entities, inclusion, options) { if (!entities.length) return []; // Source ids are grouped by their target polymorphic types // Each type search for target instances and then merge together in a merge-sort-like manner const sourceKey = relationMeta.keyFrom; const targetKey = relationMeta.keyTo; const targetDiscriminator = relationMeta.polymorphic ? relationMeta.polymorphic.discriminator : undefined; const scope = typeof inclusion === 'string' ? {} : inclusion.scope; // sourceIds in {targetType -> sourceId} const sourceIdsCategorized = {}; if (targetDiscriminator) { entities.forEach((value, index, allEntites) => { const concreteType = String(value[targetDiscriminator]); if (!getTargetRepoDict[concreteType]) { throw new __1.InvalidPolymorphismError(concreteType, targetDiscriminator); } if (!sourceIdsCategorized[concreteType]) { sourceIdsCategorized[concreteType] = []; } sourceIdsCategorized[concreteType].push(value[sourceKey]); }); } else { const concreteType = relationMeta.target().name; if (!getTargetRepoDict[concreteType]) { throw new __1.InvalidPolymorphismError(concreteType); } entities.forEach((value, index, allEntites) => { if (!sourceIdsCategorized[concreteType]) { sourceIdsCategorized[concreteType] = []; } sourceIdsCategorized[concreteType].push(value[sourceKey]); }); } // Ensure targetKey is included otherwise flatten function cannot work const changedTargetKeyField = (0, __1.includeFieldIfNot)(scope === null || scope === void 0 ? void 0 : scope.fields, targetKey); let needToRemoveTargetKeyFieldLater = false; if (changedTargetKeyField !== false) { scope.fields = changedTargetKeyField; needToRemoveTargetKeyFieldLater = true; } // Each sourceIds array with same target type extract target instances const targetCategorized = {}; for (const k of Object.keys(sourceIdsCategorized)) { const targetRepo = await getTargetRepoDict[k](); const targetsFound = await (0, relation_helpers_1.findByForeignKeys)(targetRepo, targetKey, sourceIdsCategorized[k], scope, Object.assign((0, lodash_1.cloneDeep)(options !== null && options !== void 0 ? options : {}), { polymorphicType: k })); targetCategorized[k] = (0, relation_helpers_1.flattenTargetsOfOneToOneRelation)(sourceIdsCategorized[k], targetsFound, targetKey); // Remove targetKey if should be excluded but included above if (needToRemoveTargetKeyFieldLater) { targetCategorized[k] = targetCategorized[k].map(e => { if (e) { delete e[targetKey]; } return e; }); } } // Merge // Why the order is correct: // e.g. target model 1 = a, target model 2 = b // all entities: [S(a-1), S(a-2), S(b-3), S(a-4), S(b-5)] // a-result: [a-1, a-2, a-4] // b-result: [b-3, b-4] // merged: // entities[1]->a => targets: [a-1 from a-result.shift()] // entities[2]->a => targets: [a-1, a-2 from a-result.shift()] // entities[3]->b => targets: [a-1, a-2, b-3 from b-result.shift()] // entities[4]->a => targets: [a-1, a-2, b-3, a-4 from a-result.shift()] // entities[5]->b => targets: [a-1, a-2, b-3, a-4, b-5 from b-result.shift()] if (targetDiscriminator) { const allTargets = []; entities.forEach((value, index, allEntites) => { allTargets.push(targetCategorized[String(value[targetDiscriminator])].shift()); }); return allTargets; } else { return targetCategorized[relationMeta.target().name]; } }; } exports.createHasOneInclusionResolver = createHasOneInclusionResolver; //# sourceMappingURL=has-one.inclusion-resolver.js.map