From a070922c2c2e6ab767b3bea30d7228a16648a7f1 Mon Sep 17 00:00:00 2001 From: Theodor Diaconu Date: Tue, 23 Oct 2018 10:35:12 +0300 Subject: [PATCH] Fixed #303 - Reducer inter-dependency computational rules --- lib/query/nodes/reducerNode.js | 1 + lib/query/reducers/lib/applyReducers.js | 35 ++++++++++++++++++++---- lib/query/reducers/lib/createReducers.js | 17 ++++++------ 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/lib/query/nodes/reducerNode.js b/lib/query/nodes/reducerNode.js index f0d2f26..3ecd5fd 100644 --- a/lib/query/nodes/reducerNode.js +++ b/lib/query/nodes/reducerNode.js @@ -3,6 +3,7 @@ export default class ReducerNode { this.name = name; this.body = body; this.reduceFunction = reduce; + this.dependencies = []; // This is a list of the reducer this reducer uses. } /** diff --git a/lib/query/reducers/lib/applyReducers.js b/lib/query/reducers/lib/applyReducers.js index 980692b..9398b85 100644 --- a/lib/query/reducers/lib/applyReducers.js +++ b/lib/query/reducers/lib/applyReducers.js @@ -3,9 +3,32 @@ export default function applyReducers(root, params) { applyReducers(node, params); }); - _.each(root.reducerNodes, reducerNode => { - root.results.forEach(result => { - reducerNode.compute(result, params); - }); - }); -} \ No newline at end of file + const processedReducers = []; + let reducersQueue = [...root.reducerNodes]; + + // TODO: find out if there's an infinite reducer inter-deendency + + while (reducersQueue.length) { + const reducerNode = reducersQueue.shift(); + + // If this reducer depends on other reducers + if (reducerNode.dependencies.length) { + // If there is an unprocessed reducer, move it at the end of the queue + const allDependenciesComputed = _.all(reducerNode.dependencies, dep => processedReducers.includes(dep)); + if (allDependenciesComputed) { + root.results.forEach(result => { + reducerNode.compute(result, params); + }); + processedReducers.push(reducerNode.name); + } else { + // Move it at the end of the queue + reducersQueue.push(reducerNode); + } + } else { + root.results.forEach(result => { + reducerNode.compute(result, params); + }); + processedReducers.push(reducerNode.name); + } + } +} diff --git a/lib/query/reducers/lib/createReducers.js b/lib/query/reducers/lib/createReducers.js index 9d72e9d..0522451 100644 --- a/lib/query/reducers/lib/createReducers.js +++ b/lib/query/reducers/lib/createReducers.js @@ -9,7 +9,7 @@ export default function addReducers(root) { // we add reducers last, after we have added all the fields. root.reducerNodes.forEach(reducer => { _.each(reducer.body, (body, fieldName) => { - handleAddElement(root, fieldName, body); + handleAddElement(reducer, root, fieldName, body); }) }); } @@ -19,7 +19,7 @@ export default function addReducers(root) { * @param fieldName * @param body */ -export function handleAddElement(root, fieldName, body) { +export function handleAddElement(reducerNode, root, fieldName, body) { // if it's a link const collection = root.collection; const linker = collection.getLinker(fieldName); @@ -29,6 +29,7 @@ export function handleAddElement(root, fieldName, body) { const reducer = collection.getReducer(fieldName); if (reducer) { + reducerNode.dependencies.push(fieldName); return handleAddReducer(fieldName, reducer, root); } @@ -41,14 +42,14 @@ export function handleAddElement(root, fieldName, body) { * @param reducer * @param root */ -export function handleAddReducer(fieldName, reducer, root) { +export function handleAddReducer(fieldName, {body, reduce}, root) { if (!root.hasReducerNode(fieldName)) { - let reducerNode = new ReducerNode(fieldName, reducer); - root.add(reducerNode); - reducerNode.scheduledForDeletion = true; + let childReducerNode = new ReducerNode(fieldName, {body, reduce}); + root.add(childReducerNode); + childReducerNode.scheduledForDeletion = true; - _.each(reducer.body, (body, fieldName) => { - handleAddElement(root, fieldName, body); + _.each(childReducerNode.body, (body, fieldName) => { + handleAddElement(childReducerNode, root, fieldName, body); }) } }