fix(Postgres Node): Convert js arrays to postgres type, if column type is ARRAY (#9160)

This commit is contained in:
Michael Kret
2024-04-18 12:58:04 +03:00
committed by GitHub
parent d756609826
commit 08e35027f1
8 changed files with 160 additions and 7 deletions

View File

@@ -19,6 +19,7 @@ import {
configureTableSchemaUpdater,
getTableSchema,
prepareItem,
convertArraysToPostgresFormat,
replaceEmptyStringsByNulls,
} from '../../helpers/utils';
@@ -135,7 +136,7 @@ const properties: INodeProperties[] = [
},
displayOptions: {
show: {
'@version': [2.2, 2.3],
'@version': [{ _cnd: { gte: 2.2 } }],
},
},
},
@@ -224,6 +225,10 @@ export async function execute(
tableSchema = await updateTableSchema(db, tableSchema, schema, table);
if (nodeVersion >= 2.4) {
convertArraysToPostgresFormat(item, tableSchema, this.getNode(), i);
}
values.push(checkItemAgainstSchema(this.getNode(), item, tableSchema, i));
const outputColumns = this.getNodeParameter('options.outputColumns', i, ['*']) as string[];

View File

@@ -21,6 +21,7 @@ import {
doesRowExist,
getTableSchema,
prepareItem,
convertArraysToPostgresFormat,
replaceEmptyStringsByNulls,
} from '../../helpers/utils';
@@ -172,7 +173,7 @@ const properties: INodeProperties[] = [
},
displayOptions: {
show: {
'@version': [2.2, 2.3],
'@version': [{ _cnd: { gte: 2.2 } }],
},
},
},
@@ -301,6 +302,10 @@ export async function execute(
tableSchema = await updateTableSchema(db, tableSchema, schema, table);
if (nodeVersion >= 2.4) {
convertArraysToPostgresFormat(item, tableSchema, this.getNode(), i);
}
item = checkItemAgainstSchema(this.getNode(), item, tableSchema, i);
let values: QueryValues = [schema, table];

View File

@@ -21,6 +21,7 @@ import {
prepareItem,
replaceEmptyStringsByNulls,
configureTableSchemaUpdater,
convertArraysToPostgresFormat,
} from '../../helpers/utils';
import { optionsCollection } from '../common.descriptions';
@@ -171,7 +172,7 @@ const properties: INodeProperties[] = [
},
displayOptions: {
show: {
'@version': [2.2, 2.3],
'@version': [{ _cnd: { gte: 2.2 } }],
},
},
},
@@ -270,6 +271,10 @@ export async function execute(
tableSchema = await updateTableSchema(db, tableSchema, schema, table);
if (nodeVersion >= 2.4) {
convertArraysToPostgresFormat(item, tableSchema, this.getNode(), i);
}
item = checkItemAgainstSchema(this.getNode(), item, tableSchema, i);
let values: QueryValues = [schema, table];

View File

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

View File

@@ -16,7 +16,7 @@ export type ColumnInfo = {
data_type: string;
is_nullable: string;
udt_name?: string;
column_default?: string;
column_default?: string | null;
is_generated?: 'ALWAYS' | 'NEVER';
identity_generation?: 'ALWAYS' | 'NEVER';
};

View File

@@ -5,7 +5,7 @@ import type {
INodeExecutionData,
INodePropertyOptions,
} from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import { NodeOperationError, jsonParse } from 'n8n-workflow';
import { generatePairedItemData } from '../../../../utils/utilities';
import type {
@@ -510,3 +510,63 @@ export const configureTableSchemaUpdater = (initialSchema: string, initialTable:
return tableSchema;
};
};
/**
* If postgress column type is array we need to convert it to fornmat that postgres understands, original object data would be modified
* @param data the object with keys representing column names and values
* @param schema table schema
* @param node INode
* @param itemIndex the index of the current item
*/
export const convertArraysToPostgresFormat = (
data: IDataObject,
schema: ColumnInfo[],
node: INode,
itemIndex = 0,
) => {
for (const columnInfo of schema) {
//in case column type is array we need to convert it to fornmat that postgres understands
if (columnInfo.data_type.toUpperCase() === 'ARRAY') {
let columnValue = data[columnInfo.column_name];
if (typeof columnValue === 'string') {
columnValue = jsonParse(columnValue);
}
if (Array.isArray(columnValue)) {
const arrayEntries = columnValue.map((entry) => {
if (typeof entry === 'number') {
return entry;
}
if (typeof entry === 'boolean') {
entry = String(entry);
}
if (typeof entry === 'object') {
entry = JSON.stringify(entry);
}
if (typeof entry === 'string') {
return `"${entry.replace(/"/g, '\\"')}"`; //escape double quotes
}
return entry;
});
//wrap in {} instead of [] as postgres does and join with ,
data[columnInfo.column_name] = `{${arrayEntries.join(',')}}`;
} else {
if (columnInfo.is_nullable === 'NO') {
throw new NodeOperationError(
node,
`Column '${columnInfo.column_name}' has to be an array`,
{
itemIndex,
},
);
}
}
}
}
};