UNPKG

popurelate

Version:

Easily populate and filter documents using data from related collections.

191 lines (190 loc) 7.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.copyChangingFields = exports.wrapPipeline = exports.createDefaultOptimizer = void 0; const const_1 = require("./const"); const decompose_1 = require("./decompose"); const deps_1 = require("./deps"); const is_1 = require("./is"); const recompose_1 = require("./recompose"); const reorder_1 = require("./reorder"); const { recalculateDependencies, releaseDependencies, markSameSetters } = deps_1.deps; const createDefaultOptimizer = (helpers) => (useOptimizer, options) => { const normalizedHelper = Object.assign(Object.assign({}, helpers), { pipelineIs: helpers.pipelineIs ? helpers.pipelineIs : is_1.defaultPipelineIs }); if (!useOptimizer && !hasExplicitelyTurnedOptimizer(options.pipelines)) { return options; } const optimizedPipelines = getOptimizedPipelines(useOptimizer, options.pipelines, normalizedHelper, createCounter(0)); return Object.assign(Object.assign({}, options), { pipelines: optimizedPipelines }); }; exports.createDefaultOptimizer = createDefaultOptimizer; const wrapPipeline = (pipeline, counter) => ({ id: counter.getId(), IAmDependedOnFields: new Set(), IAmChangingFields: null, cannotBeRemoved: isPipelineAbsolutelyNecessary(pipeline), partiallyUseOptimizer: hasExplicitelyTurnedOptimizer([pipeline]), IAmDependedOnPipelineIds: new Set(), pipelineIdsDepenedOnMe: new Set([const_1.FINAL_DOC_ID]), invisible: !!pipeline.invisible, sameSettersWith: new Set(), pipeline, }); exports.wrapPipeline = wrapPipeline; const copyChangingFields = (IAmChangingFields) => { if (!IAmChangingFields) return IAmChangingFields; const copied = Object.assign({}, IAmChangingFields); if (copied.isChangingEveryField) { copied.except = new Set(copied.except); } else { copied.fields = new Set(copied.fields); } return copied; }; exports.copyChangingFields = copyChangingFields; const getOptimizedPipelines = (useOptimizer, pipelines, helper, counter) => { const transformedPipelines = pipelines.map((pipeline) => exports.wrapPipeline(pipeline, counter)); normalizeUseOptimizers(useOptimizer, transformedPipelines); const usesOptimizer = transformedPipelines.some(e => e.useOptimizer || e.partiallyUseOptimizer); if (!usesOptimizer) pipelines; decompose_1.decomposePipelines(transformedPipelines, counter, helper); const finder = getFinder(transformedPipelines); setFields(transformedPipelines, helper); recalculateDependencies(transformedPipelines, finder, helper); markSameSetters(transformedPipelines); reorderAndMarkRemovable(transformedPipelines, finder, helper); removeRemovablePipelines(transformedPipelines, helper); // fullyLog(transformedPipelines); // fullyLog(transformedPipelines.map(e => e.pipeline)); recompose_1.recomposePipelines(transformedPipelines, finder); //, counter, helper, finder); // logPipelines(transformedPipelines); optimizeSubPipelines(transformedPipelines, counter, helper); return transformedPipelines.map(e => e.pipeline); }; const optimizeSubPipelines = (transformedPipelines, counter, helper) => { for (const each of transformedPipelines) { if (!each.removable && helper.pipelineIs.withCount(each.pipeline) && (each.useOptimizer || each.partiallyUseOptimizer)) { each.pipeline = Object.assign({}, each.pipeline); each.pipeline.docsPipelines = getOptimizedPipelines(each.useOptimizer, each.pipeline.docsPipelines, helper, counter); } } }; const reorderAndMarkRemovable = (transformedPipelines, finder, helper) => { let lastAffectedIndex = transformedPipelines.length; let hasRunOnce = false; let step = 0; const maxSteps = transformedPipelines.length * 2; while (lastAffectedIndex !== -1 && step <= maxSteps) { step++; lastAffectedIndex = releaseDependencies(transformedPipelines, finder, helper); lastAffectedIndex = reorder_1.reorderPipelines(transformedPipelines, hasRunOnce ? lastAffectedIndex : transformedPipelines.length, finder, helper); hasRunOnce = true; if (1 > 2) break; } if (step > maxSteps) { console.warn("QueryBuilder optimizer: Too much steps while reordering pipelines"); } }; const getFinder = (pipelines) => { const finder = {}; for (const each of pipelines) finder[each.id] = each; return finder; }; const normalizeUseOptimizers = (useOptimizer, pipeliles) => { const reversed = [...pipeliles].reverse(); const first = reversed.find(each => each.pipeline.invisible && each.pipeline.optimizer === true && typeof each.pipeline.useOptimizer === "boolean"); if (first && first.pipeline.invisible && first.pipeline.optimizer === true) { useOptimizer = first.pipeline.useOptimizer; } for (const each of reversed) { if (each.pipeline.invisible && each.pipeline.optimizer === true && typeof each.pipeline.useOptimizer === "boolean") { useOptimizer = each.pipeline.useOptimizer; } each.useOptimizer = useOptimizer; if (useOptimizer === true) { each.partiallyUseOptimizer = true; } } }; const setFields = (pipeliles, helper) => { for (const each of pipeliles) { let { IAmDependedOnFields, IAmChangingFields } = helper.getFieldsOfPipeline(each.pipeline, helper); if (IAmChangingFields && !IAmChangingFields.isChangingEveryField && IAmChangingFields.fields.size === 0) { IAmChangingFields = null; } each.IAmDependedOnFields = IAmDependedOnFields; each.IAmChangingFields = IAmChangingFields; } }; const isPipelineAbsolutelyNecessary = (pipeline) => { if (pipeline.count === true) return true; if (pipeline.withCount === true) return true; if (pipeline.rawPipeline !== undefined) return true; if (pipeline.limit !== undefined) return true; if (pipeline.skip !== undefined) return true; if (pipeline.query !== undefined) return true; return false; }; const removeRemovablePipelines = (pipeliles, helper) => { let removables = []; const is = helper.pipelineIs; for (const each of pipeliles) { if (each.removable) { removables.push(each); continue; } if (is.withCount(each.pipeline)) { each.pipeline.docsPipelines.unshift(...removables.map(e => e.pipeline)); } if (is.countLike(each.pipeline)) { removables = []; } } mutationFilter(pipeliles, each => !each.removable); }; const createCounter = (minCount = 0) => { let minId = minCount; return { getId: () => { minId++; return minId; }, }; }; const hasExplicitelyTurnedOptimizer = (pipelines) => { for (const pipeline of pipelines) { if (pipeline.invisible === true && pipeline.optimizer === true) { if (typeof pipeline.useOptimizer === "boolean") return true; } else if (pipeline.withCount && hasExplicitelyTurnedOptimizer(pipeline.docsPipelines)) { return true; } } return false; }; function mutationFilter(arr, cb) { for (let l = arr.length - 1; l >= 0; l -= 1) { if (!cb(arr[l])) arr.splice(l, 1); } }