Skip to content

Commit

Permalink
fix(Postgres Node): Empty return data fix for Postgres and MySQL (#7016)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-radency authored Aug 25, 2023
1 parent f02f6b6 commit 176ccd6
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 22 deletions.
3 changes: 2 additions & 1 deletion packages/nodes-base/nodes/MySql/MySql.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ 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',
};

const nodeVersions: IVersionedNodeType['nodeVersions'] = {
1: new MySqlV1(baseDescription),
2: new MySqlV2(baseDescription),
2.1: new MySqlV2(baseDescription),
2.2: new MySqlV2(baseDescription),
};

super(nodeVersions, baseDescription);
Expand Down
2 changes: 1 addition & 1 deletion packages/nodes-base/nodes/MySql/test/v2/operations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ describe('Test MySql V2, operations', () => {

const runQueries: QueryRunner = configureQueryRunner.call(
fakeExecuteFunction,
nodeOptions,
{ ...nodeOptions, nodeVersion: 2 },
pool,
);

Expand Down
6 changes: 3 additions & 3 deletions packages/nodes-base/nodes/MySql/test/v2/runQueries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
18 changes: 17 additions & 1 deletion packages/nodes-base/nodes/MySql/v2/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion packages/nodes-base/nodes/Postgres/Postgres.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
};

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
68 changes: 56 additions & 12 deletions packages/nodes-base/nodes/Postgres/v2/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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 } },
);

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

Expand Down

0 comments on commit 176ccd6

Please sign in to comment.