mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-12 16:10:30 +02:00
fix(MySQL Node): Support "Continue on Error" for connection-related errors (#25032)
This commit is contained in:
parent
daba1e2846
commit
f3e2930f0e
|
|
@ -101,9 +101,7 @@ describe('MySQL Integration - NODE-4174', () => {
|
||||||
expect(result[0][0].json).toHaveProperty('message');
|
expect(result[0][0].json).toHaveProperty('message');
|
||||||
});
|
});
|
||||||
|
|
||||||
// NODE-4174: createPool() is outside try-catch, so connection errors bypass continueOnFail.
|
test('connection error should return error item with continueOnFail', async () => {
|
||||||
// Remove .fails when fixed.
|
|
||||||
test.fails('bug: connection error should return error item with continueOnFail', async () => {
|
|
||||||
const params = {
|
const params = {
|
||||||
resource: 'database',
|
resource: 'database',
|
||||||
operation: 'executeQuery',
|
operation: 'executeQuery',
|
||||||
|
|
|
||||||
|
|
@ -207,4 +207,40 @@ describe('Test MySql V2, runQueries', () => {
|
||||||
|
|
||||||
expect(connectionReleaseSpy).toBeCalledTimes(1);
|
expect(connectionReleaseSpy).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return error item with continueOnFail = true for connection error', async () => {
|
||||||
|
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.SINGLE, nodeVersion: 2 };
|
||||||
|
const pool = createFakePool(fakeConnection);
|
||||||
|
pool.getConnection = jest.fn(() => {
|
||||||
|
throw new Error('ECONNREFUSED');
|
||||||
|
});
|
||||||
|
const fakeExecuteFunction = createMockExecuteFunction({}, mySqlMockNode);
|
||||||
|
fakeExecuteFunction.continueOnFail = () => true;
|
||||||
|
|
||||||
|
const result = await configureQueryRunner.call(
|
||||||
|
fakeExecuteFunction,
|
||||||
|
nodeOptions,
|
||||||
|
pool,
|
||||||
|
)([{ query: 'SELECT * FROM my_table WHERE id = ?', values: [55] }]);
|
||||||
|
|
||||||
|
expect(result).toEqual([{ json: expect.objectContaining({ message: 'Connection refused' }) }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error when continueOnFail = false for connection error', async () => {
|
||||||
|
const nodeOptions: IDataObject = { queryBatching: BATCH_MODE.SINGLE, nodeVersion: 2 };
|
||||||
|
const pool = createFakePool(fakeConnection);
|
||||||
|
pool.getConnection = jest.fn(() => {
|
||||||
|
throw new Error('ECONNREFUSED');
|
||||||
|
});
|
||||||
|
const fakeExecuteFunction = createMockExecuteFunction({}, mySqlMockNode);
|
||||||
|
fakeExecuteFunction.continueOnFail = () => false;
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
configureQueryRunner.call(
|
||||||
|
fakeExecuteFunction,
|
||||||
|
nodeOptions,
|
||||||
|
pool,
|
||||||
|
)([{ query: 'SELECT * FROM my_table WHERE id = ?', values: [55] }]),
|
||||||
|
).rejects.toThrow('Connection refused');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import type { IDataObject, INodeExecutionData, SSHCredentials } from 'n8n-workfl
|
||||||
export type Mysql2Connection = mysql2.Connection;
|
export type Mysql2Connection = mysql2.Connection;
|
||||||
export type Mysql2Pool = mysql2.Pool;
|
export type Mysql2Pool = mysql2.Pool;
|
||||||
export type Mysql2OkPacket = mysql2.OkPacket;
|
export type Mysql2OkPacket = mysql2.OkPacket;
|
||||||
|
export type Mysql2PoolConnection = mysql2.PoolConnection;
|
||||||
|
|
||||||
export type QueryValues = Array<string | number | IDataObject>;
|
export type QueryValues = Array<string | number | IDataObject>;
|
||||||
export type QueryWithValues = { query: string; values: QueryValues };
|
export type QueryWithValues = { query: string; values: QueryValues };
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { NodeOperationError } from 'n8n-workflow';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
Mysql2Pool,
|
Mysql2Pool,
|
||||||
|
Mysql2PoolConnection,
|
||||||
ParameterMatch,
|
ParameterMatch,
|
||||||
QueryMode,
|
QueryMode,
|
||||||
QueryValues,
|
QueryValues,
|
||||||
|
|
@ -320,7 +321,17 @@ export function configureQueryRunner(
|
||||||
let returnData: INodeExecutionData[] = [];
|
let returnData: INodeExecutionData[] = [];
|
||||||
const mode = (options.queryBatching as QueryMode) || BATCH_MODE.SINGLE;
|
const mode = (options.queryBatching as QueryMode) || BATCH_MODE.SINGLE;
|
||||||
|
|
||||||
const connection = await pool.getConnection();
|
let connection: Mysql2PoolConnection;
|
||||||
|
try {
|
||||||
|
connection = await pool.getConnection();
|
||||||
|
} catch (e) {
|
||||||
|
const error = parseMySqlError.call(this, e);
|
||||||
|
if (!this.continueOnFail()) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [{ json: { message: error.message, error: { ...error } } }];
|
||||||
|
}
|
||||||
|
|
||||||
if (mode === BATCH_MODE.SINGLE) {
|
if (mode === BATCH_MODE.SINGLE) {
|
||||||
const formattedQueries = queries.map(({ query, values }) => connection.format(query, values));
|
const formattedQueries = queries.map(({ query, values }) => connection.format(query, values));
|
||||||
|
|
@ -533,7 +544,7 @@ export function addWhereClauses(
|
||||||
}${valueReplacement}${operator}`;
|
}${valueReplacement}${operator}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
return [`${query}${whereQuery}`, replacements.concat(...values)];
|
return [`${query}${whereQuery}`, replacements.concat.apply(replacements, values)];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addSortRules(
|
export function addSortRules(
|
||||||
|
|
@ -552,7 +563,7 @@ export function addSortRules(
|
||||||
orderByQuery += ` ${escapeSqlIdentifier(rule.column)} ${direction}${endWith}`;
|
orderByQuery += ` ${escapeSqlIdentifier(rule.column)} ${direction}${endWith}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
return [`${query}${orderByQuery}`, replacements.concat(...values)];
|
return [`${query}${orderByQuery}`, replacements.concat.apply(replacements, values)];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function replaceEmptyStringsByNulls(
|
export function replaceEmptyStringsByNulls(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user