fix(Postgres Node): Empty return data fix for Postgres and MySQL (#7016)

This commit is contained in:
Michael Kret 2023-08-25 18:38:09 +03:00 committed by GitHub
parent f02f6b659a
commit 176ccd62bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 86 additions and 22 deletions

View file

@ -11,7 +11,7 @@ export class MySql extends VersionedNodeType {
name: 'mySql',
icon: 'file:mysql.svg',
group: ['input'],
defaultVersion: 2.1,
defaultVersion: 2.2,
description: 'Get, add and update data in MySQL',
};
@ -19,6 +19,7 @@ export class MySql extends VersionedNodeType {
1: new MySqlV1(baseDescription),
2: new MySqlV2(baseDescription),
2.1: new MySqlV2(baseDescription),
2.2: new MySqlV2(baseDescription),
};
super(nodeVersions, baseDescription);

View file

@ -305,7 +305,7 @@ describe('Test MySql V2, operations', () => {
const runQueries: QueryRunner = configureQueryRunner.call(
fakeExecuteFunction,
nodeOptions,
{ ...nodeOptions, nodeVersion: 2 },
pool,
);

View file

@ -45,7 +45,7 @@ describe('Test MySql V2, runQueries', () => {
});
it('should execute in "Single" mode, should return success true', async () => {
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.SINGLE };
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.SINGLE, nodeVersion: 2 };
const pool = createFakePool(fakeConnection);
const fakeExecuteFunction = createMockExecuteFunction({}, mySqlMockNode);
@ -81,7 +81,7 @@ describe('Test MySql V2, runQueries', () => {
});
it('should execute in "independently" mode, should return success true', async () => {
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.INDEPENDENTLY };
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.INDEPENDENTLY, nodeVersion: 2 };
const pool = createFakePool(fakeConnection);
@ -126,7 +126,7 @@ describe('Test MySql V2, runQueries', () => {
});
it('should execute in "transaction" mode, should return success true', async () => {
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.TRANSACTION };
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.TRANSACTION, nodeVersion: 2 };
const pool = createFakePool(fakeConnection);

View file

@ -8,7 +8,7 @@ export const versionDescription: INodeTypeDescription = {
name: 'mySql',
icon: 'file:mysql.svg',
group: ['input'],
version: [2, 2.1],
version: [2, 2.1, 2.2],
subtitle: '={{ $parameter["operation"] }}',
description: 'Get, add and update data in MySQL',
defaults: {

View file

@ -167,7 +167,23 @@ export function prepareOutput(
}
if (!returnData.length) {
returnData.push({ json: { success: true } });
if ((options?.nodeVersion as number) < 2.2) {
returnData.push({ json: { success: true } });
} else {
const isSelectQuery = statements
.filter((statement) => !statement.startsWith('--'))
.every((statement) =>
statement
.replace(/\/\*.*?\*\//g, '') // remove multiline comments
.replace(/\n/g, '')
.toLowerCase()
.startsWith('select'),
);
if (!isSelectQuery) {
returnData.push({ json: { success: true } });
}
}
}
return returnData;

View file

@ -11,7 +11,7 @@ export class Postgres extends VersionedNodeType {
name: 'postgres',
icon: 'file:postgres.svg',
group: ['input'],
defaultVersion: 2.2,
defaultVersion: 2.3,
description: 'Get, add and update data in Postgres',
};
@ -20,6 +20,7 @@ export class Postgres extends VersionedNodeType {
2: new PostgresV2(baseDescription),
2.1: new PostgresV2(baseDescription),
2.2: new PostgresV2(baseDescription),
2.3: new PostgresV2(baseDescription),
};
super(nodeVersions, baseDescription);

View file

@ -44,7 +44,9 @@ describe('Test PostgresV2, runQueries', () => {
const thisArg = mock<IExecuteFunctions>();
const runQueries = configureQueryRunner.call(thisArg, node, false, pgp, db);
const result = await runQueries([{ query: 'SELECT * FROM table', values: [] }], [], {});
const result = await runQueries([{ query: 'SELECT * FROM table', values: [] }], [], {
nodeVersion: 2.2,
});
expect(result).toBeDefined();
expect(result).toHaveLength(1);

View file

@ -8,7 +8,7 @@ export const versionDescription: INodeTypeDescription = {
name: 'postgres',
icon: 'file:postgres.svg',
group: ['input'],
version: [2, 2.1, 2.2],
version: [2, 2.1, 2.2, 2.3],
subtitle: '={{ $parameter["operation"] }}',
description: 'Get, add and update data in Postgres',
defaults: {

View file

@ -199,6 +199,15 @@ export function addReturning(
return [`${query} RETURNING $${replacementIndex}:name`, [...replacements, outputColumns]];
}
const isSelectQuery = (query: string) => {
return query
.replace(/\/\*.*?\*\//g, '') // remove multiline comments
.replace(/\n/g, '')
.split(';')
.filter((statement) => statement && !statement.startsWith('--')) // remove comments and empty statements
.every((statement) => statement.trim().toLowerCase().startsWith('select'));
};
export function configureQueryRunner(
this: IExecuteFunctions,
node: INode,
@ -221,7 +230,16 @@ export function configureQueryRunner(
});
})
.flat();
returnData = returnData.length ? returnData : emptyReturnData;
if (!returnData.length) {
if ((options?.nodeVersion as number) < 2.3) {
returnData = emptyReturnData;
} else {
returnData = queries.every((query) => isSelectQuery(query.query))
? []
: [{ json: { success: true } }];
}
}
} catch (err) {
const error = parsePostgresError(node, err, queries);
if (!continueOnFail) throw error;
@ -242,13 +260,26 @@ export function configureQueryRunner(
const result: INodeExecutionData[] = [];
for (let i = 0; i < queries.length; i++) {
try {
const transactionResult: IDataObject[] = await transaction.any(
queries[i].query,
queries[i].values,
);
const query = queries[i].query;
const values = queries[i].values;
let transactionResults;
if ((options?.nodeVersion as number) < 2.3) {
transactionResults = await transaction.any(query, values);
} else {
transactionResults = (await transaction.multi(query, values)).flat();
}
if (!transactionResults.length) {
if ((options?.nodeVersion as number) < 2.3) {
transactionResults = emptyReturnData;
} else {
transactionResults = isSelectQuery(query) ? [] : [{ success: true }];
}
}
const executionData = this.helpers.constructExecutionMetaData(
wrapData(transactionResult.length ? transactionResult : emptyReturnData),
wrapData(transactionResults),
{ itemData: { item: i } },
);
@ -265,17 +296,30 @@ export function configureQueryRunner(
}
if (queryBatching === 'independently') {
returnData = await db.task(async (t) => {
returnData = await db.task(async (task) => {
const result: INodeExecutionData[] = [];
for (let i = 0; i < queries.length; i++) {
try {
const transactionResult: IDataObject[] = await t.any(
queries[i].query,
queries[i].values,
);
const query = queries[i].query;
const values = queries[i].values;
let transactionResults;
if ((options?.nodeVersion as number) < 2.3) {
transactionResults = await task.any(query, values);
} else {
transactionResults = (await task.multi(query, values)).flat();
}
if (!transactionResults.length) {
if ((options?.nodeVersion as number) < 2.3) {
transactionResults = emptyReturnData;
} else {
transactionResults = isSelectQuery(query) ? [] : [{ success: true }];
}
}
const executionData = this.helpers.constructExecutionMetaData(
wrapData(transactionResult.length ? transactionResult : emptyReturnData),
wrapData(transactionResults),
{ itemData: { item: i } },
);