mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-05 02:59:27 +02:00
fix(Postgres Node): Spread array queryReplacement across multiple bind values (#31704)
Co-authored-by: Bao <bao0541@users.noreply.github.com>
This commit is contained in:
parent
6eb583b2bd
commit
ee7aa0b66a
|
|
@ -504,6 +504,88 @@ describe('Test PostgresV2, executeQuery operation', () => {
|
|||
expect(utils.isJSON).toHaveBeenCalledTimes(1);
|
||||
expect(utils.stringToArray).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
const createMockExecuteForArrayQuery = (
|
||||
nodeParameters: IDataObject,
|
||||
returnArray: unknown[],
|
||||
matchString: string,
|
||||
) =>
|
||||
({
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
_itemIndex: number,
|
||||
fallbackValue?: IDataObject,
|
||||
options?: IGetNodeParameterOptions,
|
||||
) {
|
||||
const parameter = options?.extractValue ? `${parameterName}.value` : parameterName;
|
||||
return get(nodeParameters, parameter, fallbackValue);
|
||||
},
|
||||
getNode() {
|
||||
node.parameters = { ...node.parameters, ...(nodeParameters as INodeParameters) };
|
||||
return node;
|
||||
},
|
||||
evaluateExpression(str: string, _: number) {
|
||||
if (str.includes(matchString)) {
|
||||
return returnArray;
|
||||
}
|
||||
return str.replace('{{', '').replace('}}', '');
|
||||
},
|
||||
}) as unknown as IExecuteFunctions;
|
||||
|
||||
it.each([
|
||||
{
|
||||
description: 'spread string array across individual bind values',
|
||||
query: 'INSERT INTO my_table (col1, col2, col3) VALUES ($1, $2, $3)',
|
||||
queryReplacement: "={{ ['a', 'b', 'c'] }}",
|
||||
matchString: "['a', 'b', 'c']",
|
||||
returnArray: ['a', 'b', 'c'],
|
||||
expectedValues: ['a', 'b', 'c'],
|
||||
},
|
||||
{
|
||||
description: 'JSON.stringify object elements in array bind values',
|
||||
query: 'INSERT INTO my_table (col1, col2) VALUES ($1, $2)',
|
||||
queryReplacement: '={{ [{id: 1}, {id: 2}] }}',
|
||||
matchString: '[{id: 1}, {id: 2}]',
|
||||
returnArray: [{ id: 1 }, { id: 2 }],
|
||||
expectedValues: ['{"id":1}', '{"id":2}'],
|
||||
},
|
||||
{
|
||||
description: 'handle null, number, and boolean elements in array bind values',
|
||||
query: 'INSERT INTO my_table (col1, col2, col3) VALUES ($1, $2, $3)',
|
||||
queryReplacement: '={{ [null, 42, true] }}',
|
||||
matchString: '[null, 42, true]',
|
||||
returnArray: [null, 42, true],
|
||||
expectedValues: [null, 42, true],
|
||||
},
|
||||
])(
|
||||
'should $description',
|
||||
async ({ query, queryReplacement, matchString, returnArray, expectedValues }) => {
|
||||
const nodeParameters: IDataObject = {
|
||||
operation: 'executeQuery',
|
||||
query,
|
||||
options: {
|
||||
queryReplacement,
|
||||
nodeVersion: 2.6,
|
||||
},
|
||||
};
|
||||
const nodeOptions = nodeParameters.options as IDataObject;
|
||||
|
||||
const mockExecute = createMockExecuteForArrayQuery(nodeParameters, returnArray, matchString);
|
||||
|
||||
await executeQuery.execute.call(mockExecute, runQueries, items, nodeOptions);
|
||||
|
||||
expect(runQueries).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
query,
|
||||
values: expectedValues,
|
||||
options: { partial: true },
|
||||
},
|
||||
],
|
||||
nodeOptions,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Test PostgresV2, insert operation', () => {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import type {
|
|||
PgpDatabase,
|
||||
PostgresNodeOptions,
|
||||
QueriesRunner,
|
||||
QueryValue,
|
||||
QueryWithValues,
|
||||
} from '../../helpers/interfaces';
|
||||
import {
|
||||
|
|
@ -68,7 +69,7 @@ export async function execute(
|
|||
query = query.replace(resolvable, this.evaluateExpression(resolvable, index) as string);
|
||||
}
|
||||
|
||||
let values: Array<IDataObject | string> = [];
|
||||
let values: QueryValue[] = [];
|
||||
|
||||
let queryReplacement = this.getNodeParameter('options.queryReplacement', index, '');
|
||||
|
||||
|
|
@ -89,9 +90,19 @@ export async function execute(
|
|||
const resolvables = getResolvables(rawValues);
|
||||
if (resolvables.length) {
|
||||
for (const resolvable of resolvables) {
|
||||
const evaluatedExpression = evaluateExpression(
|
||||
this.evaluateExpression(`${resolvable}`, index),
|
||||
);
|
||||
const rawEvaluated = this.evaluateExpression(`${resolvable}`, index);
|
||||
|
||||
if (Array.isArray(rawEvaluated)) {
|
||||
for (const item of rawEvaluated) {
|
||||
if (item === undefined) continue;
|
||||
values.push(
|
||||
typeof item === 'object' && item !== null ? JSON.stringify(item) : item,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const evaluatedExpression = evaluateExpression(rawEvaluated);
|
||||
const evaluatedValues = isJSON(evaluatedExpression)
|
||||
? [evaluatedExpression]
|
||||
: stringToArray(evaluatedExpression);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type pg from 'pg-promise/typescript/pg-subset';
|
|||
|
||||
export type QueryMode = 'single' | 'transaction' | 'independently';
|
||||
|
||||
export type QueryValue = string | number | IDataObject | string[];
|
||||
export type QueryValue = string | number | boolean | null | IDataObject | string[];
|
||||
export type QueryValues = QueryValue[];
|
||||
export type QueryWithValues = { query: string; values?: QueryValues; options?: IFormattingOptions };
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user