mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
fix(core): Remove run data of utility nodes for partial executions v2 (#12673)
This commit is contained in:
parent
2f81b29d34
commit
b66a9dc8fb
|
@ -1,4 +1,15 @@
|
|||
import type { IRunData } from 'n8n-workflow';
|
||||
// NOTE: Diagrams in this file have been created with https://asciiflow.com/#/
|
||||
// If you update the tests, please update the diagrams as well.
|
||||
// If you add a test, please create a new diagram.
|
||||
//
|
||||
// Map
|
||||
// 0 means the output has no run data
|
||||
// 1 means the output has run data
|
||||
// ►► denotes the node that the user wants to execute to
|
||||
// XX denotes that the node is disabled
|
||||
// PD denotes that the node has pinned data
|
||||
|
||||
import { NodeConnectionType, type IRunData } from 'n8n-workflow';
|
||||
|
||||
import { createNodeData, toITaskData } from './helpers';
|
||||
import { cleanRunData } from '../clean-run-data';
|
||||
|
@ -111,4 +122,73 @@ describe('cleanRunData', () => {
|
|||
[node1.name]: [toITaskData([{ data: { value: 1 } }])],
|
||||
});
|
||||
});
|
||||
|
||||
// ┌─────┐ ┌────────┐
|
||||
// │node1├─────►rootNode│
|
||||
// └─────┘ └───▲────┘
|
||||
// │
|
||||
// ┌───┴───┐
|
||||
// │subNode│
|
||||
// └───────┘
|
||||
test('removes run data of sub nodes when the start node is a root node', () => {
|
||||
// ARRANGE
|
||||
const node1 = createNodeData({ name: 'Node1' });
|
||||
const rootNode = createNodeData({ name: 'Root Node' });
|
||||
const subNode = createNodeData({ name: 'Sub Node' });
|
||||
const graph = new DirectedGraph()
|
||||
.addNodes(node1, rootNode, subNode)
|
||||
.addConnections(
|
||||
{ from: node1, to: rootNode },
|
||||
{ from: subNode, to: rootNode, type: NodeConnectionType.AiLanguageModel },
|
||||
);
|
||||
const runData: IRunData = {
|
||||
[node1.name]: [toITaskData([{ data: { value: 1 } }])],
|
||||
[rootNode.name]: [toITaskData([{ data: { value: 2 } }])],
|
||||
[subNode.name]: [toITaskData([{ data: { value: 3 } }])],
|
||||
};
|
||||
|
||||
// ACT
|
||||
const newRunData = cleanRunData(runData, graph, new Set([rootNode]));
|
||||
|
||||
// ASSERT
|
||||
expect(newRunData).toEqual({
|
||||
[node1.name]: [toITaskData([{ data: { value: 1 } }])],
|
||||
});
|
||||
});
|
||||
|
||||
// ┌─────┐ ┌─────┐ ┌────────┐
|
||||
// │node1├───►node2├────►rootNode│
|
||||
// └─────┘ └─────┘ └───▲────┘
|
||||
// │
|
||||
// ┌───┴───┐
|
||||
// │subNode│
|
||||
// └───────┘
|
||||
test('removes run data of sub nodes for root nodes downstream of the start node', () => {
|
||||
// ARRANGE
|
||||
const node1 = createNodeData({ name: 'Node1' });
|
||||
const node2 = createNodeData({ name: 'Node2' });
|
||||
const rootNode = createNodeData({ name: 'Root Node' });
|
||||
const subNode = createNodeData({ name: 'Sub Node' });
|
||||
const graph = new DirectedGraph()
|
||||
.addNodes(node1, node2, rootNode, subNode)
|
||||
.addConnections(
|
||||
{ from: node1, to: node2 },
|
||||
{ from: node2, to: rootNode },
|
||||
{ from: subNode, to: rootNode, type: NodeConnectionType.AiLanguageModel },
|
||||
);
|
||||
const runData: IRunData = {
|
||||
[node1.name]: [toITaskData([{ data: { value: 1 } }])],
|
||||
[node2.name]: [toITaskData([{ data: { value: 1 } }])],
|
||||
[rootNode.name]: [toITaskData([{ data: { value: 2 } }])],
|
||||
[subNode.name]: [toITaskData([{ data: { value: 3 } }])],
|
||||
};
|
||||
|
||||
// ACT
|
||||
const newRunData = cleanRunData(runData, graph, new Set([node2]));
|
||||
|
||||
// ASSERT
|
||||
expect(newRunData).toEqual({
|
||||
[node1.name]: [toITaskData([{ data: { value: 1 } }])],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { INode, IRunData } from 'n8n-workflow';
|
||||
import { NodeConnectionType, type INode, type IRunData } from 'n8n-workflow';
|
||||
|
||||
import type { DirectedGraph } from './directed-graph';
|
||||
|
||||
|
@ -16,10 +16,22 @@ export function cleanRunData(
|
|||
|
||||
for (const startNode of startNodes) {
|
||||
delete newRunData[startNode.name];
|
||||
const children = graph.getChildren(startNode);
|
||||
|
||||
for (const child of children) {
|
||||
delete newRunData[child.name];
|
||||
const children = graph.getChildren(startNode);
|
||||
for (const node of [startNode, ...children]) {
|
||||
delete newRunData[node.name];
|
||||
|
||||
// Delete runData for subNodes
|
||||
const subNodeConnections = graph.getParentConnections(node);
|
||||
for (const subNodeConnection of subNodeConnections) {
|
||||
// Sub nodes never use the Main connection type, so this filters our
|
||||
// the connection that goes upstream of the startNode.
|
||||
if (subNodeConnection.type === NodeConnectionType.Main) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete newRunData[subNodeConnection.from.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue