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'; @Injectable() export class clientesService { private readonly CUSTOMERS_TTL = 60 * 60 * 12; // 12 horas private readonly CUSTOMERS_CACHE_KEY = 'clientes:search'; constructor( @Inject(DATA_SOURCE) private readonly dataSource: DataSource, @Inject(RedisClientToken) private readonly redisClient: IRedisClient, ) {} /** * Buscar clientes com cache otimizado * @param filter - Filtro de busca (código, CPF/CNPJ ou nome) * @returns Array de clientes encontrados */ async customers(filter: string) { const cacheKey = `${this.CUSTOMERS_CACHE_KEY}:${filter}`; return getOrSetCache( this.redisClient, cacheKey, this.CUSTOMERS_TTL, async () => { const queryRunner: QueryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { // Primeira tentativa: busca por código do cliente let sql = `SELECT PCCLIENT.CODCLI as "id" ,PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE|| ' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name" ,PCCLIENT.ESTCOB as "estcob" FROM PCCLIENT WHERE PCCLIENT.CODCLI = REGEXP_REPLACE('${filter}', '[^0-9]', '') ORDER BY PCCLIENT.CLIENTE`; let customers = await queryRunner.manager.query(sql); // Segunda tentativa: busca por CPF/CNPJ se não encontrou por código if (customers.length === 0) { sql = `SELECT PCCLIENT.CODCLI as "id", PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE|| ' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name" ,PCCLIENT.ESTCOB as "estcob" FROM PCCLIENT WHERE REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE('${filter}', '[^0-9]', '') ORDER BY PCCLIENT.CLIENTE`; customers = await queryRunner.manager.query(sql); } // Terceira tentativa: busca por nome do cliente se não encontrou por código ou CPF/CNPJ if (customers.length === 0) { sql = `SELECT PCCLIENT.CODCLI as "id", PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE|| ' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name" ,PCCLIENT.ESTCOB as "estcob" FROM PCCLIENT WHERE PCCLIENT.CLIENTE LIKE '${filter .toUpperCase() .replace('@', '%')}%' ORDER BY PCCLIENT.CLIENTE`; customers = await queryRunner.manager.query(sql); } return customers; } finally { await queryRunner.release(); } }, ); } /** * Buscar todos os clientes com cache * @returns Array de todos os clientes */ async getAllCustomers() { const cacheKey = 'clientes:all'; return getOrSetCache( this.redisClient, cacheKey, this.CUSTOMERS_TTL, async () => { const queryRunner: QueryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { const sql = `SELECT PCCLIENT.CODCLI as "id" ,PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE|| ' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name" ,PCCLIENT.ESTCOB as "estcob" FROM PCCLIENT ORDER BY PCCLIENT.CLIENTE`; return await queryRunner.manager.query(sql); } finally { await queryRunner.release(); } }, ); } /** * Buscar cliente por ID específico com cache * @param customerId - ID do cliente * @returns Cliente encontrado ou null */ async getCustomerById(customerId: string) { const cacheKey = `clientes:id:${customerId}`; return getOrSetCache( this.redisClient, cacheKey, this.CUSTOMERS_TTL, async () => { const queryRunner: QueryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); try { const sql = `SELECT PCCLIENT.CODCLI as "id" ,PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE|| ' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name" ,PCCLIENT.ESTCOB as "estcob" FROM PCCLIENT WHERE PCCLIENT.CODCLI = '${customerId}'`; const customers = await queryRunner.manager.query(sql); return customers.length > 0 ? customers[0] : null; } finally { await queryRunner.release(); } }, ); } async clearCustomersCache(pattern?: string) { const cachePattern = pattern || 'clientes:*'; } }