🚧 insert function extracted

This commit is contained in:
Ben Hesseldieck 2020-07-08 12:01:16 +02:00
parent 9dee7a2a98
commit 0108538fcc
2 changed files with 136 additions and 133 deletions

View file

@ -2,6 +2,33 @@ import { IDataObject, INodeExecutionData } from 'n8n-workflow';
import pgPromise = require('pg-promise');
import pg = require('pg-promise/typescript/pg-subset');
/**
* Returns of copy of the items which only contains the json data and
* of that only the define properties
*
* @param {INodeExecutionData[]} items The items to copy
* @param {string[]} properties The properties it should include
* @returns
*/
function getItemCopy(
items: INodeExecutionData[],
properties: string[],
): IDataObject[] {
// Prepare the data to insert and copy it to be returned
let newItem: IDataObject;
return items.map(item => {
newItem = {};
for (const property of properties) {
if (item.json[property] === undefined) {
newItem[property] = null;
} else {
newItem[property] = JSON.parse(JSON.stringify(item.json[property]));
}
}
return newItem;
});
}
/**
* Executes the given SQL query on the database.
*
@ -9,14 +36,14 @@ import pg = require('pg-promise/typescript/pg-subset');
* @param {pgPromise.IMain<{}, pg.IClient>} pgp The pgPromise instance
* @param {pgPromise.IDatabase<{}, pg.IClient>} db The pgPromise database connection
* @param {input[]} input The Node's input data
* @returns Promise<any>
* @returns Promise<Array<object>>
*/
export function executeQuery(
getNodeParam: Function,
pgp: pgPromise.IMain<{}, pg.IClient>,
db: pgPromise.IDatabase<{}, pg.IClient>,
input: INodeExecutionData[],
): Promise<any> {
): Promise<Array<object>> {
const queries: string[] = [];
for (let i = 0; i < input.length; i++) {
queries.push(getNodeParam('query', i) as string);
@ -25,24 +52,47 @@ export function executeQuery(
return db.any(pgp.helpers.concat(queries));
}
// /**
// * Returns of copy of the items which only contains the json data and
// * of that only the define properties
// *
// * @param {items[]} items The items execute the query with
// * @param {string[]} properties The properties it should include
// * @returns
// */
// export function insert(
// getNodeParam: Function,
// pgp: pgPromise.IMain<{}, pg.IClient>,
// db: pgPromise.IDatabase<{}, pg.IClient>,
// items: INodeExecutionData[]
// ): Promise<any> {
// const queries: string[] = [];
// for (let i = 0; i < items.length; i++) {
// queries.push(getNodeParam('query', i) as string);
// }
/**
* Returns of copy of the items which only contains the json data and
* of that only the define properties
*
* @param {Function} getNodeParam The getter of the Node
* @param {pgPromise.IMain<{}, pg.IClient>} pgp The pgPromise instance
* @param {pgPromise.IDatabase<{}, pg.IClient>} db The pgPromise database connection
* @param {input[]} input The Node's input data
* @returns Promise<object>
*/
export async function executeInsert(
getNodeParam: Function,
pgp: pgPromise.IMain<{}, pg.IClient>,
db: pgPromise.IDatabase<{}, pg.IClient>,
items: INodeExecutionData[],
): Promise<Array<IDataObject[]>> {
const table = getNodeParam('table', 0) as string;
const schema = getNodeParam('schema', 0) as string;
let returnFields = (getNodeParam('returnFields', 0) as string).split(
',',
) as string[];
const columnString = getNodeParam('columns', 0) as string;
const columns = columnString.split(',').map(column => column.trim());
// return db.any(pgp.helpers.concat(queries));
// }
const cs = new pgp.helpers.ColumnSet(columns);
const te = new pgp.helpers.TableName({ table, schema });
// Prepare the data to insert and copy it to be returned
const insertItems = getItemCopy(items, columns);
// Generate the multi-row insert query and return the id of new row
returnFields = returnFields
.map(value => value.trim())
.filter(value => !!value);
const query =
pgp.helpers.insert(insertItems, cs, te) +
(returnFields.length ? ` RETURNING ${returnFields.join(',')}` : '');
// Executing the query to insert the data
const insertData = await db.manyOrNone(query);
return [insertData, insertItems];
}

View file

@ -3,39 +3,12 @@ import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription
INodeTypeDescription,
} from 'n8n-workflow';
import * as pgPromise from 'pg-promise';
import { executeQuery } from './Postgres.node.functions';
/**
* Returns of copy of the items which only contains the json data and
* of that only the define properties
*
* @param {INodeExecutionData[]} items The items to copy
* @param {string[]} properties The properties it should include
* @returns
*/
function getItemCopy(
items: INodeExecutionData[],
properties: string[]
): IDataObject[] {
// Prepare the data to insert and copy it to be returned
let newItem: IDataObject;
return items.map(item => {
newItem = {};
for (const property of properties) {
if (item.json[property] === undefined) {
newItem[property] = null;
} else {
newItem[property] = JSON.parse(JSON.stringify(item.json[property]));
}
}
return newItem;
});
}
import { executeInsert, executeQuery } from './Postgres.node.functions';
export class Postgres implements INodeType {
description: INodeTypeDescription = {
@ -47,15 +20,15 @@ export class Postgres implements INodeType {
description: 'Gets, add and update data in Postgres.',
defaults: {
name: 'Postgres',
color: '#336791'
color: '#336791',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'postgres',
required: true
}
required: true,
},
],
properties: [
{
@ -66,21 +39,21 @@ export class Postgres implements INodeType {
{
name: 'Execute Query',
value: 'executeQuery',
description: 'Executes a SQL query.'
description: 'Executes a SQL query.',
},
{
name: 'Insert',
value: 'insert',
description: 'Insert rows in database.'
description: 'Insert rows in database.',
},
{
name: 'Update',
value: 'update',
description: 'Updates rows in database.'
}
description: 'Updates rows in database.',
},
],
default: 'insert',
description: 'The operation to perform.'
description: 'The operation to perform.',
},
// ----------------------------------
@ -91,17 +64,17 @@ export class Postgres implements INodeType {
name: 'query',
type: 'string',
typeOptions: {
rows: 5
rows: 5,
},
displayOptions: {
show: {
operation: ['executeQuery']
}
operation: ['executeQuery'],
},
},
default: '',
placeholder: 'SELECT id, name FROM product WHERE id < 40',
required: true,
description: 'The SQL query to execute.'
description: 'The SQL query to execute.',
},
// ----------------------------------
@ -113,12 +86,12 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['insert']
}
operation: ['insert'],
},
},
default: 'public',
required: true,
description: 'Name of the schema the table belongs to'
description: 'Name of the schema the table belongs to',
},
{
displayName: 'Table',
@ -126,12 +99,12 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['insert']
}
operation: ['insert'],
},
},
default: '',
required: true,
description: 'Name of the table in which to insert data to.'
description: 'Name of the table in which to insert data to.',
},
{
displayName: 'Columns',
@ -139,13 +112,13 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['insert']
}
operation: ['insert'],
},
},
default: '',
placeholder: 'id,name,description',
description:
'Comma separated list of the properties which should used as columns for the new rows.'
'Comma separated list of the properties which should used as columns for the new rows.',
},
{
displayName: 'Return Fields',
@ -153,12 +126,12 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['insert']
}
operation: ['insert'],
},
},
default: '*',
description:
'Comma separated list of the fields that the operation will return'
'Comma separated list of the fields that the operation will return',
},
// ----------------------------------
@ -170,12 +143,12 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['update']
}
operation: ['update'],
},
},
default: '',
required: true,
description: 'Name of the table in which to update data in'
description: 'Name of the table in which to update data in',
},
{
displayName: 'Update Key',
@ -183,13 +156,13 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['update']
}
operation: ['update'],
},
},
default: 'id',
required: true,
description:
'Name of the property which decides which rows in the database should be updated. Normally that would be "id".'
'Name of the property which decides which rows in the database should be updated. Normally that would be "id".',
},
{
displayName: 'Columns',
@ -197,15 +170,15 @@ export class Postgres implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: ['update']
}
operation: ['update'],
},
},
default: '',
placeholder: 'name,description',
description:
'Comma separated list of the properties which should used as columns for rows to update.'
}
]
'Comma separated list of the properties which should used as columns for rows to update.',
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
@ -224,9 +197,9 @@ export class Postgres implements INodeType {
user: credentials.user as string,
password: credentials.password as string,
ssl: !['disable', undefined].includes(
credentials.ssl as string | undefined
credentials.ssl as string | undefined,
),
sslmode: (credentials.ssl as string) || 'disable'
sslmode: (credentials.ssl as string) || 'disable',
};
const db = pgp(config);
@ -245,7 +218,7 @@ export class Postgres implements INodeType {
this.getNodeParameter,
pgp,
db,
items
items,
);
returnItems = this.helpers.returnJsonArray(queryResult as IDataObject[]);
@ -254,40 +227,20 @@ export class Postgres implements INodeType {
// insert
// ----------------------------------
const table = this.getNodeParameter('table', 0) as string;
const schema = this.getNodeParameter('schema', 0) as string;
let returnFields = (this.getNodeParameter(
'returnFields',
0
) as string).split(',') as string[];
const columnString = this.getNodeParameter('columns', 0) as string;
const columns = columnString.split(',').map(column => column.trim());
const cs = new pgp.helpers.ColumnSet(columns);
const te = new pgp.helpers.TableName({ table, schema });
// Prepare the data to insert and copy it to be returned
const insertItems = getItemCopy(items, columns);
// Generate the multi-row insert query and return the id of new row
returnFields = returnFields
.map(value => value.trim())
.filter(value => !!value);
const query =
pgp.helpers.insert(insertItems, cs, te) +
(returnFields.length ? ` RETURNING ${returnFields.join(',')}` : '');
// Executing the query to insert the data
const insertData = await db.manyOrNone(query);
const [insertData, insertItems] = await executeInsert(
this.getNodeParameter,
pgp,
db,
items,
);
// Add the id to the data
for (let i = 0; i < insertData.length; i++) {
returnItems.push({
json: {
...insertData[i],
...insertItems[i]
}
...insertItems[i],
},
});
}
} else if (operation === 'update') {
@ -301,26 +254,26 @@ export class Postgres implements INodeType {
const columns = columnString.split(',').map(column => column.trim());
// Make sure that the updateKey does also get queried
if (!columns.includes(updateKey)) {
columns.unshift(updateKey);
}
// // Make sure that the updateKey does also get queried
// if (!columns.includes(updateKey)) {
// columns.unshift(updateKey);
// }
// Prepare the data to update and copy it to be returned
const updateItems = getItemCopy(items, columns);
// // Prepare the data to update and copy it to be returned
// const updateItems = getItemCopy(items, columns);
// Generate the multi-row update query
const query =
pgp.helpers.update(updateItems, columns, table) +
' WHERE v.' +
updateKey +
' = t.' +
updateKey;
// // Generate the multi-row update query
// const query =
// pgp.helpers.update(updateItems, columns, table) +
// ' WHERE v.' +
// updateKey +
// ' = t.' +
// updateKey;
// Executing the query to update the data
await db.none(query);
// // Executing the query to update the data
// await db.none(query);
returnItems = this.helpers.returnJsonArray(updateItems as IDataObject[]);
// returnItems = this.helpers.returnJsonArray(updateItems as IDataObject[]);
} else {
await pgp.end();
throw new Error(`The operation "${operation}" is not supported!`);