n8n/packages/nodes-base/nodes/Merge/v3/actions/mode/combineBySql.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

137 lines
3.3 KiB
TypeScript
Raw Normal View History

import type {
IDataObject,
IExecuteFunctions,
INodeExecutionData,
INodeProperties,
IPairedItemData,
} from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import alasql from 'alasql';
import type { Database } from 'alasql';
import { numberInputsProperty } from '../../helpers/descriptions';
import { getResolvables, updateDisplayOptions } from '@utils/utilities';
export const properties: INodeProperties[] = [
numberInputsProperty,
{
displayName: 'Query',
name: 'query',
type: 'string',
default: 'SELECT * FROM input1 LEFT JOIN input2 ON input1.name = input2.id',
noDataExpression: true,
description: 'Input data available as tables with corresponding number, e.g. input1, input2',
hint: 'Supports <a href="https://github.com/alasql/alasql/wiki/Supported-SQL-statements" target="_blank">most</a> of the SQL-99 language',
required: true,
typeOptions: {
rows: 5,
editor: 'sqlEditor',
},
},
];
const displayOptions = {
show: {
mode: ['combineBySql'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
inputsData: INodeExecutionData[][],
): Promise<INodeExecutionData[]> {
const nodeId = this.getNode().id;
const returnData: INodeExecutionData[] = [];
const pairedItem: IPairedItemData[] = [];
const db: typeof Database = new (alasql as any).Database(nodeId);
try {
for (let i = 0; i < inputsData.length; i++) {
const inputData = inputsData[i];
inputData.forEach((item, index) => {
if (item.pairedItem === undefined) {
item.pairedItem = index;
}
if (typeof item.pairedItem === 'number') {
pairedItem.push({
item: item.pairedItem,
input: i,
});
return;
}
if (Array.isArray(item.pairedItem)) {
const pairedItems = item.pairedItem
.filter((p) => p !== undefined)
.map((p) => (typeof p === 'number' ? { item: p } : p))
.map((p) => {
return {
item: p.item,
input: i,
};
});
pairedItem.push(...pairedItems);
return;
}
pairedItem.push({
item: item.pairedItem.item,
input: i,
});
});
db.exec(`CREATE TABLE input${i + 1}`);
db.tables[`input${i + 1}`].data = inputData.map((entry) => entry.json);
}
} catch (error) {
throw new NodeOperationError(this.getNode(), error, {
message: 'Issue while creating table from',
description: error.message,
itemIndex: 0,
});
}
try {
let query = this.getNodeParameter('query', 0) as string;
for (const resolvable of getResolvables(query)) {
query = query.replace(resolvable, this.evaluateExpression(resolvable, 0) as string);
}
const result: IDataObject[] = db.exec(query);
for (const item of result) {
if (Array.isArray(item)) {
returnData.push(...item.map((json) => ({ json, pairedItem })));
} else if (typeof item === 'object') {
returnData.push({ json: item, pairedItem });
}
}
if (!returnData.length) {
returnData.push({ json: { success: true }, pairedItem });
}
} catch (error) {
let message = '';
if (typeof error === 'string') {
message = error;
} else {
message = error.message;
}
throw new NodeOperationError(this.getNode(), error, {
message: 'Issue while executing query',
description: message,
itemIndex: 0,
});
}
delete alasql.databases[nodeId];
return returnData;
}