popurelate
Version:
Easily populate and filter documents using data from related collections.
284 lines (283 loc) • 10.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.deps = void 0;
const path_1 = require("../path");
const const_1 = require("./const");
const addDependenciesIf = (each, startIndex, pipelines, finder, dependenceCheckFn) => {
for (let i = startIndex; i < pipelines.length; ++i) {
const second = pipelines[i];
const isDepended = Array.isArray(dependenceCheckFn)
? dependenceCheckFn.some(fn => fn(second.pipeline))
: dependenceCheckFn(second.pipeline);
if (isDepended) {
pairDependence(each.id, second.id, finder);
}
}
};
const updateDependency = (pipelines, index, finder) => {
const primary = pipelines[index];
if (primary.removable)
return;
for (let j = index + 1; j < pipelines.length; j++) {
const secondary = pipelines[j];
if (secondary.removable)
continue;
if (isDependedOnMe(primary, secondary)) {
pairDependence(primary.id, secondary.id, finder);
break;
}
}
};
const updatePredefinedDependency = (wrappedPipeliles, i, finder, helper) => {
const is = helper.pipelineIs;
const each = wrappedPipeliles[i];
if (is.changingCountOrOrder(each.pipeline)) {
addDependenciesIf(each, i + 1, wrappedPipeliles, finder, is.orderAndCountImportant);
}
if (is.orderAndCountImportant(each.pipeline)) {
addDependenciesIf(each, i + 1, wrappedPipeliles, finder, is.changingCountOrOrder);
}
};
const isDependedOnMe = (primary, secondary) => {
const IAmChanging = primary.IAmChangingFields;
const dependency = secondary.IAmDependedOnFields;
if (!IAmChanging)
return false;
if (!IAmChanging.isChangingEveryField) {
for (const field of IAmChanging.fields) {
for (const depField of dependency) {
if (path_1.isSubPathOf(field, depField) || path_1.isSubPathOf(depField, field)) {
return true;
}
}
}
return false;
}
for (const field of IAmChanging.except) {
for (const depField of dependency) {
if (!path_1.isSubPathOf(field, depField))
return true;
}
}
return false;
};
const pairDependence = (mainId, depenedOnMeId, finder) => {
const main = finder[mainId];
if (main) {
main.pipelineIdsDepenedOnMe.add(depenedOnMeId);
main.removable = false;
}
const depenedOnMe = finder[depenedOnMeId];
if (depenedOnMe) {
depenedOnMe.IAmDependedOnPipelineIds.add(mainId);
}
};
const releaseDependencies = (pipelines, finder, helper) => {
let lastAffectedIndex = -1;
const is = helper.pipelineIs;
for (let i = 0; i < pipelines.length; ++i) {
const each = pipelines[i];
if (isMarkedRemovable(each))
continue;
if (is.countLike(each.pipeline)) {
const changed = releaseCountlikeDependencies(i, pipelines, finder, helper);
if (changed)
lastAffectedIndex = i;
}
if (is.skip(each.pipeline) && each.pipeline.skip === 0) {
markRemovable(each.id, finder);
lastAffectedIndex = i;
}
}
const index = releaseNonusableSetters(pipelines, finder, helper);
lastAffectedIndex = Math.max(lastAffectedIndex, index);
if (lastAffectedIndex !== -1) {
recalculateDependencies(pipelines, finder, helper);
}
return lastAffectedIndex;
};
const releaseNonusableSetters = (pipelines, finder, helper) => {
let lastAffectedIndex = -1;
const is = helper.pipelineIs;
for (let i = 0; i < pipelines.length; ++i) {
const each = pipelines[i];
if (isMarkedRemovable(each) ||
!each.IAmChangingFields ||
each.IAmChangingFields.isChangingEveryField) {
continue;
}
if (is.rawPipeline(each.pipeline) ||
is.changingCountOrOrder(each.pipeline)) {
continue;
}
// console.log("---", "\n", each.pipeline, "\n", "---");
const changingFields = each.IAmChangingFields.fields;
const willBeNeglectedFields = getNeglectedFields(i, pipelines, changingFields);
if (willBeNeglectedFields.size === changingFields.size) {
markRemovable(each.id, finder);
lastAffectedIndex = i;
}
// console.log("\n\n\n\n");
}
return lastAffectedIndex;
};
const getNeglectedFields = (myIndex, pipelines, changingFieldsOriginal) => {
const changingFields = new Set(changingFieldsOriginal);
const neglectedFields = new Set();
for (let i = myIndex + 1; i < pipelines.length; ++i) {
const secondaryPipeline = pipelines[i];
let recentlyNeglected = new Set();
if (secondaryPipeline.IAmChangingFields) {
({ recentlyNeglected } = getNegligenceInfo(changingFields, secondaryPipeline.IAmChangingFields, neglectedFields));
}
for (const field of secondaryPipeline.IAmDependedOnFields) {
for (const myField of changingFields) {
if (path_1.isSubPathOf(field, myField) || path_1.isSubPathOf(myField, field)) {
neglectedFields.delete(myField);
changingFields.delete(myField);
}
}
}
for (const field of recentlyNeglected) {
changingFields.delete(field);
}
if (changingFields.size === 0)
break;
}
return neglectedFields;
};
const getNegligenceInfo = (myChangingFields, secondaryChanging, neglectedFields = new Set()) => {
const recentlyNeglected = new Set();
if (secondaryChanging && !secondaryChanging.isChangingEveryField) {
for (const field of secondaryChanging.fields) {
for (const myField of myChangingFields) {
if (path_1.isSubPathOf(field, myField)) {
neglectedFields.add(myField);
recentlyNeglected.add(myField);
}
}
}
}
if (secondaryChanging && secondaryChanging.isChangingEveryField) {
for (const myField of myChangingFields) {
for (const field of secondaryChanging.except) {
if (!path_1.isSubPathOf(field, myField)) {
neglectedFields.add(myField);
recentlyNeglected.add(myField);
}
}
}
}
return { neglectedFields, recentlyNeglected };
};
const releaseCountlikeDependencies = (myIndex, pipelines, finder, helper) => {
let hasAffected = false;
const is = helper.pipelineIs;
for (let i = myIndex - 1; i >= 0; --i) {
const each = pipelines[i];
if (isMarkedRemovable(each))
continue;
if (!is.changingDocCount(each.pipeline)) {
markRemovable(each.id, finder);
hasAffected = true;
}
else
break;
}
return hasAffected;
};
const removeDependency = (from, to, finder) => {
const me = finder[from];
if (me) {
me.IAmDependedOnPipelineIds.delete(to);
}
const second = finder[to];
if (second) {
second.pipelineIdsDepenedOnMe.delete(from);
if (second.pipelineIdsDepenedOnMe.size === 0 && !second.cannotBeRemoved) {
second.removable = true;
}
}
};
const markRemovable = (id, finder) => {
console.trace("=========remove id=======", id);
const me = finder[id];
if (!me)
return;
for (const from of me.pipelineIdsDepenedOnMe) {
removeDependency(from, id, finder);
}
};
const isMarkedRemovable = (pipeline) => !!pipeline.removable;
const addRelations = (wrappedPipeliles, finder, helper) => {
for (let i = 0; i < wrappedPipeliles.length; ++i) {
updatePredefinedDependency(wrappedPipeliles, i, finder, helper);
updateDependency(wrappedPipeliles, i, finder);
}
};
const resetDependencies = (wrappedPipeliles) => {
// requires all pipelines. Don not pass slice of it
for (let i = 0; i < wrappedPipeliles.length; ++i) {
const each = wrappedPipeliles[i];
const isFinalDocDepened = each.pipelineIdsDepenedOnMe.has(const_1.FINAL_DOC_ID);
each.pipelineIdsDepenedOnMe = new Set();
each.IAmDependedOnPipelineIds = new Set();
each.removable = true;
if (isFinalDocDepened) {
each.removable = false;
each.pipelineIdsDepenedOnMe.add(const_1.FINAL_DOC_ID);
}
}
};
const recalculateDependencies = (wrappedPipeliles, finder, helper) => {
resetDependencies(wrappedPipeliles);
addRelations(wrappedPipeliles, finder, helper);
};
const transferDependences = (from, to, finder) => {
const fromInfo = finder[from];
if (!fromInfo)
return;
const toInfo = finder[to];
if (!toInfo)
return;
for (const pipelineId of fromInfo.IAmDependedOnPipelineIds) {
removeDependency(from, pipelineId, finder);
pairDependence(pipelineId, to, finder);
}
for (const pipelineId of fromInfo.pipelineIdsDepenedOnMe) {
removeDependency(pipelineId, from, finder);
pairDependence(to, pipelineId, finder);
}
};
const markSameSetters = (pipelines) => {
for (let i = 0; i < pipelines.length; ++i) {
const first = pipelines[i];
for (let j = i + 1; j < pipelines.length; ++j) {
const second = pipelines[j];
if (areChangingSameThings(first.IAmChangingFields, second.IAmChangingFields)) {
first.sameSettersWith.add(second.id);
second.sameSettersWith.add(first.id);
}
}
}
};
const areChangingSameThings = (ch1, ch2) => {
if (!ch1 || !ch2)
return false;
if (!ch1.isChangingEveryField) {
const { neglectedFields } = getNegligenceInfo(new Set(ch1.fields), ch2);
return neglectedFields.size > 0;
}
if (!ch2.isChangingEveryField) {
const { neglectedFields } = getNegligenceInfo(new Set(ch2.fields), ch1);
return neglectedFields.size > 0;
}
return true;
};
exports.deps = {
releaseDependencies,
addRelations,
transferDependences,
markSameSetters,
recalculateDependencies,
};