popurelate
Version:
Easily populate and filter documents using data from related collections.
191 lines (190 loc) • 7.74 kB
JavaScript
;
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);
}
}