mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -08:00
feat(core): Expression function $ifEmpty (#7660)
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: Elias Meire <elias@meire.dev>
This commit is contained in:
parent
14035e1244
commit
1c7225ebdb
|
@ -44,7 +44,7 @@ export const baseCompletions = defineComponent({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - Complete `$` to `$execution $input $prevNode $runIndex $workflow $now $today
|
* - Complete `$` to `$execution $input $prevNode $runIndex $workflow $now $today
|
||||||
* $jmespath $('nodeName')` in both modes.
|
* $jmespath $ifEmpt $('nodeName')` in both modes.
|
||||||
* - Complete `$` to `$json $binary $itemIndex` in single-item mode.
|
* - Complete `$` to `$json $binary $itemIndex` in single-item mode.
|
||||||
*/
|
*/
|
||||||
baseCompletions(context: CompletionContext): CompletionResult | null {
|
baseCompletions(context: CompletionContext): CompletionResult | null {
|
||||||
|
@ -58,6 +58,10 @@ export const baseCompletions = defineComponent({
|
||||||
label: `${prefix}execution`,
|
label: `${prefix}execution`,
|
||||||
info: this.$locale.baseText('codeNodeEditor.completer.$execution'),
|
info: this.$locale.baseText('codeNodeEditor.completer.$execution'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: `${prefix}ifEmpty()`,
|
||||||
|
info: this.$locale.baseText('codeNodeEditor.completer.$ifEmpty'),
|
||||||
|
},
|
||||||
{ label: `${prefix}input`, info: this.$locale.baseText('codeNodeEditor.completer.$input') },
|
{ label: `${prefix}input`, info: this.$locale.baseText('codeNodeEditor.completer.$input') },
|
||||||
{
|
{
|
||||||
label: `${prefix}prevNode`,
|
label: `${prefix}prevNode`,
|
||||||
|
|
|
@ -460,6 +460,7 @@ export const MAPPING_PARAMS = [
|
||||||
'$env',
|
'$env',
|
||||||
'$evaluateExpression',
|
'$evaluateExpression',
|
||||||
'$execution',
|
'$execution',
|
||||||
|
'$ifEmpty',
|
||||||
'$input',
|
'$input',
|
||||||
'$item',
|
'$item',
|
||||||
'$jmespath',
|
'$jmespath',
|
||||||
|
|
|
@ -47,7 +47,7 @@ export function dollarCompletions(context: CompletionContext): CompletionResult
|
||||||
export function dollarOptions() {
|
export function dollarOptions() {
|
||||||
const rank = setRank(['$json', '$input']);
|
const rank = setRank(['$json', '$input']);
|
||||||
const SKIP = new Set();
|
const SKIP = new Set();
|
||||||
const DOLLAR_FUNCTIONS = ['$jmespath'];
|
const DOLLAR_FUNCTIONS = ['$jmespath', '$ifEmpty'];
|
||||||
|
|
||||||
if (isCredentialsModalOpen()) {
|
if (isCredentialsModalOpen()) {
|
||||||
return useExternalSecretsStore().isEnterpriseExternalSecretsEnabled
|
return useExternalSecretsStore().isEnterpriseExternalSecretsEnabled
|
||||||
|
|
|
@ -328,6 +328,7 @@ export class I18nClass {
|
||||||
rootVars: Record<string, string | undefined> = {
|
rootVars: Record<string, string | undefined> = {
|
||||||
$binary: this.baseText('codeNodeEditor.completer.binary'),
|
$binary: this.baseText('codeNodeEditor.completer.binary'),
|
||||||
$execution: this.baseText('codeNodeEditor.completer.$execution'),
|
$execution: this.baseText('codeNodeEditor.completer.$execution'),
|
||||||
|
$ifEmpty: this.baseText('codeNodeEditor.completer.$ifEmpty'),
|
||||||
$input: this.baseText('codeNodeEditor.completer.$input'),
|
$input: this.baseText('codeNodeEditor.completer.$input'),
|
||||||
$jmespath: this.baseText('codeNodeEditor.completer.$jmespath'),
|
$jmespath: this.baseText('codeNodeEditor.completer.$jmespath'),
|
||||||
$json: this.baseText('codeNodeEditor.completer.json'),
|
$json: this.baseText('codeNodeEditor.completer.json'),
|
||||||
|
|
|
@ -168,6 +168,7 @@
|
||||||
"codeNodeEditor.completer.$execution.customData.get()": "Get custom data set in the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
"codeNodeEditor.completer.$execution.customData.get()": "Get custom data set in the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||||
"codeNodeEditor.completer.$execution.customData.setAll()": "Set multiple custom data key/value pairs with an object for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
"codeNodeEditor.completer.$execution.customData.setAll()": "Set multiple custom data key/value pairs with an object for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||||
"codeNodeEditor.completer.$execution.customData.getAll()": "Get all custom data for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
"codeNodeEditor.completer.$execution.customData.getAll()": "Get all custom data for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||||
|
"codeNodeEditor.completer.$ifEmpty": "Checks whether the first parameter is empty, and if so returns the second parameter. Otherwise returns the first parameter. The following count as empty: null/undefined values, empty strings, empty arrays, objects with no keys.",
|
||||||
"codeNodeEditor.completer.$input": "This node’s input data",
|
"codeNodeEditor.completer.$input": "This node’s input data",
|
||||||
"codeNodeEditor.completer.$input.all": "@:_reusableBaseText.codeNodeEditor.completer.all",
|
"codeNodeEditor.completer.$input.all": "@:_reusableBaseText.codeNodeEditor.completer.all",
|
||||||
"codeNodeEditor.completer.$input.first": "@:_reusableBaseText.codeNodeEditor.completer.first",
|
"codeNodeEditor.completer.$input.first": "@:_reusableBaseText.codeNodeEditor.completer.first",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ExpressionExtensionError } from '../ExpressionError';
|
import { ExpressionError, ExpressionExtensionError } from '../ExpressionError';
|
||||||
import { average as aAverage } from './ArrayExtensions';
|
import { average as aAverage } from './ArrayExtensions';
|
||||||
|
|
||||||
const min = Math.min;
|
const min = Math.min;
|
||||||
|
@ -39,6 +39,36 @@ const not = (value: unknown): boolean => {
|
||||||
return !value;
|
return !value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ifEmpty<T, V>(value: V, defaultValue: T) {
|
||||||
|
if (arguments.length !== 2) {
|
||||||
|
throw new ExpressionError('expected two arguments (value, defaultValue) for this function');
|
||||||
|
}
|
||||||
|
if (value === undefined || value === null || value === '') {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
if (Array.isArray(value) && !value.length) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if (!Object.keys(value).length) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifEmpty.doc = {
|
||||||
|
name: 'ifEmpty',
|
||||||
|
description:
|
||||||
|
'Returns the default value if the value is empty. Empty values are undefined, null, empty strings, arrays without elements and objects without keys.',
|
||||||
|
returnType: 'any',
|
||||||
|
args: [
|
||||||
|
{ name: 'value', type: 'any' },
|
||||||
|
{ name: 'defaultValue', type: 'any' },
|
||||||
|
],
|
||||||
|
docURL: 'https://docs.n8n.io/code-examples/expressions/data-transformation-functions/#if-empty',
|
||||||
|
};
|
||||||
|
|
||||||
export const extendedFunctions = {
|
export const extendedFunctions = {
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
|
@ -50,4 +80,5 @@ export const extendedFunctions = {
|
||||||
$max: max,
|
$max: max,
|
||||||
$average: average,
|
$average: average,
|
||||||
$not: not,
|
$not: not,
|
||||||
|
$ifEmpty: ifEmpty,
|
||||||
};
|
};
|
||||||
|
|
|
@ -228,5 +228,18 @@ describe('tmpl Expression Parser', () => {
|
||||||
expect(evaluate('={{ $not("") }}')).toEqual(true);
|
expect(evaluate('={{ $not("") }}')).toEqual(true);
|
||||||
expect(evaluate('={{ $not("a") }}')).toEqual(false);
|
expect(evaluate('={{ $not("a") }}')).toEqual(false);
|
||||||
});
|
});
|
||||||
|
test('$ifEmpty', () => {
|
||||||
|
expect(evaluate('={{ $ifEmpty(1, "default") }}')).toEqual(1);
|
||||||
|
expect(evaluate('={{ $ifEmpty(0, "default") }}')).toEqual(0);
|
||||||
|
expect(evaluate('={{ $ifEmpty(false, "default") }}')).toEqual(false);
|
||||||
|
expect(evaluate('={{ $ifEmpty(true, "default") }}')).toEqual(true);
|
||||||
|
expect(evaluate('={{ $ifEmpty("", "default") }}')).toEqual('default');
|
||||||
|
expect(evaluate('={{ $ifEmpty(null, "default") }}')).toEqual('default');
|
||||||
|
expect(evaluate('={{ $ifEmpty(undefined, "default") }}')).toEqual('default');
|
||||||
|
expect(evaluate('={{ $ifEmpty([], "default") }}')).toEqual('default');
|
||||||
|
expect(evaluate('={{ $ifEmpty({}, "default") }}')).toEqual('default');
|
||||||
|
expect(evaluate('={{ $ifEmpty([1], "default") }}')).toEqual([1]);
|
||||||
|
expect(evaluate('={{ $ifEmpty({a: 1}, "default") }}')).toEqual({ a: 1 });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue