import { Injectable, Inject } from '@nestjs/common'; import { QueryRunner, DataSource } from 'typeorm'; import { DATA_SOURCE } from '../core/constants'; import { RedisClientToken } from '../core/configs/cache/redis-client.adapter.provider'; import { IRedisClient } from '../core/configs/cache/IRedisClient'; import { getOrSetCache } from '../shared/cache.util'; import { PartnerDto } from './dto/partner.dto'; @Injectable() export class PartnersService { private readonly PARTNERS_TTL = 60 * 60 * 12; // 12 horas private readonly PARTNERS_CACHE_KEY = 'parceiros:search'; constructor( @Inject(DATA_SOURCE) private readonly dataSource: DataSource, @Inject(RedisClientToken) private readonly redisClient: IRedisClient, ) {} /** * Buscar parceiros com cache otimizado * @param filter - Filtro de busca (ID, CPF ou nome) * @returns Array de parceiros encontrados */ async findPartners(filter: string): Promise { const cacheKey = `${this.PARTNERS_CACHE_KEY}:${filter}`; return getOrSetCache( this.redisClient, cacheKey, this.PARTNERS_TTL, async () => { const queryRunner: QueryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { // Primeira tentativa: busca por ID do parceiro let sql = `SELECT ESTPARCEIRO.ID as "id", ESTPARCEIRO.ID || ' - ' || ESTPARCEIRO.NOME || ' ( ' || ESTPARCEIRO.CPF || ' )' as "name", ESTPARCEIRO.CPF as "cpf" FROM ESTPARCEIRO WHERE ESTPARCEIRO.ID = REGEXP_REPLACE('${filter}', '[^0-9]', '') ORDER BY ESTPARCEIRO.NOME`; let partners = await queryRunner.manager.query(sql); // Segunda tentativa: busca por CPF se não encontrou por ID if (partners.length === 0) { sql = `SELECT ESTPARCEIRO.ID as "id", ESTPARCEIRO.ID || ' - ' || ESTPARCEIRO.NOME || ' ( ' || ESTPARCEIRO.CPF || ' )' as "name", ESTPARCEIRO.CPF as "cpf" FROM ESTPARCEIRO WHERE REGEXP_REPLACE(ESTPARCEIRO.CPF, '[^0-9]', '') = REGEXP_REPLACE('${filter}', '[^0-9]', '') ORDER BY ESTPARCEIRO.NOME`; partners = await queryRunner.manager.query(sql); } // Terceira tentativa: busca por nome do parceiro se não encontrou por ID ou CPF if (partners.length === 0) { sql = `SELECT ESTPARCEIRO.ID as "id", ESTPARCEIRO.ID || ' - ' || ESTPARCEIRO.NOME || ' ( ' || ESTPARCEIRO.CPF || ' )' as "name", ESTPARCEIRO.CPF as "cpf" FROM ESTPARCEIRO WHERE ESTPARCEIRO.NOME LIKE '${filter.toUpperCase().replace('@', '%')}%' ORDER BY ESTPARCEIRO.NOME`; partners = await queryRunner.manager.query(sql); } return partners.map(partner => new PartnerDto({ id: partner.id, cpf: partner.cpf, nome: partner.name })); } finally { await queryRunner.release(); } } ); } /** * Buscar todos os parceiros com cache * @returns Array de todos os parceiros */ async getAllPartners(): Promise { const cacheKey = 'parceiros:all'; return getOrSetCache( this.redisClient, cacheKey, this.PARTNERS_TTL, async () => { const queryRunner: QueryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { const sql = `SELECT ESTPARCEIRO.ID as "id", ESTPARCEIRO.ID || ' - ' || ESTPARCEIRO.NOME || ' ( ' || ESTPARCEIRO.CPF || ' )' as "name", ESTPARCEIRO.CPF as "cpf" FROM ESTPARCEIRO ORDER BY ESTPARCEIRO.NOME`; const partners = await queryRunner.manager.query(sql); return partners.map(partner => new PartnerDto({ id: partner.id, cpf: partner.cpf, nome: partner.name })); } finally { await queryRunner.release(); } } ); } /** * Buscar parceiro por ID específico com cache * @param partnerId - ID do parceiro * @returns Parceiro encontrado ou null */ async getPartnerById(partnerId: string): Promise { const cacheKey = `parceiros:id:${partnerId}`; return getOrSetCache( this.redisClient, cacheKey, this.PARTNERS_TTL, async () => { const queryRunner: QueryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { const sql = `SELECT ESTPARCEIRO.ID as "id", ESTPARCEIRO.ID || ' - ' || ESTPARCEIRO.NOME || ' ( ' || ESTPARCEIRO.CPF || ' )' as "name", ESTPARCEIRO.CPF as "cpf" FROM ESTPARCEIRO WHERE ESTPARCEIRO.ID = '${partnerId}'`; const partners = await queryRunner.manager.query(sql); return partners.length > 0 ? new PartnerDto({ id: partners[0].id, cpf: partners[0].cpf, nome: partners[0].name }) : null; } finally { await queryRunner.release(); } } ); } /** * Limpar cache de parceiros (útil para invalidação) * @param pattern - Padrão de chaves para limpar (opcional) */ async clearPartnersCache(pattern?: string) { const cachePattern = pattern || 'parceiros:*'; // Nota: Esta funcionalidade requer implementação específica do Redis // Por enquanto, mantemos a interface para futuras implementações console.log(`Cache de parceiros seria limpo para o padrão: ${cachePattern}`); } }