Add $items to expression and Function-Nodes to get all items

This commit is contained in:
Jan Oberhauser 2020-04-12 18:42:29 +02:00
parent 135e467be9
commit 09e528565f
4 changed files with 114 additions and 50 deletions

View file

@ -48,11 +48,13 @@ the value would be: "My name is: Jim"
The following special variables are available:
- **$binary**: Incoming binary data of a node
- **$data**: Incoming JSON data of a node
- **$evaluateExpression**: Evaluates a string as expression
- **$env**: Environment variables
- **$node**: Data of other nodes (output-data, parameters)
- **$items**: Environment variables
- **$json**: Incoming JSON data of a node
- **$node**: Data of other nodes (context, output-data, parameters)
- **$parameters**: Parameters of the current node
- **$workflow**: Returns workflow metadata like: active, id, name
Normally it is not needed to write the JavaScript variables manually as they can be simply selected with the help of the Expression Editor.

View file

@ -59,7 +59,7 @@ return newItems;
```
#### Method: $item(index)
#### Method: $item(index: number)
With `$item` it is possible to access the data of parent nodes. That can be the item data but also
the parameters. It expects as input an index of the item the data should be returned for. This is
@ -88,6 +88,28 @@ const channel = $item(9).$node["Slack"].parameter["channel"];
```
#### Method: $items(nodeName?: string, outputIndex?: number, runIndex?: number)
Gives access to all the items of current or parent nodes. If no parameters get supplied
it returns all the items of the current node.
If a node-name is given, it returns the items the give node did output. By default of the
first output (index: 0, most nodes only have one output, exceptions are IF and Switch-Node)
and the current run.
Example:
```typescript
// Returns all the items of the current node and current run
const allItems = $items();
// Returns all items the node "IF" outputs (index: 0 which is Output "true" of current run)
const allItems = $items("IF");
// Returns all items the node "IF" outputs (index: 1 which is Output "false" of run 0 which is the first one)
const allItems = $items("IF", 1, 0);
```
#### Variable: $node
Works exactly like `$item` with the difference that it will always return the data of the first item.

View file

@ -534,6 +534,7 @@ export interface IWorkflowDataProxyData {
$env: any; // tslint:disable-line:no-any
$evaluateExpression: any; // tslint:disable-line:no-any
$item: any; // tslint:disable-line:no-any
$items: any; // tslint:disable-line:no-any
$json: any; // tslint:disable-line:no-any
$node: any; // tslint:disable-line:no-any
$parameter: any; // tslint:disable-line:no-any

View file

@ -104,6 +104,79 @@ export class WorkflowDataProxy {
}
/**
* Returns the node ExecutionData
*
* @private
* @param {string} nodeName The name of the node query data from
* @param {boolean} [shortSyntax=false] If short syntax got used
* @param {number} [outputIndex] The index of the output, if not given the first one gets used
* @param {number} [runIndex] The index of the run, if not given the current one does get used
* @returns {INodeExecutionData[]}
* @memberof WorkflowDataProxy
*/
private getNodeExecutionData(nodeName: string, shortSyntax = false, outputIndex?: number, runIndex?: number): INodeExecutionData[] {
const that = this;
let executionData: INodeExecutionData[];
if (shortSyntax === false) {
// Long syntax got used to return data from node in path
if (that.runExecutionData === null) {
throw new Error(`Workflow did not run so do not have any execution-data.`);
}
if (!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName)) {
throw new Error(`No execution data found for node "${nodeName}"`);
}
runIndex = runIndex === undefined ? that.runIndex : 0;
if (that.runExecutionData.resultData.runData[nodeName].length < runIndex) {
throw new Error(`No execution data found for run "${runIndex}" of node "${nodeName}"`);
}
const taskData = that.runExecutionData.resultData.runData[nodeName][runIndex].data!;
if (taskData.main === null || !taskData.main.length || taskData.main[0] === null) {
// throw new Error(`No data found for item-index: "${itemIndex}"`);
throw new Error(`No data found from "main" input.`);
}
// Check from which output to read the data.
// Depends on how the nodes are connected.
// (example "IF" node. If node is connected to "true" or to "false" output)
if (outputIndex === undefined) {
const outputIndex = that.workflow.getNodeConnectionOutputIndex(that.activeNodeName, nodeName, 'main');
if (outputIndex === undefined) {
throw new Error(`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`);
}
}
if (outputIndex === undefined) {
outputIndex = 0;
}
if (taskData.main.length < outputIndex) {
throw new Error(`No data found from "main" input with index "${outputIndex}" via which node is connected with.`);
}
executionData = taskData.main[outputIndex] as INodeExecutionData[];
} else {
// Short syntax got used to return data from active node
// TODO: Here have to generate connection Input data for the current node by itself
// Data needed:
// #- the run-index
// - node which did send data (has to be the one from last recent execution)
// - later also the name of the input and its index (currently not needed as it is always "main" and index "0")
executionData = that.connectionInputData;
}
return executionData;
}
/**
* Returns a proxy which allows to query data of a given node
@ -128,53 +201,7 @@ export class WorkflowDataProxy {
name = name.toString();
if (['binary', 'data', 'json'].includes(name)) {
let executionData: INodeExecutionData[];
if (shortSyntax === false) {
// Long syntax got used to return data from node in path
if (that.runExecutionData === null) {
throw new Error(`Workflow did not run so do not have any execution-data.`);
}
if (!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName)) {
throw new Error(`No execution data found for node "${nodeName}"`);
}
if (that.runExecutionData.resultData.runData[nodeName].length < that.runIndex) {
throw new Error(`No execution data found for run "${that.runIndex}" of node "${nodeName}"`);
}
const taskData = that.runExecutionData.resultData.runData[nodeName][that.runIndex].data!;
if (taskData.main === null || !taskData.main.length || taskData.main[0] === null) {
// throw new Error(`No data found for item-index: "${itemIndex}"`);
throw new Error(`No data found from "main" input.`);
}
// Check from which output to read the data.
// Depends on how the nodes are connected.
// (example "IF" node. If node is connected to "true" or to "false" output)
const outputIndex = that.workflow.getNodeConnectionOutputIndex(that.activeNodeName, nodeName, 'main');
if (outputIndex === undefined) {
throw new Error(`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`);
}
if (taskData.main.length < outputIndex) {
throw new Error(`No data found from "main" input with index "${outputIndex}" via which node is connected with.`);
}
executionData = taskData.main[outputIndex] as INodeExecutionData[];
} else {
// Short syntax got used to return data from active node
// TODO: Here have to generate connection Input data for the current node by itself
// Data needed:
// #- the run-index
// - node which did send data (has to be the one from last recent execution)
// - later also the name of the input and its index (currently not needed as it is always "main" and index "0")
executionData = that.connectionInputData;
}
const executionData = that.getNodeExecutionData(name, shortSyntax);
if (executionData.length <= that.itemIndex) {
throw new Error(`No data found for item-index: "${that.itemIndex}"`);
@ -305,6 +332,18 @@ export class WorkflowDataProxy {
const dataProxy = new WorkflowDataProxy(this.workflow, this.runExecutionData, this.runIndex, itemIndex, this.activeNodeName, this.connectionInputData);
return dataProxy.getDataProxy();
},
$items: (nodeName?: string, outputIndex?: number, runIndex?: number) => {
let executionData: INodeExecutionData[];
if (nodeName === undefined) {
executionData = that.connectionInputData;
} else {
outputIndex = outputIndex || 0;
executionData = that.getNodeExecutionData(nodeName, false, outputIndex, runIndex);
}
return executionData;
},
$json: {}, // Placeholder
$node: this.nodeGetter(),
$parameter: this.nodeParameterGetter(this.activeNodeName),