diff --git a/packages/nodes-base/nodes/Merge/Merge.node.ts b/packages/nodes-base/nodes/Merge/Merge.node.ts index dee9932318..6b342f5b43 100644 --- a/packages/nodes-base/nodes/Merge/Merge.node.ts +++ b/packages/nodes-base/nodes/Merge/Merge.node.ts @@ -14,7 +14,7 @@ export class Merge extends VersionedNodeType { group: ['transform'], subtitle: '={{$parameter["mode"]}}', description: 'Merges data of multiple streams once data from both is available', - defaultVersion: 3.1, + defaultVersion: 3.2, }; const nodeVersions: IVersionedNodeType['nodeVersions'] = { @@ -23,6 +23,7 @@ export class Merge extends VersionedNodeType { 2.1: new MergeV2(baseDescription), 3: new MergeV3(baseDescription), 3.1: new MergeV3(baseDescription), + 3.2: new MergeV3(baseDescription), }; super(nodeVersions, baseDescription); diff --git a/packages/nodes-base/nodes/Merge/test/v3/operations.test.ts b/packages/nodes-base/nodes/Merge/test/v3/operations.test.ts index 46598c7c09..cbd2d0a5b1 100644 --- a/packages/nodes-base/nodes/Merge/test/v3/operations.test.ts +++ b/packages/nodes-base/nodes/Merge/test/v3/operations.test.ts @@ -396,6 +396,59 @@ describe('Test MergeV3, combineBySql operation', () => { ], ]); }); + + it('Empty successful query should return [{ success: true }] at version <= 3.1', async () => { + const nodeParameters: IDataObject = { + operation: 'combineBySql', + query: 'SELECT id from input1', + }; + + const returnData = await mode.combineBySql.execute.call( + createMockExecuteFunction(nodeParameters, { ...node, typeVersion: 3.1 }), + [[]], + ); + + expect(returnData.length).toEqual(1); + expect(returnData[0].length).toEqual(1); + expect(returnData[0][0].json).toEqual({ + success: true, + }); + }); + + it('Empty successful query should return [] at version >= 3.2 if no option set', async () => { + const nodeParameters: IDataObject = { + operation: 'combineBySql', + query: 'SELECT id from input1', + }; + + const returnData = await mode.combineBySql.execute.call( + createMockExecuteFunction(nodeParameters, { ...node, typeVersion: 3.2 }), + [[]], + ); + + expect(returnData).toEqual([[]]); + }); + + it('Empty successful query should return [{ success: true }] at version >= 3.2 if option set', async () => { + const nodeParameters: IDataObject = { + operation: 'combineBySql', + query: 'SELECT id from input1', + options: { + emptyQueryResult: 'success', + }, + }; + + const returnData = await mode.combineBySql.execute.call( + createMockExecuteFunction(nodeParameters, { ...node, typeVersion: 3.2 }), + [[]], + ); + + expect(returnData.length).toEqual(1); + expect(returnData[0].length).toEqual(1); + expect(returnData[0][0].json).toEqual({ + success: true, + }); + }); }); describe('Test MergeV3, append operation', () => { diff --git a/packages/nodes-base/nodes/Merge/v3/actions/mode/combineBySql.ts b/packages/nodes-base/nodes/Merge/v3/actions/mode/combineBySql.ts index c53d5c4c58..3578e19a18 100644 --- a/packages/nodes-base/nodes/Merge/v3/actions/mode/combineBySql.ts +++ b/packages/nodes-base/nodes/Merge/v3/actions/mode/combineBySql.ts @@ -17,6 +17,10 @@ import { getResolvables, updateDisplayOptions } from '@utils/utilities'; import { numberInputsProperty } from '../../helpers/descriptions'; import { modifySelectQuery, rowToExecutionData } from '../../helpers/utils'; +type OperationOptions = { + emptyQueryResult: 'success' | 'empty'; +}; + export const properties: INodeProperties[] = [ numberInputsProperty, { @@ -33,6 +37,37 @@ export const properties: INodeProperties[] = [ editor: 'sqlEditor', }, }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add option', + default: {}, + options: [ + { + displayName: 'Empty Query Result', + name: 'emptyQueryResult', + type: 'options', + description: 'What to return if the query executed successfully but returned no results', + options: [ + { + name: 'Success', + value: 'success', + }, + { + name: 'Empty Result', + value: 'empty', + }, + ], + default: 'empty', + }, + ], + displayOptions: { + show: { + '@version': [3.2], + }, + }, + }, ]; const displayOptions = { @@ -61,6 +96,7 @@ async function executeSelectWithMappedPairedItems( node: INode, inputsData: INodeExecutionData[][], query: string, + returnSuccessItemIfEmpty: boolean, ): Promise { const returnData: INodeExecutionData[] = []; @@ -95,7 +131,7 @@ async function executeSelectWithMappedPairedItems( } } - if (!returnData.length) { + if (!returnData.length && returnSuccessItemIfEmpty) { returnData.push({ json: { success: true } }); } } catch (error) { @@ -114,6 +150,7 @@ export async function execute( const node = this.getNode(); const returnData: INodeExecutionData[] = []; const pairedItem: IPairedItemData[] = []; + const options = this.getNodeParameter('options', 0, {}) as OperationOptions; let query = this.getNodeParameter('query', 0) as string; @@ -122,10 +159,17 @@ export async function execute( } const isSelectQuery = node.typeVersion >= 3.1 ? query.toLowerCase().startsWith('select') : false; + const returnSuccessItemIfEmpty = + node.typeVersion <= 3.1 ? true : options.emptyQueryResult === 'success'; if (isSelectQuery) { try { - return await executeSelectWithMappedPairedItems(node, inputsData, query); + return await executeSelectWithMappedPairedItems( + node, + inputsData, + query, + returnSuccessItemIfEmpty, + ); } catch (error) { Container.get(ErrorReporter).error(error, { extra: { @@ -199,7 +243,7 @@ export async function execute( } } - if (!returnData.length) { + if (!returnData.length && returnSuccessItemIfEmpty) { returnData.push({ json: { success: true }, pairedItem }); } } catch (error) { diff --git a/packages/nodes-base/nodes/Merge/v3/actions/versionDescription.ts b/packages/nodes-base/nodes/Merge/v3/actions/versionDescription.ts index f49abd170b..f1b50ba665 100644 --- a/packages/nodes-base/nodes/Merge/v3/actions/versionDescription.ts +++ b/packages/nodes-base/nodes/Merge/v3/actions/versionDescription.ts @@ -9,7 +9,7 @@ export const versionDescription: INodeTypeDescription = { name: 'merge', group: ['transform'], description: 'Merges data of multiple streams once data from both is available', - version: [3, 3.1], + version: [3, 3.1, 3.2], defaults: { name: 'Merge', },