diff --git a/packages/nodes-base/nodes/Postgres/test/v2/operations.test.ts b/packages/nodes-base/nodes/Postgres/test/v2/operations.test.ts index 61484e54a1..aff8c740a5 100644 --- a/packages/nodes-base/nodes/Postgres/test/v2/operations.test.ts +++ b/packages/nodes-base/nodes/Postgres/test/v2/operations.test.ts @@ -219,6 +219,77 @@ describe('Test PostgresV2, executeQuery operation', () => { nodeOptions, ); }); + + it('should call runQueries and insert enclosed placeholder into values', async () => { + const nodeParameters: IDataObject = { + operation: 'executeQuery', + query: "select '$1';", + options: {}, + }; + const nodeOptions = nodeParameters.options as IDataObject; + + await executeQuery.execute.call( + createMockExecuteFunction(nodeParameters), + runQueries, + items, + nodeOptions, + ); + + expect(runQueries).toHaveBeenCalledWith( + [{ query: 'select $1;', values: ['$1'] }], + items, + nodeOptions, + ); + }); + + it('should call runQueries and not insert enclosed placeholder into values because queryReplacement is defined', async () => { + const nodeParameters: IDataObject = { + operation: 'executeQuery', + query: "select '$1';", + options: { + queryReplacement: 'my_table', + }, + }; + const nodeOptions = nodeParameters.options as IDataObject; + + await executeQuery.execute.call( + createMockExecuteFunction(nodeParameters), + runQueries, + items, + nodeOptions, + ); + + expect(runQueries).toHaveBeenCalledWith( + [{ query: "select '$1';", values: ['my_table'] }], + items, + nodeOptions, + ); + }); + + it('should call runQueries and insert enclosed placeholder into values because treatQueryParametersInSingleQuotesAsText is true', async () => { + const nodeParameters: IDataObject = { + operation: 'executeQuery', + query: "select '$1';", + options: { + queryReplacement: 'my_table', + treatQueryParametersInSingleQuotesAsText: true, + }, + }; + const nodeOptions = nodeParameters.options as IDataObject; + + await executeQuery.execute.call( + createMockExecuteFunction(nodeParameters), + runQueries, + items, + nodeOptions, + ); + + expect(runQueries).toHaveBeenCalledWith( + [{ query: 'select $2;', values: ['my_table', '$1'] }], + items, + nodeOptions, + ); + }); }); describe('Test PostgresV2, insert operation', () => { 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 1d4088820f..8814e9a4df 100644 --- a/packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts +++ b/packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts @@ -79,6 +79,17 @@ export const optionsCollection: INodeProperties = { show: { '/operation': ['executeQuery'] }, }, }, + { + // eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased + displayName: 'Treat query parameters in single quotes as text', + name: 'treatQueryParametersInSingleQuotesAsText', + type: 'boolean', + default: false, + description: "Whether to treat query parameters enclosed in single quotes as text e.g. '$1'", + displayOptions: { + show: { queryReplacement: [{ _cnd: { exists: true } }] }, + }, + }, { // eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options displayName: 'Output Columns', diff --git a/packages/nodes-base/nodes/Postgres/v2/actions/database/executeQuery.operation.ts b/packages/nodes-base/nodes/Postgres/v2/actions/database/executeQuery.operation.ts index 6d7908905e..2b8449e983 100644 --- a/packages/nodes-base/nodes/Postgres/v2/actions/database/executeQuery.operation.ts +++ b/packages/nodes-base/nodes/Postgres/v2/actions/database/executeQuery.operation.ts @@ -109,6 +109,16 @@ export async function execute( } } + if (!queryReplacement || nodeOptions.treatQueryParametersInSingleQuotesAsText) { + let nextValueIndex = values.length + 1; + const literals = query.match(/'\$[0-9]+'/g) ?? []; + for (const literal of literals) { + query = query.replace(literal, `$${nextValueIndex}`); + values.push(literal.replace(/'/g, '')); + nextValueIndex++; + } + } + queries.push({ query, values }); } diff --git a/packages/nodes-base/nodes/Postgres/v2/helpers/interfaces.ts b/packages/nodes-base/nodes/Postgres/v2/helpers/interfaces.ts index 8a8677f4f0..8aadf14ddc 100644 --- a/packages/nodes-base/nodes/Postgres/v2/helpers/interfaces.ts +++ b/packages/nodes-base/nodes/Postgres/v2/helpers/interfaces.ts @@ -47,6 +47,7 @@ export type PostgresNodeOptions = { largeNumbersOutput?: 'numbers' | 'text'; skipOnConflict?: boolean; replaceEmptyStrings?: boolean; + treatQueryParametersInSingleQuotesAsText?: boolean; }; export type PostgresNodeCredentials = {