mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 13:27:31 -08:00
✨ Add $items to expression and Function-Nodes to get all items
This commit is contained in:
parent
135e467be9
commit
09e528565f
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in a new issue