UNPKG

n8n-nodes-fuse-postgre-master

Version:

Node do n8n para buscas fuzzy no PostgreSQL usando Fuse.js.

202 lines (187 loc) 5.45 kB
import { IExecuteFunctions } from 'n8n-core'; import { INodeExecutionData, INodeType, INodeTypeDescription, IDataObject, } from 'n8n-workflow'; import { Client } from 'pg'; import Fuse from 'fuse.js'; export class FusePostgre implements INodeType { description: INodeTypeDescription = { displayName: 'Fuse Postgre', name: 'fusePostgre', icon: 'fa:search', group: ['transform'], version: 1, description: 'Busca fuzzy no PostgreSQL usando Fuse.js', defaults: { name: 'Fuse Postgre', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'postgres', required: true, }, ], properties: [ { displayName: 'Tabela', name: 'table', type: 'string', default: '', placeholder: 'nome_da_tabela', description: 'Nome da tabela para buscar', required: true, }, { displayName: 'Campo de Busca', name: 'searchField', type: 'string', default: '', placeholder: 'nome, email, descricao', description: 'Campo(s) para realizar a busca (separados por vírgula)', required: true, }, { displayName: 'Termo de Busca', name: 'searchTerm', type: 'string', default: '', placeholder: 'termo para buscar', description: 'Termo que será buscado usando Fuse.js', required: true, }, { displayName: 'Limite de Resultados', name: 'limit', type: 'number', default: 10, description: 'Número máximo de resultados a retornar', }, { displayName: 'Configurações do Fuse.js', name: 'fuseOptions', type: 'collection', default: {}, options: [ { displayName: 'Threshold', name: 'threshold', type: 'number', default: 0.6, description: 'Limite de similaridade (0 = perfeita, 1 = qualquer coisa)', typeOptions: { minValue: 0, maxValue: 1, numberStepSize: 0.1, }, }, { displayName: 'Distance', name: 'distance', type: 'number', default: 100, description: 'Distância máxima entre caracteres para considerar uma correspondência', }, { displayName: 'MinMatchCharLength', name: 'minMatchCharLength', type: 'number', default: 1, description: 'Comprimento mínimo de caracteres que devem corresponder', }, { displayName: 'IsCaseSensitive', name: 'isCaseSensitive', type: 'boolean', default: false, description: 'Se a busca deve ser sensível a maiúsculas/minúsculas', }, ], }, { displayName: 'Condições WHERE', name: 'whereConditions', type: 'string', default: '', placeholder: "status = 'ativo' AND created_at > '2023-01-01'", description: 'Condições SQL adicionais para filtrar os dados (opcional)', }, ], }; async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; for (let i = 0; i < items.length; i++) { try { const table = this.getNodeParameter('table', i) as string; const searchField = this.getNodeParameter('searchField', i) as string; const searchTerm = this.getNodeParameter('searchTerm', i) as string; const limit = this.getNodeParameter('limit', i) as number; const fuseOptions = this.getNodeParameter('fuseOptions', i) as IDataObject; const whereConditions = this.getNodeParameter('whereConditions', i) as string; // Obter credenciais do PostgreSQL const credentials = await this.getCredentials('postgres'); const client = new Client({ 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, ssl: credentials.ssl as boolean ? { rejectUnauthorized: false } : false, }); await client.connect(); // Construir query SQL let query = `SELECT * FROM "${table}"`; if (whereConditions) { query += ` WHERE ${whereConditions}`; } // Executar query const result = await client.query(query); await client.end(); // Preparar dados para Fuse.js const searchFields = searchField.split(',').map(field => field.trim()); const fuse = new Fuse(result.rows, { keys: searchFields, threshold: (fuseOptions.threshold as number) || 0.6, distance: (fuseOptions.distance as number) || 100, minMatchCharLength: (fuseOptions.minMatchCharLength as number) || 1, isCaseSensitive: (fuseOptions.isCaseSensitive as boolean) || false, }); // Realizar busca fuzzy const searchResults = fuse.search(searchTerm); // Limitar resultados const limitedResults = searchResults.slice(0, limit); // Preparar dados de retorno const returnItem: INodeExecutionData = { json: { searchTerm, totalResults: searchResults.length, limitedResults: limitedResults.length, results: limitedResults.map(result => ({ item: result.item, score: result.score, refIndex: result.refIndex, })), }, }; returnData.push(returnItem); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error instanceof Error ? error.message : String(error), }, }); continue; } throw error; } } return [returnData]; } } export default FusePostgre;