implementado filtro Delta

This commit is contained in:
Luiz Silva 2026-05-30 09:40:49 -03:00
parent b0b76562b7
commit 4aa775266f
6 changed files with 234 additions and 5 deletions

View file

@ -1,9 +1,90 @@
import z from "zod"
/**
* =============================================================================
* FILTRO DELTA (zFiltroDelta)
* =============================================================================
*
* OBJETIVO
* -----------------------------------------------------------------------------
* Novo sistema de filtros projetado para maior flexibilidade e geração segura
* de instruções SQL dinâmicas (WHERE).
*
* REGRAS IMPORTANTES (PARA IA)
* -----------------------------------------------------------------------------
* - O filtro é composto de duas partes obrigatórias: `condicoes` e `formula`.
* - Apenas referências aos `id`s das `condicoes` podem ser usadas na `formula`.
* - Não use sintaxe baseada em objetos aninhados para agrupamento (ex: { E: [], OU: [] }). Use fórmulas em string.
*
* 1) CONDIÇÕES (`condicoes`):
* Array de objetos contendo as definições isoladas de cada comparação.
* Exemplo:
* [
* { id: "{1}", coluna: "idade", operador: ">=", valor: 18 },
* { id: "{2}", coluna: "nome", operador: "like", valor: "%pa%" }
* ]
* - `id`: Deve SEMPRE seguir o formato {identificador}. Ex: `{c1}`, `{idade_min}`.
* - `coluna`: O nome da coluna ou um path JSONB válido (ex: `veiculo.ano`).
* - `operador`: Um dos valores do tipo `tipoOperadorFiltroDelta` (veja a constante).
*
* 2) FÓRMULA (`formula`):
* String que define a expressão lógica relacionando as condições através de seus `id`s.
* Operadores Lógicos Suportados (EM MAIÚSCULO):
* - `E` (AND)
* - `OU` (OR)
* - `NAO` (NOT)
* Suporta o agrupamento lógico usando parênteses `()`
* Exemplo válido: "({1} E NAO({2})) OU {3}"
*
* =============================================================================
*/
/**
* Operadores permitidos para comparação.
*/
export const zOperadorFiltroDelta = z.enum([">", "<", ">=", "<=", "=", "!=", "in", "like"])
export const zOperadorFiltroDelta = z.enum([">", "<", ">=", "<=", "=", "!=", "in", "like", "∩"])
export const operadorFiltroDeltaDetalhes: Record<
z.infer<typeof zOperadorFiltroDelta>,
{ rotulo: string; descricao: string }
> = {
">": {
rotulo: "Maior que",
descricao: "O valor de A deve ser maior que o valor de B",
},
"<": {
rotulo: "Menor que",
descricao: "O valor de A deve ser menor que o valor de B",
},
">=": {
rotulo: "Maior ou igual a",
descricao: "O valor de A deve ser maior ou igual ao valor de B",
},
"<=": {
rotulo: "Menor ou igual a",
descricao: "O valor de A deve ser menor ou igual ao valor de B",
},
"=": {
rotulo: "Igual a",
descricao: "O valor de A deve ser igual ao valor de B",
},
"!=": {
rotulo: "Diferente de",
descricao: "O valor de A deve ser diferente do valor de B",
},
in: {
rotulo: "Está em",
descricao: "O valor de A deve estar presente na coleção ou lista definida em B",
},
like: {
rotulo: "Contém",
descricao: "O valor de A deve conter o texto informado em B",
},
"∩": {
rotulo: "Interseção",
descricao: "A e B devem possuir pelo menos um elemento em comum",
},
}
/**
* Valida o identificador da condição.
@ -160,3 +241,32 @@ export type tipoOperadorFiltroDelta = z.infer<typeof zOperadorFiltroDelta>
export type tipoColunaFiltroDelta = z.infer<typeof zColunaFiltroDelta>
export type tipoCondicaoFiltroDelta = z.infer<typeof zCondicaoFiltroDelta>
export type tipoFiltroDelta = z.infer<typeof zFiltroDelta>
export type tipoFiltroDeltaColunaTipada<T extends string> = {
condicoes: (tipoCondicaoFiltroDelta & { coluna: T })[]
formula: string
}
/**
* Fábrica para criar filtros com colunas estritamente tipadas.
* Útil para autocompletar os nomes das colunas e garantir a estrutura no TypeScript.
*
* @example
* ```ts
* const { criarFiltroDelta } = iniciarFiltroDelta<"nome" | "idade" | "jsonb.propriedade">()
*
* const filtro = criarFiltroDelta({
* condicoes: [
* { id: "{c1}", coluna: "idade", operador: ">", valor: 18 },
* { id: "{c2}", coluna: "nome", operador: "=", valor: "luiz" },
* { id: "{c3}", coluna: "jsonb.propriedade", operador: "=", valor: "valor" },
* ],
* formula: "({c1} E {c2}) OU {c3}",
* })
* ```
*/
export const iniciarFiltroDelta = <TColunas extends string>() => {
return {
criarFiltroDelta: (filtro: tipoFiltroDeltaColunaTipada<TColunas>) =>
zFiltroDelta.parse(filtro) as tipoFiltroDeltaColunaTipada<TColunas>,
}
}