From f85b85185109b0ebd3f2f0def8a7c4a0902c8014 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:57:26 +0300 Subject: [PATCH] feat(Postgres Node): Batching warning for executeQuery operation insert query (#14287) --- .../nodes/Postgres/test/v2/utils.test.ts | 38 ++++++++++++++++++- .../v2/actions/common.descriptions.ts | 2 +- .../nodes/Postgres/v2/actions/router.ts | 9 +---- .../nodes/Postgres/v2/helpers/utils.ts | 27 +++++++++++++ 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/packages/nodes-base/nodes/Postgres/test/v2/utils.test.ts b/packages/nodes-base/nodes/Postgres/test/v2/utils.test.ts index e5aef35a37..05963e86f9 100644 --- a/packages/nodes-base/nodes/Postgres/test/v2/utils.test.ts +++ b/packages/nodes-base/nodes/Postgres/test/v2/utils.test.ts @@ -1,4 +1,4 @@ -import type { IDataObject, INode } from 'n8n-workflow'; +import type { IDataObject, IExecuteFunctions, INode } from 'n8n-workflow'; import { NodeOperationError } from 'n8n-workflow'; import pgPromise from 'pg-promise'; @@ -18,6 +18,7 @@ import { convertValuesToJsonWithPgp, hasJsonDataTypeInSchema, evaluateExpression, + addExecutionHints, } from '../../v2/helpers/utils'; const node: INode = { @@ -535,3 +536,38 @@ describe('Test PostgresV2, convertArraysToPostgresFormat', () => { }); }); }); + +describe('Test PostgresV2, addExecutionHints', () => { + it('should add batching insert hint to executeQuery operation', () => { + const context = { + getNodeParameter: (parameterName: string) => { + if (parameterName === 'options.queryBatching') { + return 'single'; + } + if (parameterName === 'query') { + return 'INSERT INTO my_test_table VALUES (`{{ $json.name }}`)'; + } + }, + addExecutionHints: jest.fn(), + } as unknown as IExecuteFunctions; + + addExecutionHints(context, [{ json: {} }, { json: {} }], 'executeQuery', false); + expect(context.addExecutionHints).toHaveBeenCalledWith({ + message: + "Inserts were batched for performance. If you need to preserve item matching, consider changing 'Query batching' to 'Independent' in the options.", + location: 'outputPane', + }); + }); + it('should add run per item hint to select operation', () => { + const context = { + addExecutionHints: jest.fn(), + } as unknown as IExecuteFunctions; + + addExecutionHints(context, [{ json: {} }, { json: {} }], 'select', false); + expect(context.addExecutionHints).toHaveBeenCalledWith({ + location: 'outputPane', + message: + "This node ran 2 times, once for each input item. To run for the first item only, enable 'execute once' in the node settings", + }); + }); +}); diff --git a/packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts b/packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts index d737758399..9f00b634e4 100644 --- a/packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts +++ b/packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts @@ -52,7 +52,7 @@ export const optionsCollection: INodeProperties = { description: 'A single query for all incoming items', }, { - name: 'Independently', + name: 'Independent', value: 'independently', description: 'Execute one query per incoming item of the run', }, diff --git a/packages/nodes-base/nodes/Postgres/v2/actions/router.ts b/packages/nodes-base/nodes/Postgres/v2/actions/router.ts index 4c35994dd1..ff988a99d6 100644 --- a/packages/nodes-base/nodes/Postgres/v2/actions/router.ts +++ b/packages/nodes-base/nodes/Postgres/v2/actions/router.ts @@ -5,7 +5,7 @@ import * as database from './database/Database.resource'; import type { PostgresType } from './node.type'; import { configurePostgres } from '../../transport'; import type { PostgresNodeCredentials, PostgresNodeOptions } from '../helpers/interfaces'; -import { configureQueryRunner } from '../helpers/utils'; +import { addExecutionHints, configureQueryRunner } from '../helpers/utils'; export async function router(this: IExecuteFunctions): Promise { let returnData: INodeExecutionData[] = []; @@ -53,12 +53,7 @@ export async function router(this: IExecuteFunctions): Promise 1 && !node.executeOnce) { - this.addExecutionHints({ - message: `This node ran ${items.length} times, once for each input item. To run for the first item only, enable 'execute once' in the node settings`, - location: 'outputPane', - }); - } + addExecutionHints(this, items, operation, node.executeOnce); return [returnData]; } diff --git a/packages/nodes-base/nodes/Postgres/v2/helpers/utils.ts b/packages/nodes-base/nodes/Postgres/v2/helpers/utils.ts index a8caf39c18..0d95cdd9e4 100644 --- a/packages/nodes-base/nodes/Postgres/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/Postgres/v2/helpers/utils.ts @@ -616,3 +616,30 @@ export const convertArraysToPostgresFormat = ( } } }; + +export function addExecutionHints( + context: IExecuteFunctions, + items: INodeExecutionData[], + operation: string, + executeOnce: boolean | undefined, +) { + if (operation === 'select' && items.length > 1 && !executeOnce) { + context.addExecutionHints({ + message: `This node ran ${items.length} times, once for each input item. To run for the first item only, enable 'execute once' in the node settings`, + location: 'outputPane', + }); + } + + if ( + operation === 'executeQuery' && + items.length > 1 && + (context.getNodeParameter('options.queryBatching', 0, 'single') as string) === 'single' && + (context.getNodeParameter('query', 0, '') as string).toLowerCase().startsWith('insert') + ) { + context.addExecutionHints({ + message: + "Inserts were batched for performance. If you need to preserve item matching, consider changing 'Query batching' to 'Independent' in the options.", + location: 'outputPane', + }); + } +}