fix(Postgres Node): Option to treat query parameters enclosed in single quotas as text (#10214)

This commit is contained in:
Michael Kret 2024-07-29 14:48:11 +03:00 committed by GitHub
parent 24ffca7c75
commit 00ec253337
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 93 additions and 0 deletions

View file

@ -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', () => {

View file

@ -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',

View file

@ -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 });
}

View file

@ -47,6 +47,7 @@ export type PostgresNodeOptions = {
largeNumbersOutput?: 'numbers' | 'text';
skipOnConflict?: boolean;
replaceEmptyStrings?: boolean;
treatQueryParametersInSingleQuotesAsText?: boolean;
};
export type PostgresNodeCredentials = {