import { filter, includes, some, } from 'lodash/fp'; import { getAllIdsIterator } from '../indexing/allIds'; import { getFlattenedHierarchy, getRecordNodeById, getNode, isIndex, isRecord, getAllowedRecordNodesForIndex, fieldReversesReferenceToIndex, } from '../templateApi/hierarchy'; import { joinKey, apiWrapper, events, $ } from '../common'; import { createBuildIndexFolder, transactionForBuildIndex, } from '../transactions/create'; import { permission } from '../authApi/permissions'; import { BadRequestError } from '../common/errors'; /** rebuilds an index * @param {object} app - the application container * @param {string} indexNodeKey - node key of the index, which the index belongs to */ export const buildIndex = app => async indexNodeKey => apiWrapper( app, events.indexApi.buildIndex, permission.manageIndex.isAuthorized, { indexNodeKey }, _buildIndex, app, indexNodeKey, ); const _buildIndex = async (app, indexNodeKey) => { const indexNode = getNode(app.hierarchy, indexNodeKey); await createBuildIndexFolder(app.datastore, indexNodeKey); if (!isIndex(indexNode)) { throw new BadRequestError('BuildIndex: must supply an indexnode'); } if (indexNode.indexType === 'reference') { await buildReverseReferenceIndex( app, indexNode, ); } else { await buildHeirarchalIndex( app, indexNode, ); } await app.cleanupTransactions(); }; const buildReverseReferenceIndex = async (app, indexNode) => { // Iterate through all referencING records, // and update referenced index for each record let recordCount = 0; const referencingNodes = $(app.hierarchy, [ getFlattenedHierarchy, filter(n => isRecord(n) && some(fieldReversesReferenceToIndex(indexNode))(n.fields)), ]); const createTransactionsForReferencingNode = async (referencingNode) => { const iterateReferencingNodes = await getAllIdsIterator(app)(referencingNode.collectionNodeKey()); let referencingIdIterator = await iterateReferencingNodes(); while (!referencingIdIterator.done) { const { result } = referencingIdIterator; for (const id of result.ids) { const recordKey = joinKey(result.collectionKey, id); await transactionForBuildIndex(app, indexNode.nodeKey(), recordKey, recordCount); recordCount++; } referencingIdIterator = await iterateReferencingNodes(); } }; for (const referencingNode of referencingNodes) { await createTransactionsForReferencingNode(referencingNode); } }; /* const getAllowedParentCollectionNodes = (hierarchy, indexNode) => $(getAllowedRecordNodesForIndex(hierarchy, indexNode), [ map(n => n.parent()), ]); */ const buildHeirarchalIndex = async (app, indexNode) => { let recordCount = 0; const createTransactionsForIds = async (collectionKey, ids) => { for (const recordId of ids) { const recordKey = joinKey(collectionKey, recordId); const recordNode = getRecordNodeById( app.hierarchy, recordId, ); if (recordNodeApplies(indexNode)(recordNode)) { await transactionForBuildIndex( app, indexNode.nodeKey(), recordKey, recordCount, ); recordCount++; } } }; const collectionRecords = getAllowedRecordNodesForIndex(app.hierarchy, indexNode); for (const targetCollectionRecordNode of collectionRecords) { const allIdsIterator = await getAllIdsIterator(app)(targetCollectionRecordNode.collectionNodeKey()); let allIds = await allIdsIterator(); while (allIds.done === false) { await createTransactionsForIds( allIds.result.collectionKey, allIds.result.ids, ); allIds = await allIdsIterator(); } } return recordCount; }; // const chooseChildRecordNodeByKey = (collectionNode, recordId) => find(c => recordId.startsWith(c.nodeId))(collectionNode.children); const recordNodeApplies = indexNode => recordNode => includes(recordNode.nodeId)(indexNode.allowedRecordNodeIds); /* const hasApplicableDecendant = (hierarchy, ancestorNode, indexNode) => $(hierarchy, [ getFlattenedHierarchy, filter( allTrue( isRecord, isDecendant(ancestorNode), recordNodeApplies(indexNode), ), ), ]); */ /* const applyAllDecendantRecords = async (app, collection_Key_or_NodeKey, indexNode, indexKey, currentIndexedData, currentIndexedDataKey, recordCount = 0) => { const collectionNode = getCollectionNodeByKeyOrNodeKey( app.hierarchy, collection_Key_or_NodeKey, ); const allIdsIterator = await getAllIdsIterator(app)(collection_Key_or_NodeKey); const createTransactionsForIds = async (collectionKey, allIds) => { for (const recordId of allIds) { const recordKey = joinKey(collectionKey, recordId); const recordNode = chooseChildRecordNodeByKey( collectionNode, recordId, ); if (recordNodeApplies(indexNode)(recordNode)) { await transactionForBuildIndex( app, indexNode.nodeKey(), recordKey, recordCount, ); recordCount++; } if (hasApplicableDecendant(app.hierarchy, recordNode, indexNode)) { for (const childCollectionNode of recordNode.children) { recordCount = await applyAllDecendantRecords( app, joinKey(recordKey, childCollectionNode.collectionName), indexNode, indexKey, currentIndexedData, currentIndexedDataKey, recordCount, ); } } } }; let allIds = await allIdsIterator(); while (allIds.done === false) { await createTransactionsForIds( allIds.result.collectionKey, allIds.result.ids, ); allIds = await allIdsIterator(); } return recordCount; }; */ export default buildIndex;