"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAllRelatedAssets = getAllRelatedAssets; var _lodash = require("lodash"); var _get_assets = require("./get_assets"); var _get_related_assets = require("./get_related_assets"); var _errors = require("./errors"); var _utils = require("./utils"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ async function getAllRelatedAssets(esClient, options) { // How to put size into this? const { ean, from, to, relation, maxDistance, type = [] } = options; const primary = await findPrimary(esClient, { ean, from, to }); let assetsToFetch = [primary]; let currentDistance = 1; const relatedAssets = []; while (currentDistance <= maxDistance) { const queryOptions = { relation, from, to, visitedEans: [primary['asset.ean'], ...relatedAssets.map(asset => asset['asset.ean'])] }; // if we enforce the type filter before the last query we'll miss nodes with // possible edges to the requested types if (currentDistance === maxDistance && type.length) { queryOptions.type = type; } const results = (0, _lodash.flatten)(await Promise.all(assetsToFetch.map(asset => findRelatedAssets(esClient, asset, queryOptions)))); if (results.length === 0) { break; } relatedAssets.push(...results.map(withDistance(currentDistance))); assetsToFetch = results; currentDistance++; } return { primary, [relation]: type.length ? relatedAssets.filter(asset => type.includes(asset['asset.type'])) : relatedAssets }; } async function findPrimary(esClient, { ean, from, to }) { const primaryResults = await (0, _get_assets.getAssets)({ esClient, size: 1, filters: { ean, from, to } }); if (primaryResults.length === 0) { throw new _errors.AssetNotFoundError(ean); } if (primaryResults.length > 1) { throw new Error(`Illegal state: Found more than one asset with the same ean (ean=${ean}).`); } return primaryResults[0]; } async function findRelatedAssets(esClient, primary, { relation, from, to, type, visitedEans }) { const relationField = relationToDirectField(relation); const directlyRelatedEans = (0, _utils.toArray)(primary[relationField]); let directlyRelatedAssets = []; if (directlyRelatedEans.length) { // get the directly related assets we haven't visited already directlyRelatedAssets = await (0, _get_assets.getAssets)({ esClient, filters: { ean: (0, _lodash.without)(directlyRelatedEans, ...visitedEans), from, to, type } }); } const indirectlyRelatedAssets = await (0, _get_related_assets.getRelatedAssets)({ esClient, ean: primary['asset.ean'], excludeEans: visitedEans.concat(directlyRelatedEans), relation, from, to, type }); return [...directlyRelatedAssets, ...indirectlyRelatedAssets]; } function relationToDirectField(relation) { if (relation === 'ancestors') { return 'asset.parents'; } else if (relation === 'descendants') { return 'asset.children'; } else { return 'asset.references'; } } function withDistance(distance) { return asset => ({ ...asset, distance }); }