n8n/packages/nodes-base/nodes/Postgres/Postgres.node.ts

419 lines
11 KiB
TypeScript
Raw Normal View History

2019-08-21 09:44:10 -07:00
import { IExecuteFunctions } from 'n8n-core';
import {
ICredentialsDecrypted,
ICredentialTestFunctions,
2019-08-21 09:44:10 -07:00
IDataObject,
INodeCredentialTestResult,
2019-08-21 09:44:10 -07:00
INodeExecutionData,
INodeType,
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
INodeTypeDescription,
NodeOperationError,
2019-08-21 09:44:10 -07:00
} from 'n8n-workflow';
import pgPromise from 'pg-promise';
2019-08-21 09:44:10 -07:00
import { pgInsertV2, pgQueryV2, pgUpdate } from './Postgres.node.functions';
2019-08-21 09:44:10 -07:00
export class Postgres implements INodeType {
description: INodeTypeDescription = {
displayName: 'Postgres',
name: 'postgres',
icon: 'file:postgres.svg',
2019-08-21 09:44:10 -07:00
group: ['input'],
version: 1,
description: 'Get, add and update data in Postgres',
2019-08-21 09:44:10 -07:00
defaults: {
name: 'Postgres',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'postgres',
required: true,
testedBy: 'postgresConnectionTest',
},
2019-08-21 09:44:10 -07:00
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
refactor: Apply more nodelinting rules (#3324) * :pencil2: Alphabetize lint rules * :fire: Remove duplicates * :zap: Update `lintfix` script * :shirt: Apply `node-param-operation-without-no-data-expression` (#3329) * :shirt: Apply `node-param-operation-without-no-data-expression` * :shirt: Add exceptions * :shirt: Apply `node-param-description-weak` (#3328) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-option-value-duplicate` (#3331) * :shirt: Apply `node-param-description-miscased-json` (#3337) * :shirt: Apply `node-param-display-name-excess-inner-whitespace` (#3335) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-type-options-missing-from-limit` (#3336) * Rule workig as intended * :pencil2: Uncomment rules Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-option-name-duplicate` (#3338) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-description-wrong-for-simplify` (#3334) * :zap: fix * :zap: exceptions * :zap: changed rule ignoring from file to line * :shirt: Apply `node-param-resource-without-no-data-expression` (#3339) * :shirt: Apply `node-param-display-name-untrimmed` (#3341) * :shirt: Apply `node-param-display-name-miscased-id` (#3340) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-resource-with-plural-option` (#3342) * :shirt: Apply `node-param-description-wrong-for-upsert` (#3333) * :zap: fix * :zap: replaced record with contact in description * :zap: fix Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-option-description-identical-to-name` (#3343) * :shirt: Apply `node-param-option-name-containing-star` (#3347) * :shirt: Apply `node-param-display-name-wrong-for-update-fields` (#3348) * :shirt: Apply `node-param-option-name-wrong-for-get-all` (#3345) * :zap: fix * :zap: exceptions * :shirt: Apply node-param-display-name-wrong-for-simplify (#3344) * Rule working as intended * Uncomented other rules * :shirt: Undo and add exceptions Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :zap: Alphabetize lint rules * :zap: Restore `lintfix` script Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com> Co-authored-by: agobrech <45268029+agobrech@users.noreply.github.com>
2022-05-20 14:47:24 -07:00
noDataExpression: true,
2019-08-21 09:44:10 -07:00
options: [
{
name: 'Execute Query',
value: 'executeQuery',
description: 'Execute an SQL query',
action: 'Execute a SQL query',
2019-08-21 09:44:10 -07:00
},
{
name: 'Insert',
value: 'insert',
description: 'Insert rows in database',
action: 'Insert rows in database',
2019-08-21 09:44:10 -07:00
},
{
name: 'Update',
value: 'update',
description: 'Update rows in database',
action: 'Update rows in database',
},
2019-08-21 09:44:10 -07:00
],
default: 'insert',
},
// ----------------------------------
// executeQuery
// ----------------------------------
{
displayName: 'Query',
name: 'query',
type: 'string',
displayOptions: {
show: {
operation: ['executeQuery'],
},
2019-08-21 09:44:10 -07:00
},
default: '',
placeholder: 'SELECT id, name FROM product WHERE quantity > $1 AND price <= $2',
2019-08-21 09:44:10 -07:00
required: true,
description:
'The SQL query to execute. You can use n8n expressions or $1 and $2 in conjunction with query parameters.',
2019-08-21 09:44:10 -07:00
},
{
displayName:
'Due to the behavior of the Multiple Queries mode, if you want to use the PairedItem feature, you need to use either the independent or the transaction mode under Additional Fields.',
name: 'pairedItemsNotice',
type: 'notice',
displayOptions: {
show: {
operation: ['executeQuery'],
},
},
default: '',
},
2019-08-21 09:44:10 -07:00
// ----------------------------------
// insert
// ----------------------------------
2020-03-17 16:49:21 -07:00
{
displayName: 'Schema',
name: 'schema',
type: 'string',
displayOptions: {
show: {
operation: ['insert'],
},
2020-03-17 16:49:21 -07:00
},
default: 'public',
required: true,
description: 'Name of the schema the table belongs to',
2020-03-17 16:49:21 -07:00
},
2019-08-21 09:44:10 -07:00
{
displayName: 'Table',
name: 'table',
type: 'string',
displayOptions: {
show: {
operation: ['insert'],
},
2019-08-21 09:44:10 -07:00
},
default: '',
required: true,
description: 'Name of the table in which to insert data to',
2019-08-21 09:44:10 -07:00
},
{
displayName: 'Columns',
name: 'columns',
type: 'string',
displayOptions: {
show: {
operation: ['insert'],
},
2019-08-21 09:44:10 -07:00
},
default: '',
refactor: Apply more `eslint-plugin-n8n-nodes-base` autofixable rules (#3432) * :zap: Update `lintfix` script * :shirt: Remove unneeded lint exceptions * :shirt: Run baseline `lintfix` * :shirt: Apply `node-param-description-miscased-url` (#3441) * :shirt: Apply `rule node-param-placeholder-miscased-id` (#3443) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-option-name-wrong-for-upsert` (#3446) * :shirt: Apply `node-param-min-value-wrong-for-limit` (#3442) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * Apply `node-param-display-name-wrong-for-dynamic-options` (#3454) * :hammer: fix * :zap: Fix `Assigned To` fields Co-authored-by: Michael Kret <michael.k@radency.com> * :shirt: Apply `rule node-param-default-wrong-for-number` (#3453) * :shirt: Apply `node-param-default-wrong-for-string` (#3452) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * Apply `node-param-display-name-miscased` (#3449) * :hammer: fix * :hammer: exceptions * :zap: review fixes * :shirt: Apply `node-param-description-lowercase-first-char` (#3451) * :zap: fix * :zap: review fixes * :zap: fix Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-description-wrong-for-dynamic-options` (#3456) * Rule working as intended * Add rule * :fire: Remove repetitions * :shirt: Add exceptions Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Small fix for `node-param-description-wrong-for-dynamic-options` * :shirt: Apply `node-param-default-wrong-for-fixed-collection` (#3460) * :shirt: Apply `node-param-description-line-break-html-tag` (#3462) * :shirt: Run baseline `lintfix` * :shirt: Apply `node-param-options-type-unsorted-items` (#3459) * :zap: fix * :hammer: exceptions * Add exception for Salesmate and Zoom Co-authored-by: Michael Kret <michael.k@radency.com> Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :zap: Restore `lintfix` command Co-authored-by: Omar Ajoue <krynble@gmail.com> Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com> Co-authored-by: agobrech <45268029+agobrech@users.noreply.github.com> Co-authored-by: Michael Kret <michael.k@radency.com> Co-authored-by: brianinoa <54530642+brianinoa@users.noreply.github.com>
2022-06-03 10:23:49 -07:00
// eslint-disable-next-line n8n-nodes-base/node-param-placeholder-miscased-id
placeholder: 'id:int,name:text,description',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-id
description:
'Comma-separated list of the properties which should used as columns for the new rows. You can use type casting with colons (:) like id:int.',
2019-08-21 09:44:10 -07:00
},
// ----------------------------------
// update
// ----------------------------------
{
displayName: 'Schema',
name: 'schema',
type: 'string',
displayOptions: {
show: {
operation: ['update'],
},
},
default: 'public',
description: 'Name of the schema the table belongs to',
},
2019-08-21 09:44:10 -07:00
{
displayName: 'Table',
name: 'table',
type: 'string',
displayOptions: {
show: {
operation: ['update'],
},
2019-08-21 09:44:10 -07:00
},
default: '',
required: true,
description: 'Name of the table in which to update data in',
2019-08-21 09:44:10 -07:00
},
{
displayName: 'Update Key',
name: 'updateKey',
type: 'string',
displayOptions: {
show: {
operation: ['update'],
},
2019-08-21 09:44:10 -07:00
},
default: 'id',
required: true,
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-id
description:
'Comma-separated list of the properties which decides which rows in the database should be updated. Normally that would be "id".',
2019-08-21 09:44:10 -07:00
},
{
displayName: 'Columns',
name: 'columns',
type: 'string',
displayOptions: {
show: {
operation: ['update'],
},
2019-08-21 09:44:10 -07:00
},
default: '',
placeholder: 'name:text,description',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-id
description:
'Comma-separated list of the properties which should used as columns for rows to update. You can use type casting with colons (:) like id:int.',
},
// ----------------------------------
// insert,update
// ----------------------------------
{
displayName: 'Return Fields',
name: 'returnFields',
type: 'string',
displayOptions: {
show: {
operation: ['insert', 'update'],
},
},
default: '*',
refactor: Apply `eslint-plugin-n8n-nodes-base` autofixable rules (#3174) * :zap: Initial setup * :shirt: Update `.eslintignore` * :shirt: Autofix node-param-default-missing (#3173) * :fire: Remove duplicate key * :shirt: Add exceptions * :package: Update package-lock.json * :shirt: Apply `node-class-description-inputs-wrong-trigger-node` (#3176) * :shirt: Apply `node-class-description-inputs-wrong-regular-node` (#3177) * :shirt: Apply `node-class-description-outputs-wrong` (#3178) * :shirt: Apply `node-execute-block-double-assertion-for-items` (#3179) * :shirt: Apply `node-param-default-wrong-for-collection` (#3180) * :shirt: Apply node-param-default-wrong-for-boolean (#3181) * Autofixed default missing * Autofixed booleans, worked well * :zap: Fix params * :rewind: Undo exempted autofixes * :package: Update package-lock.json * :shirt: Apply node-class-description-missing-subtitle (#3182) * :zap: Fix missing comma * :shirt: Apply `node-param-default-wrong-for-fixed-collection` (#3184) * :shirt: Add exception for `node-class-description-missing-subtitle` * :shirt: Apply `node-param-default-wrong-for-multi-options` (#3185) * :shirt: Apply `node-param-collection-type-unsorted-items` (#3186) * Missing coma * :shirt: Apply `node-param-default-wrong-for-simplify` (#3187) * :shirt: Apply `node-param-description-comma-separated-hyphen` (#3190) * :shirt: Apply `node-param-description-empty-string` (#3189) * :shirt: Apply `node-param-description-excess-inner-whitespace` (#3191) * Rule looks good * Add whitespace rule in eslint config * :zao: fix * :shirt: Apply `node-param-description-identical-to-display-name` (#3193) * :shirt: Apply `node-param-description-missing-for-ignore-ssl-issues` (#3195) * :rewind: Revert ":zao: fix" This reverts commit ef8a76f3dfedffd1bdccf3178af8a8d90cf5a55c. * :shirt: Apply `node-param-description-missing-for-simplify` (#3196) * :shirt: Apply `node-param-description-missing-final-period` (#3194) * Rule working as intended * Add rule to eslint * :shirt: Apply node-param-description-missing-for-return-all (#3197) * :zap: Restore `lintfix` command Co-authored-by: agobrech <45268029+agobrech@users.noreply.github.com> Co-authored-by: Omar Ajoue <krynble@gmail.com> Co-authored-by: agobrech <ael.gobrecht@gmail.com> Co-authored-by: Michael Kret <michael.k@radency.com>
2022-04-22 09:29:51 -07:00
description: 'Comma-separated list of the fields that the operation will return',
},
// ----------------------------------
// Additional fields
// ----------------------------------
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Mode',
name: 'mode',
type: 'options',
options: [
{
name: 'Independently',
value: 'independently',
description: 'Execute each query independently',
},
{
refactor: Apply more `eslint-plugin-n8n-nodes-base` autofixable rules (#3432) * :zap: Update `lintfix` script * :shirt: Remove unneeded lint exceptions * :shirt: Run baseline `lintfix` * :shirt: Apply `node-param-description-miscased-url` (#3441) * :shirt: Apply `rule node-param-placeholder-miscased-id` (#3443) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-option-name-wrong-for-upsert` (#3446) * :shirt: Apply `node-param-min-value-wrong-for-limit` (#3442) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * Apply `node-param-display-name-wrong-for-dynamic-options` (#3454) * :hammer: fix * :zap: Fix `Assigned To` fields Co-authored-by: Michael Kret <michael.k@radency.com> * :shirt: Apply `rule node-param-default-wrong-for-number` (#3453) * :shirt: Apply `node-param-default-wrong-for-string` (#3452) Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * Apply `node-param-display-name-miscased` (#3449) * :hammer: fix * :hammer: exceptions * :zap: review fixes * :shirt: Apply `node-param-description-lowercase-first-char` (#3451) * :zap: fix * :zap: review fixes * :zap: fix Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Apply `node-param-description-wrong-for-dynamic-options` (#3456) * Rule working as intended * Add rule * :fire: Remove repetitions * :shirt: Add exceptions Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :shirt: Small fix for `node-param-description-wrong-for-dynamic-options` * :shirt: Apply `node-param-default-wrong-for-fixed-collection` (#3460) * :shirt: Apply `node-param-description-line-break-html-tag` (#3462) * :shirt: Run baseline `lintfix` * :shirt: Apply `node-param-options-type-unsorted-items` (#3459) * :zap: fix * :hammer: exceptions * Add exception for Salesmate and Zoom Co-authored-by: Michael Kret <michael.k@radency.com> Co-authored-by: Iván Ovejero <ivov.src@gmail.com> * :zap: Restore `lintfix` command Co-authored-by: Omar Ajoue <krynble@gmail.com> Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com> Co-authored-by: agobrech <45268029+agobrech@users.noreply.github.com> Co-authored-by: Michael Kret <michael.k@radency.com> Co-authored-by: brianinoa <54530642+brianinoa@users.noreply.github.com>
2022-06-03 10:23:49 -07:00
name: 'Multiple Queries',
value: 'multiple',
description: '<b>Default</b>. Sends multiple queries at once to database.',
},
{
name: 'Transaction',
value: 'transaction',
description: 'Executes all queries in a single transaction',
},
],
default: 'multiple',
description:
'The way queries should be sent to database. Can be used in conjunction with <b>Continue on Fail</b>. See <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.postgres/">the docs</a> for more examples',
},
{
displayName: 'Output Large-Format Numbers As',
name: 'largeNumbersOutput',
type: 'options',
options: [
{
name: 'Numbers',
value: 'numbers',
},
{
name: 'Text',
value: 'text',
description:
'Use this if you expect numbers longer than 16 digits (otherwise numbers may be incorrect)',
},
],
hint: 'Applies to NUMERIC and BIGINT columns only',
default: 'text',
},
{
displayName: 'Query Parameters',
name: 'queryParams',
type: 'string',
displayOptions: {
show: {
'/operation': ['executeQuery'],
},
},
default: '',
placeholder: 'quantity,price',
description:
'Comma-separated list of properties which should be used as query parameters',
},
],
},
],
2019-08-21 09:44:10 -07:00
};
methods = {
credentialTest: {
async postgresConnectionTest(
this: ICredentialTestFunctions,
credential: ICredentialsDecrypted,
): Promise<INodeCredentialTestResult> {
const credentials = credential.data as IDataObject;
try {
const pgp = pgPromise();
const config: IDataObject = {
host: credentials.host as string,
port: credentials.port as number,
database: credentials.database as string,
user: credentials.user as string,
password: credentials.password as string,
};
if (credentials.allowUnauthorizedCerts === true) {
config.ssl = {
rejectUnauthorized: false,
};
} else {
config.ssl = !['disable', undefined].includes(credentials.ssl as string | undefined);
config.sslmode = (credentials.ssl as string) || 'disable';
}
const db = pgp(config);
await db.connect();
pgp.end();
} catch (error) {
return {
status: 'Error',
message: error.message,
};
}
return {
status: 'OK',
message: 'Connection successful!',
};
},
},
};
2019-08-21 09:44:10 -07:00
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const credentials = await this.getCredentials('postgres');
const largeNumbersOutput = this.getNodeParameter(
'additionalFields.largeNumbersOutput',
0,
'',
) as string;
2019-08-21 09:44:10 -07:00
const pgp = pgPromise();
if (largeNumbersOutput === 'numbers') {
pgp.pg.types.setTypeParser(20, (value: string) => {
return parseInt(value, 10);
});
pgp.pg.types.setTypeParser(1700, (value: string) => {
return parseFloat(value);
});
}
const config: IDataObject = {
host: credentials.host as string,
port: credentials.port as number,
database: credentials.database as string,
user: credentials.user as string,
password: credentials.password as string,
};
if (credentials.allowUnauthorizedCerts === true) {
config.ssl = {
rejectUnauthorized: false,
};
} else {
config.ssl = !['disable', undefined].includes(credentials.ssl as string | undefined);
config.sslmode = (credentials.ssl as string) || 'disable';
}
const db = pgp(config);
2019-08-21 09:44:10 -07:00
let returnItems: INodeExecutionData[] = [];
2019-08-21 09:44:10 -07:00
const items = this.getInputData();
const operation = this.getNodeParameter('operation', 0);
2019-08-21 09:44:10 -07:00
if (operation === 'executeQuery') {
// ----------------------------------
// executeQuery
// ----------------------------------
const queryResult = await pgQueryV2.call(this, pgp, db, items, this.continueOnFail());
returnItems = queryResult as INodeExecutionData[];
2019-08-21 09:44:10 -07:00
} else if (operation === 'insert') {
// ----------------------------------
// insert
// ----------------------------------
const insertData = await pgInsertV2.call(this, pgp, db, items, this.continueOnFail());
2019-08-21 09:44:10 -07:00
// returnItems = this.helpers.returnJsonArray(insertData);
returnItems = insertData as INodeExecutionData[];
2019-08-21 09:44:10 -07:00
} else if (operation === 'update') {
// ----------------------------------
// update
// ----------------------------------
const updateItems = await pgUpdate(
this.getNodeParameter,
pgp,
db,
items,
this.continueOnFail(),
);
2019-08-21 09:44:10 -07:00
2020-07-08 05:36:40 -07:00
returnItems = this.helpers.returnJsonArray(updateItems);
2019-08-21 09:44:10 -07:00
} else {
pgp.end();
throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not supported!`,
);
2019-08-21 09:44:10 -07:00
}
// Close the connection
pgp.end();
2019-08-21 09:44:10 -07:00
return this.prepareOutputData(returnItems);
}
}