fix(Postgres Node): Upsert does not fetch columns when schema other then public (#6643)

This commit is contained in:
Michael Kret
2023-07-12 13:26:46 +03:00
committed by GitHub
parent 05007d894e
commit aaa9ee3949
12 changed files with 42 additions and 40 deletions

View File

@@ -62,7 +62,7 @@ export const optionsCollection: INodeProperties = {
type: 'string',
default: '',
description:
'Comma-separated list of the values you want to use as query parameters. <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.postgres/#use-query-parameters">More info</a>.',
'Comma-separated list of the values you want to use as query parameters. <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.postgres/#use-query-parameters" target="_blank">More info</a>.',
hint: 'Comma-separated list of values: reference them in your query as $1, $2, $3…',
placeholder: 'e.g. value1,value2,value3',
displayOptions: {
@@ -74,8 +74,9 @@ export const optionsCollection: INodeProperties = {
displayName: 'Output Columns',
name: 'outputColumns',
type: 'multiOptions',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-multi-options
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>',
typeOptions: {
loadOptionsMethod: 'getColumnsMultiOptions',
loadOptionsDependsOn: ['table.value'],
@@ -202,8 +203,9 @@ export const whereFixedCollection: INodeProperties = {
displayName: 'Column',
name: 'column',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>',
default: '',
placeholder: 'e.g. ID',
typeOptions: {
@@ -284,8 +286,9 @@ export const sortFixedCollection: INodeProperties = {
displayName: 'Column',
name: 'column',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>',
default: '',
typeOptions: {
loadOptionsMethod: 'getColumns',

View File

@@ -29,15 +29,7 @@ const properties: INodeProperties[] = [
editor: 'sqlEditor',
sqlDialect: 'PostgreSQL',
},
hint: 'Prefer using query parameters over n8n expressions to avoid SQL injection attacks',
},
{
displayName: `
To use query parameters in your SQL query, reference them as $1, $2, $3, etc in the corresponding order. <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.postgres/#use-query-parameters" target="_blank">More info</a>.
`,
name: 'notice',
type: 'notice',
default: '',
hint: 'Consider using query parameters to prevent SQL injection attacks. Add them in the options below',
},
optionsCollection,
];

View File

@@ -90,8 +90,9 @@ const properties: INodeProperties[] = [
displayName: 'Column',
name: 'column',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>',
typeOptions: {
loadOptionsMethod: 'getColumns',
loadOptionsDependsOn: ['schema.value', 'table.value'],

View File

@@ -72,8 +72,9 @@ const properties: INodeProperties[] = [
name: 'columnToMatchOn',
type: 'options',
required: true,
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The column to compare when finding the rows to update. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
'The column to compare when finding the rows to update. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>.',
typeOptions: {
loadOptionsMethod: 'getColumns',
loadOptionsDependsOn: ['schema.value', 'table.value'],
@@ -126,8 +127,9 @@ const properties: INodeProperties[] = [
displayName: 'Column',
name: 'column',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>',
typeOptions: {
loadOptionsMethod: 'getColumnsWithoutColumnToMatchOn',
loadOptionsDependsOn: ['schema.value', 'table.value'],

View File

@@ -71,8 +71,9 @@ const properties: INodeProperties[] = [
name: 'columnToMatchOn',
type: 'options',
required: true,
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The column to compare when finding the rows to update. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
'The column to compare when finding the rows to update. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>.',
typeOptions: {
loadOptionsMethod: 'getColumns',
loadOptionsDependsOn: ['schema.value', 'table.value'],
@@ -125,8 +126,9 @@ const properties: INodeProperties[] = [
displayName: 'Column',
name: 'column',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/" target="_blank">expression</a>',
typeOptions: {
loadOptionsMethod: 'getColumnsWithoutColumnToMatchOn',
loadOptionsDependsOn: ['schema.value', 'table.value'],

View File

@@ -337,16 +337,18 @@ export async function getTableSchema(
return columns;
}
export async function uniqueColumns(db: PgpDatabase, table: string) {
export async function uniqueColumns(db: PgpDatabase, table: string, schema = 'public') {
// Using the modified query from https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns
// `quote_ident` - properly quote and escape an identifier
// `::regclass` - cast a string to a regclass (internal type for object names)
const unique = await db.any(
`
SELECT DISTINCT a.attname
FROM pg_index i JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = quote_ident($1)::regclass
WHERE i.indrelid = (quote_ident($1) || '.' || quote_ident($2))::regclass
AND (i.indisprimary OR i.indisunique);
`,
[table],
[schema, table],
);
return unique as IDataObject[];
}

View File

@@ -63,7 +63,7 @@ export async function getMappingColumns(
try {
const columns = await getTableSchema(db, schema, table);
const unique = operation === 'upsert' ? await uniqueColumns(db, table) : [];
const unique = operation === 'upsert' ? await uniqueColumns(db, table, schema) : [];
const enumInfo = await getEnums(db);
const fields = await Promise.all(
columns.map(async (col) => {