n8n-nodes-fuse-postgre-master
Version:
Node do n8n para buscas fuzzy no PostgreSQL usando Fuse.js.
202 lines (187 loc) • 5.45 kB
text/typescript
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;