🐛 Execute node also if it is a sibling but does not receive data

from parent
This commit is contained in:
Jan Oberhauser 2021-02-17 00:16:10 +01:00
parent caad6d1c8d
commit c811294612
2 changed files with 203 additions and 4 deletions

View file

@ -22,6 +22,8 @@ import {
NodeExecuteFunctions, NodeExecuteFunctions,
} from './'; } from './';
import { get } from 'lodash';
export class WorkflowExecute { export class WorkflowExecute {
runExecutionData: IRunExecutionData; runExecutionData: IRunExecutionData;
private additionalData: IWorkflowExecuteAdditionalData; private additionalData: IWorkflowExecuteAdditionalData;
@ -234,6 +236,21 @@ export class WorkflowExecute {
} }
/**
* Checks the incoming connection does not receive any data
*/
incomingConnectionIsEmpty(runData: IRunData, inputConnections: IConnection[], runIndex: number): boolean {
// for (const inputConnection of workflow.connectionsByDestinationNode[nodeToAdd].main[0]) {
for (const inputConnection of inputConnections) {
const nodeIncomingData = get(runData, `[${inputConnection.node}][${runIndex}].data.main[${inputConnection.index}]`);
if (nodeIncomingData !== undefined && (nodeIncomingData as object[]).length !== 0) {
return false;
}
}
return true;
}
addNodeToBeExecuted(workflow: Workflow, connectionData: IConnection, outputIndex: number, parentNodeName: string, nodeSuccessData: INodeExecutionData[][], runIndex: number): void { addNodeToBeExecuted(workflow: Workflow, connectionData: IConnection, outputIndex: number, parentNodeName: string, nodeSuccessData: INodeExecutionData[][], runIndex: number): void {
let stillDataMissing = false; let stillDataMissing = false;
@ -299,7 +316,7 @@ export class WorkflowExecute {
if (nodeWasWaiting === false) { if (nodeWasWaiting === false) {
// Get a list of all the output nodes that we can check for siblings eaiser // Get a list of all the output nodes that we can check for siblings easier
const checkOutputNodes = []; const checkOutputNodes = [];
for (const outputIndexParent in workflow.connectionsBySourceNode[parentNodeName].main) { for (const outputIndexParent in workflow.connectionsBySourceNode[parentNodeName].main) {
if (!workflow.connectionsBySourceNode[parentNodeName].main.hasOwnProperty(outputIndexParent)) { if (!workflow.connectionsBySourceNode[parentNodeName].main.hasOwnProperty(outputIndexParent)) {
@ -327,8 +344,12 @@ export class WorkflowExecute {
// previously processed one // previously processed one
if (inputData.node !== parentNodeName && checkOutputNodes.includes(inputData.node)) { if (inputData.node !== parentNodeName && checkOutputNodes.includes(inputData.node)) {
// So the parent node will be added anyway which // So the parent node will be added anyway which
// will then process this node next. So nothing to do. // will then process this node next. So nothing to do
continue; // unless the incoming data of the node is empty
// because then it would not be executed
if (!this.incomingConnectionIsEmpty(this.runExecutionData.resultData.runData, workflow.connectionsByDestinationNode[inputData.node].main[0], runIndex)) {
continue;
}
} }
// Check if it is already in the execution stack // Check if it is already in the execution stack
@ -384,7 +405,19 @@ export class WorkflowExecute {
continue; continue;
} }
if (workflow.connectionsByDestinationNode[nodeToAdd] === undefined) { let addEmptyItem = false;
if (workflow.connectionsByDestinationNode[nodeToAdd] === undefined) {
// Add empty item if the node does not have any input connections
addEmptyItem = true;
} else {
if (this.incomingConnectionIsEmpty(this.runExecutionData.resultData.runData, workflow.connectionsByDestinationNode[nodeToAdd].main[0], runIndex)) {
// Add empty item also if the input data is empty
addEmptyItem = true;
}
}
if (addEmptyItem === true) {
// Add only node if it does not have any inputs because else it will // Add only node if it does not have any inputs because else it will
// be added by its input node later anyway. // be added by its input node later anyway.
this.runExecutionData.executionData!.nodeExecutionStack.push( this.runExecutionData.executionData!.nodeExecutionStack.push(

View file

@ -986,6 +986,172 @@ describe('WorkflowExecute', () => {
}, },
}, },
}, },
{
description: 'should use empty data if input of sibling does not receive any data from parent',
input: {
// Leave the workflowData in regular JSON to be able to easily
// copy it from/in the UI
workflowData: {
"nodes": [
{
"parameters": {},
"name": "Start",
"type": "n8n-nodes-base.start",
"typeVersion": 1,
"position": [
250,
300,
],
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{$json[\"value1\"]}}",
"operation": "equal",
"value2": 1,
},
],
},
},
"name": "IF",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
650,
300,
],
},
{
"parameters": {
"values": {
"string": [],
"number": [
{
"name": "value2",
"value": 2,
},
],
},
"options": {},
},
"name": "Set2",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
850,
450,
],
},
{
"parameters": {
"values": {
"number": [
{
"name": "value1",
"value": 1,
},
],
},
"options": {},
},
"name": "Set1",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
450,
300,
],
},
{
"parameters": {},
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 1,
"position": [
1050,
300,
],
},
],
"connections": {
"Start": {
"main": [
[
{
"node": "Set1",
"type": "main",
"index": 0,
},
],
],
},
"IF": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0,
},
],
[
{
"node": "Set2",
"type": "main",
"index": 0,
},
],
],
},
"Set2": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1,
},
],
],
},
"Set1": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0,
},
],
],
},
},
},
},
output: {
nodeExecutionOrder: [
'Start',
'Set1',
'IF',
'Set2',
'Merge',
],
nodeData: {
Merge: [
[
{
value1: 1,
},
{
value2: 2,
},
],
],
},
},
},
]; ];