@horizon-apps/domain-schema-core
Version:
Core domain schema utilities for Horizon Platform - Schema generators, data enrichers, converters and specifications
282 lines (231 loc) • 9.07 kB
Markdown
# 🏗️ Plano de Implementação Multi-Search v2.0
## 📋 **CHECKLIST COMPLETO - NADA FICA DE FORA**
### **🔧 ETAPA 1: Interfaces Base** ✅ COMPLETO
- [x] Criar interfaces MultiSearchRequest/Response limpas
- [x] Interface GeospatialFilter com bbox/polygon
- [x] Interface PrismaMultiQuery para transaction
- [x] Validação Zod completa
- [x] Fragmentação em arquivo separado: `multi-search-interfaces.ts`
### **🔧 ETAPA 2: Mapper Geoespacial** ✅ COMPLETO
- [x] Função extractGeospatialQuery (bbox/polygon → SQL)
- [x] Função prismaWhereToSQL (conversão básica)
- [x] Fragmentação em arquivo separado: `geospatial-utils.ts`
- [x] Teste isolado passando: `geospatial-function.test.ts`
### **🔧 ETAPA 3: Multi Request Mapper** ✅ COMPLETO
- [x] Classe MultiSearchMapper completa
- [x] Método mapMultiSearch (request → queries)
- [x] Método buildListQueries (paginação)
- [x] Método buildMapQueries (sem paginação + geo)
- [x] Validação completa de entrada
- [x] Fragmentação em arquivo separado: `multi-search-mapper.ts`
- [x] Teste isolado passando: `multi-search-mapper.test.ts`
### **🔧 ETAPA 4: Service com Transaction** ✅ COMPLETO
- [x] Classe PrismaMultiService completa
- [x] Método multiSearch com $transaction
- [x] Processamento paralelo de queries
- [x] Separação automática property/relations
- [x] Cálculo de bounds geográficos
- [x] Logs de entrada/saída
- [x] Fragmentação em arquivo separado: `multi-search-service.ts`
- [x] Teste isolado passando: `multi-search-service.test.ts`
### **🔧 ETAPA 5: Integração Completa** ✅ COMPLETO
- [x] Teste mapper + service juntos
- [x] Cenário bbox (lista + mapa + meta)
- [x] Cenário polygon (só mapa)
- [x] Validação de erros
- [x] Performance com transaction
- [x] Teste end-to-end passando: `integration-complete.test.ts`
### **🔧 ETAPA 6: Documentação** ✅ COMPLETO
- [x] Documentar implementação realizada
- [x] Exemplos de uso completos
- [x] Breaking changes documentation
### **🔧 ETAPA 7: Schema Awareness** ✅ COMPLETO
- [x] Integrar HorizonSchema no MultiSearchMapper
- [x] Expandir schema de teste com geo-point location
- [x] Implementar validação de campos vs schema
- [x] Adicionar type safety para filtros geoespaciais
- [x] Criar testes com schema awareness
- [x] Documentar nova funcionalidade
## 🎯 **IMPLEMENTAÇÃO COMPLETA - FUNCIONANDO 100%**
✅ **TODOS OS TESTES PASSANDO**
✅ **ARQUITETURA FRAGMENTADA CORRETAMENTE**
✅ **INTEGRAÇÃO END-TO-END FUNCIONAL**
## 📁 **ESTRUTURA DE ARQUIVOS CRIADA**
```
src/search-request-to-prisma-mapper/
├── index.ts (arquivo original + exports)
├── multi-search-interfaces.ts (interfaces fragmentadas)
├── multi-search-mapper.ts (mapper novo)
├── geospatial-utils.ts (funções geo)
├── docs/
│ └── readme.md (doc movida)
└── tests/
├── geospatial-function.test.ts (teste geo isolado)
├── multi-search-mapper.test.ts (teste mapper)
├── multi-search-schema-awareness.test.ts (teste schema awareness)
├── index.test.ts (teste original)
└── schema-awareness.test.ts (teste mapper original)
src/prisma-generic-search-service/
├── index.ts (arquivo original + exports)
├── multi-search-service.ts (service novo)
└── tests/
├── multi-search-service.test.ts (teste service)
├── integration-complete.test.ts (teste integração)
├── prisma-generic-search-service.test.ts (teste original)
└── prisma-logs.test.ts (teste original)
```
## 🚀 **FORMATO DE USO**
### **Opção 1: Sem Schema (compatibilidade)**
```typescript
// 1. Frontend Request (novo formato)
const request: MultiSearchRequest = {
include: ['list', 'map', 'meta'],
list: {
fields: ['id', 'title', 'price'],
relations: { broker: true },
pagination: { page: 1, limit: 10 }
},
map: {
fields: ['id', 'latitude', 'longitude']
},
filters: {
tipo: { value: 'Casa' },
location: {
value: {
type: 'bbox',
bounds: { west: -51, south: -30, east: -50, north: -29 }
}
}
}
}
// 2. Mapper: Frontend → Prisma (sem validação)
const mapper = MultiSearchMapper.createWithoutSchema()
const queries = mapper.mapMultiSearch(request)
// 3. Service: Transaction paralela
const service = new PrismaMultiService('property', prisma)
const result = await service.multiSearch(queries)
// 4. Response estruturada
console.log(result.list?.data) // Lista paginada
console.log(result.map?.data) // Dados do mapa
console.log(result.meta) // Metadados globais
```
### **Opção 2: Com Schema Awareness (recomendado)**
```typescript
import { TEST_SCHEMA_WITH_GEO } from './multi-search-interfaces'
// 1. Schema de validação
const schema = TEST_SCHEMA_WITH_GEO // ou seu próprio schema
// 2. Mapper com validação
const mapper = MultiSearchMapper.createWithSchema(schema)
// 3. Request com validação automática
const request: MultiSearchRequest = {
include: ['list', 'map'],
list: {
fields: ['id', 'title', 'tipo'], // ✅ Validados vs schema
pagination: { page: 1, limit: 10 }
},
map: {
fields: ['latitude', 'longitude'] // ✅ Validados vs schema
},
filters: {
location: { // ✅ Validado vs geo-point no schema
value: {
type: 'polygon',
coordinates: [[-49.76, -29.18], [-50.87, -29.09], [-49.76, -29.18]]
}
}
}
}
// 4. Execução com type safety
const queries = mapper.mapMultiSearch(request) // Valida campos automaticamente
const result = await service.multiSearch(queries)
```
### **Opção 3: Compatibilidade estática (para testes)**
```typescript
// Para manter testes existentes funcionando
const queries = MultiSearchMapper.mapMultiSearch(request)
```
## 🚨 **REGRAS CRÍTICAS DE USO**
### **⚠️ SCHEMA É OBRIGATÓRIO PARA ARRAYS**
**DESCOBERTA CRÍTICA:** `createSQLBuilder()` **DEVE** receber schema obrigatoriamente para detectar campos array corretamente.
#### **❌ ERRO COMUM:**
```typescript
// SEM SCHEMA = CAMPOS ARRAY NÃO FUNCIONAM
const sqlBuilder = createSQLBuilder() // ❌ SEM SCHEMA!
```
**Resultado:** Campo `operacao` (que é `string[]` no PostgreSQL) é tratado como string simples:
```sql
-- SQL INCORRETO gerado:
WHERE operacao = 'venda' -- ❌ ERRO! Vai dar "malformed array literal"
```
#### **✅ SOLUÇÃO CORRETA:**
```typescript
import { createTestPropertySchema } from './filter/schema-adapter'
// ✅ SEMPRE PASSAR SCHEMA
const schema = createTestPropertySchema()
const sqlBuilder = createSQLBuilder({ schema })
```
**Resultado:** Campo `operacao` é corretamente detectado como array:
```sql
-- SQL CORRETO gerado:
WHERE 'venda' = ANY(operacao) -- ✅ FUNCIONA! Detecta array via SSOT
```
#### **🔧 COMO APLICAR:**
**1. URL Parser Integration:**
```typescript
import { createSQLBuilder } from '../postgre-search-sql-builder'
import { createTestPropertySchema } from '../postgre-search-sql-builder/filter/schema-adapter'
// 🚨 OBRIGATÓRIO: Schema para detecção de arrays
const schema = createTestPropertySchema()
const sqlBuilder = createSQLBuilder({ schema })
```
**2. Examples e Database Testing:**
```typescript
// TODOS os examples e testes devem seguir este padrão
const schema = createTestPropertySchema()
const sqlBuilder = createSQLBuilder({ schema })
// Agora operacao, caracteristicas, tags (arrays) funcionam corretamente
```
#### **🔍 COMO IDENTIFICAR O PROBLEMA:**
**Sintomas:**
- Erro PostgreSQL: `malformed array literal: "venda"`
- SQL gerado: `operacao = 'venda'` em vez de `'venda' = ANY(operacao)`
- Filtros de array não funcionam
**Diagnóstico:**
- Verificar se `createSQLBuilder({ schema })` está sendo usado
- Confirmar se schema contém definição `string[]` para campos array
**Validação:**
```typescript
// Verificar se schema está sendo usado:
console.log(sqlBuilder.getStats().hasSchema) // deve ser true
```
## 🔥 **TROUBLESHOOTING COMUM**
### **Problema: "malformed array literal: 'venda'"**
**Causa:** `createSQLBuilder()` chamado sem schema parameter
**Sintoma:**
```sql
WHERE operacao = 'venda' -- Tenta inserir string em campo array
```
**Solução:**
```typescript
// ❌ ERRADO:
const sqlBuilder = createSQLBuilder()
// ✅ CORRETO:
const schema = createTestPropertySchema()
const sqlBuilder = createSQLBuilder({ schema })
```
### **Problema: Arrays sendo tratados como strings**
**Causa:** FilterConverter sem informação SSOT sobre tipos de campo
**Diagnóstico:**
```typescript
// Verificar se campo está definido como array no schema:
const fieldInfo = schema.fields.find(f => f.name === 'operacao')
console.log(fieldInfo?.type) // deve ser 'string[]'
```
**Solução:** Garantir que schema define corretamente:
```typescript
{
name: 'operacao',
type: 'string[]', // ✅ CRÍTICO: [] indica array
db: 'operacao'
}
```