fix(Postgres Node): Allow using composite key in upsert queries (#12639)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <netroy@users.noreply.github.com>
This commit is contained in:
Shireen Missi 2025-01-17 08:42:46 +00:00 committed by GitHub
parent 982131a75a
commit 83ce3a9096
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 185 additions and 2 deletions

View file

@ -1151,3 +1151,184 @@ describe('Test PostgresV2, upsert operation', () => {
);
});
});
describe('When matching on all columns', () => {
it('dataMode: define, should call runQueries with', async () => {
const nodeParameters: IDataObject = {
operation: 'upsert',
schema: {
__rl: true,
mode: 'list',
value: 'public',
},
table: {
__rl: true,
value: 'my_table',
mode: 'list',
},
columns: {
matchingColumns: ['id', 'json', 'foo'],
value: { id: '5', json: '{ "test": 5 }', foo: 'data 5' },
mappingMode: 'defineBelow',
},
options: {
outputColumns: ['json'],
nodeVersion: 2.5,
},
};
const columnsInfo: ColumnInfo[] = [
{ column_name: 'id', data_type: 'integer', is_nullable: 'NO', udt_name: '' },
{ column_name: 'json', data_type: 'json', is_nullable: 'NO', udt_name: '' },
{ column_name: 'foo', data_type: 'text', is_nullable: 'NO', udt_name: '' },
];
const inputItems = [
{
json: {
id: 1,
json: {
test: 15,
},
foo: 'data 1',
},
},
];
const nodeOptions = nodeParameters.options as IDataObject;
await upsert.execute.call(
createMockExecuteFunction(nodeParameters),
runQueries,
inputItems,
nodeOptions,
createMockDb(columnsInfo),
);
expect(runQueries).toHaveBeenCalledWith(
[
{
query:
'INSERT INTO $1:name.$2:name($6:name) VALUES($6:csv) ON CONFLICT ($3:name,$4:name,$5:name) DO NOTHING RETURNING $7:name',
values: [
'public',
'my_table',
'id',
'json',
'foo',
{ id: '5', json: '{ "test": 5 }', foo: 'data 5' },
['json'],
],
},
],
inputItems,
nodeOptions,
);
});
it('dataMode: autoMapInputData, should call runQueries with', async () => {
const nodeParameters: IDataObject = {
operation: 'upsert',
schema: {
__rl: true,
mode: 'list',
value: 'public',
},
table: {
__rl: true,
value: 'my_table',
mode: 'list',
},
columns: {
matchingColumns: ['id', 'json', 'foo'],
mappingMode: 'autoMapInputData',
},
options: { nodeVersion: 2.5 },
};
const columnsInfo: ColumnInfo[] = [
{ column_name: 'id', data_type: 'integer', is_nullable: 'NO', udt_name: '' },
{ column_name: 'json', data_type: 'json', is_nullable: 'NO', udt_name: '' },
{ column_name: 'foo', data_type: 'text', is_nullable: 'NO', udt_name: '' },
];
const inputItems = [
{
json: {
id: 1,
json: {
test: 15,
},
foo: 'data 1',
},
},
{
json: {
id: 2,
json: {
test: 10,
},
foo: 'data 2',
},
},
{
json: {
id: 3,
json: {
test: 5,
},
foo: 'data 3',
},
},
];
const nodeOptions = nodeParameters.options as IDataObject;
await upsert.execute.call(
createMockExecuteFunction(nodeParameters),
runQueries,
inputItems,
nodeOptions,
createMockDb(columnsInfo),
);
expect(runQueries).toHaveBeenCalledWith(
[
{
query:
'INSERT INTO $1:name.$2:name($6:name) VALUES($6:csv) ON CONFLICT ($3:name,$4:name,$5:name) DO NOTHING RETURNING *',
values: [
'public',
'my_table',
'id',
'json',
'foo',
{ id: 1, json: { test: 15 }, foo: 'data 1' },
],
},
{
query:
'INSERT INTO $1:name.$2:name($6:name) VALUES($6:csv) ON CONFLICT ($3:name,$4:name,$5:name) DO NOTHING RETURNING *',
values: [
'public',
'my_table',
'id',
'json',
'foo',
{ id: 2, json: { test: 10 }, foo: 'data 2' },
],
},
{
query:
'INSERT INTO $1:name.$2:name($6:name) VALUES($6:csv) ON CONFLICT ($3:name,$4:name,$5:name) DO NOTHING RETURNING *',
values: [
'public',
'my_table',
'id',
'json',
'foo',
{ id: 3, json: { test: 5 }, foo: 'data 3' },
],
},
],
inputItems,
nodeOptions,
);
});
});

View file

@ -285,7 +285,7 @@ export async function execute(
valuesLength = valuesLength + 1;
values.push(column);
});
const onConflict = ` ON CONFLICT (${conflictColumns.join(',')}) DO UPDATE `;
const onConflict = ` ON CONFLICT (${conflictColumns.join(',')})`;
const insertQuery = `INSERT INTO $1:name.$2:name($${valuesLength}:name) VALUES($${valuesLength}:csv)${onConflict}`;
valuesLength = valuesLength + 1;
@ -300,7 +300,9 @@ export async function execute(
values.push(column, item[column] as string);
}
let query = `${insertQuery} SET ${updates.join(', ')}`;
const updateQuery =
updates?.length > 0 ? ` DO UPDATE SET ${updates.join(', ')}` : ' DO NOTHING ';
let query = `${insertQuery}${updateQuery}`;
const outputColumns = this.getNodeParameter('options.outputColumns', i, ['*']) as string[];