mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
fix(Postgres Node): RMC do not mark collumn as required if identity_generation is BY DEFAULT (#13752)
Co-authored-by: Dana <152518854+dana-gill@users.noreply.github.com>
This commit is contained in:
@@ -11,7 +11,7 @@ export class Postgres extends VersionedNodeType {
|
||||
name: 'postgres',
|
||||
icon: 'file:postgres.svg',
|
||||
group: ['input'],
|
||||
defaultVersion: 2.5,
|
||||
defaultVersion: 2.6,
|
||||
description: 'Get, add and update data in Postgres',
|
||||
parameterPane: 'wide',
|
||||
};
|
||||
@@ -24,6 +24,7 @@ export class Postgres extends VersionedNodeType {
|
||||
2.3: new PostgresV2(baseDescription),
|
||||
2.4: new PostgresV2(baseDescription),
|
||||
2.5: new PostgresV2(baseDescription),
|
||||
2.6: new PostgresV2(baseDescription),
|
||||
};
|
||||
|
||||
super(nodeVersions, baseDescription);
|
||||
|
||||
@@ -713,6 +713,51 @@ describe('Test PostgresV2, insert operation', () => {
|
||||
expect(hasJsonDataTypeInSchemaSpy).toHaveBeenCalledWith(columnsInfo);
|
||||
});
|
||||
});
|
||||
|
||||
it('should insert default values if no values are provided', async () => {
|
||||
const nodeParameters: IDataObject = {
|
||||
schema: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
value: 'public',
|
||||
},
|
||||
table: {
|
||||
__rl: true,
|
||||
value: 'my_table',
|
||||
mode: 'list',
|
||||
},
|
||||
dataMode: 'defineBelow',
|
||||
valuesToSend: {
|
||||
values: [],
|
||||
},
|
||||
options: { nodeVersion: 2.6 },
|
||||
};
|
||||
const columnsInfo: ColumnInfo[] = [
|
||||
{ column_name: 'id', data_type: 'integer', is_nullable: 'NO', udt_name: '' },
|
||||
];
|
||||
|
||||
const nodeOptions = nodeParameters.options as IDataObject;
|
||||
|
||||
await insert.execute.call(
|
||||
createMockExecuteFunction(nodeParameters),
|
||||
runQueries,
|
||||
items,
|
||||
nodeOptions,
|
||||
createMockDb(columnsInfo),
|
||||
pgPromise(),
|
||||
);
|
||||
|
||||
expect(runQueries).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
query: 'INSERT INTO $1:name.$2:name DEFAULT VALUES RETURNING *',
|
||||
values: ['public', 'my_table', {}],
|
||||
},
|
||||
],
|
||||
items,
|
||||
nodeOptions,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test PostgresV2, select operation', () => {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { MockProxy } from 'jest-mock-extended';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { ILoadOptionsFunctions } from 'n8n-workflow';
|
||||
|
||||
import { getMappingColumns } from '../../v2/methods/resourceMapping';
|
||||
|
||||
jest.mock('../../transport', () => {
|
||||
const originalModule = jest.requireActual('../../transport');
|
||||
return {
|
||||
...originalModule,
|
||||
configurePostgres: jest.fn(async () => ({ db: {} })),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../v2/helpers/utils', () => {
|
||||
const originalModule = jest.requireActual('../../v2/helpers/utils');
|
||||
return {
|
||||
...originalModule,
|
||||
getEnums: jest.fn(() => []),
|
||||
getEnumValues: jest.fn(),
|
||||
getTableSchema: jest.fn(() => [
|
||||
{
|
||||
column_name: 'id',
|
||||
data_type: 'bigint',
|
||||
is_nullable: 'NO',
|
||||
udt_name: 'int8',
|
||||
column_default: null,
|
||||
identity_generation: 'BY DEFAULT',
|
||||
is_generated: 'NEVER',
|
||||
},
|
||||
{
|
||||
column_name: 'name',
|
||||
data_type: 'text',
|
||||
is_nullable: 'YES',
|
||||
udt_name: 'text',
|
||||
column_default: null,
|
||||
identity_generation: null,
|
||||
is_generated: 'NEVER',
|
||||
},
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Postgres, resourceMapping', () => {
|
||||
let loadOptionsFunctions: MockProxy<ILoadOptionsFunctions>;
|
||||
|
||||
beforeEach(() => {
|
||||
loadOptionsFunctions = mock<ILoadOptionsFunctions>();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should mark id as not required if identity_generation is "BY_DEFAULT"', async () => {
|
||||
loadOptionsFunctions.getCredentials.mockResolvedValue({});
|
||||
loadOptionsFunctions.getNodeParameter.mockReturnValueOnce('public');
|
||||
loadOptionsFunctions.getNodeParameter.mockReturnValueOnce('test_table');
|
||||
loadOptionsFunctions.getNodeParameter.mockReturnValueOnce('insert');
|
||||
|
||||
const fields = await getMappingColumns.call(loadOptionsFunctions);
|
||||
|
||||
expect(fields).toEqual({
|
||||
fields: [
|
||||
{
|
||||
canBeUsedToMatch: true,
|
||||
defaultMatch: true,
|
||||
display: true,
|
||||
displayName: 'id',
|
||||
id: 'id',
|
||||
options: undefined,
|
||||
required: false,
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
canBeUsedToMatch: true,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
displayName: 'name',
|
||||
id: 'name',
|
||||
options: undefined,
|
||||
required: false,
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -146,15 +146,15 @@ describe('Test PostgresV2, parsePostgresError', () => {
|
||||
|
||||
it('should update message with syntax error', () => {
|
||||
// eslint-disable-next-line n8n-local-rules/no-unneeded-backticks
|
||||
const errorMessage = String.raw`syntax error at or near "seelect"`;
|
||||
const errorMessage = String.raw`syntax error at or near "select"`;
|
||||
const error = new Error();
|
||||
error.message = errorMessage;
|
||||
|
||||
const parsedError = parsePostgresError(node, error, [
|
||||
{ query: 'seelect * from my_table', values: [] },
|
||||
{ query: 'select * from my_table', values: [] },
|
||||
]);
|
||||
expect(parsedError).toBeDefined();
|
||||
expect(parsedError.message).toEqual('Syntax error at line 1 near "seelect"');
|
||||
expect(parsedError.message).toEqual('Syntax error at line 1 near "select"');
|
||||
expect(parsedError instanceof NodeOperationError).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -201,7 +201,7 @@ describe('Test PostgresV2, addWhereClauses', () => {
|
||||
expect(updatedValues).toEqual(['public', 'my_table', 'id', '1', 'foo', 'select 2']);
|
||||
});
|
||||
|
||||
it('should ignore incorect combine conition ad use AND', () => {
|
||||
it('should ignore incorrect combine condition ad use AND', () => {
|
||||
const query = 'SELECT * FROM $1:name.$2:name';
|
||||
const values = ['public', 'my_table'];
|
||||
const whereClauses = [
|
||||
@@ -246,7 +246,7 @@ describe('Test PostgresV2, addSortRules', () => {
|
||||
expect(updatedQuery).toEqual('SELECT * FROM $1:name.$2:name ORDER BY $3:name DESC');
|
||||
expect(updatedValues).toEqual(['public', 'my_table', 'id']);
|
||||
});
|
||||
it('should ignore incorect direction', () => {
|
||||
it('should ignore incorrect direction', () => {
|
||||
const query = 'SELECT * FROM $1:name.$2:name';
|
||||
const values = ['public', 'my_table'];
|
||||
const sortRules = [{ column: 'id', direction: 'SELECT * FROM my_table' }];
|
||||
@@ -340,7 +340,7 @@ describe('Test PostgresV2, replaceEmptyStringsByNulls', () => {
|
||||
});
|
||||
|
||||
describe('Test PostgresV2, prepareItem', () => {
|
||||
it('should convert fixedColections values to object', () => {
|
||||
it('should convert fixedCollection values to object', () => {
|
||||
const values = [
|
||||
{
|
||||
column: 'id',
|
||||
|
||||
@@ -241,6 +241,10 @@ export async function execute(
|
||||
|
||||
const outputColumns = this.getNodeParameter('options.outputColumns', i, ['*']) as string[];
|
||||
|
||||
if (nodeVersion >= 2.6 && Object.keys(item).length === 0) {
|
||||
query = 'INSERT INTO $1:name.$2:name DEFAULT VALUES';
|
||||
}
|
||||
|
||||
[query, values] = addReturning(query, outputColumns, values);
|
||||
|
||||
queries.push({ query, values });
|
||||
|
||||
@@ -8,7 +8,7 @@ export const versionDescription: INodeTypeDescription = {
|
||||
name: 'postgres',
|
||||
icon: 'file:postgres.svg',
|
||||
group: ['input'],
|
||||
version: [2, 2.1, 2.2, 2.3, 2.4, 2.5],
|
||||
version: [2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6],
|
||||
subtitle: '={{ $parameter["operation"] }}',
|
||||
description: 'Get, add and update data in Postgres',
|
||||
defaults: {
|
||||
|
||||
@@ -74,7 +74,9 @@ export async function getMappingColumns(
|
||||
const options =
|
||||
type === 'options' ? getEnumValues(enumInfo, col.udt_name as string) : undefined;
|
||||
const hasDefault = Boolean(col.column_default);
|
||||
const isGenerated = col.is_generated === 'ALWAYS' || col.identity_generation === 'ALWAYS';
|
||||
const isGenerated =
|
||||
col.is_generated === 'ALWAYS' ||
|
||||
['ALWAYS', 'BY DEFAULT'].includes(col.identity_generation ?? '');
|
||||
const nullable = col.is_nullable === 'YES';
|
||||
return {
|
||||
id: col.column_name,
|
||||
|
||||
Reference in New Issue
Block a user