Logosulfite.app
rafagazani/sulfite 999999

Processamento de dados

Bindings, expressões, formatação e agregados

Processamento de dados#

O DataProcessor recebe a definição e o payload, e produz um ProcessedData com:

  • detailRows: registros resolvidos para cada data source
  • aggregates: valores calculados (SUM, COUNT, AVG, MAX, MIN)
  • calculated: campos de expressão resolvidos
  • errors: erros encontrados em modo resilient

Bindings#

Um FieldElement usa a propriedade binding para referenciar campos do registro:

{ "type": "field", "id": "f1", "x": 0, "y": 0, "width": 200, "binding": "product" }

O engine substitui product pelo valor do registro atual na detail band.

Expressões em bindings#

O binding aceita expressões aritméticas:

{ "binding": "quantity * price" }

Variáveis de contexto#

O engine disponibiliza variáveis automáticas que podem ser usadas em bindings, expressões e condições. O escopo depende do tipo de band e do tipo de elemento:

VariávelDisponível emSintaxe
Campo do registro FieldElement em detail binding: "campo"
Campo do payload global (dot-path) FieldElement em header/footer/summary binding: "empresa.nome"
Número de página FieldElement e TextElementsomente PDF binding: "page" ou {page} no content
Total de páginas FieldElement e TextElementsomente PDF binding: "totalPages" ou {totalPages} no content
Número de página (expressão) printWhen de bands — somente PDF pageNumber
Total de páginas (expressão) printWhen de bands — somente PDF totalPages
Data atualbindings e printWhenTODAY()
Data e hora atualbindings e printWhenNOW()

Ver a referência completa de expressões →

Formatação#

A propriedade format controla como o valor é exibido:

FormatExemplo de saídaDescrição
""2500Sem formatação (toString)
"currency:BRL" R$ 2.500,00 Real brasileiro
"currency:USD" $2,500.00 Dólar americano
"date:dd/MM/yyyy" 16/02/2026 Data formatada
"datetime:dd/MM/yyyy HH:mm" 16/02/2026 14:30 Data e hora
"integer"42Sem casas decimais
"number:2"42.502 casas decimais
"#,##0.00" 1.250,75 Padrão estilo Excel/JasperReports
"#,##0" 1.250 Inteiro com separador de milhar
"0.00" 250,75 Decimal sem separador de milhar

Tokens de data: dd (dia), MM (mês), yyyy (ano), HH (hora 24h), mm (minuto), ss (segundo).

Padrões numéricos estilo Excel#

O engine aceita padrões no formato #,##0.00, #,##0, 0.00, etc. (mesmo estilo do Excel e JasperReports). A vírgula (,) ativa o separador de milhar (ponto .) e o ponto (.) determina a quantidade de casas decimais:

PadrãoEntradaSaída
#,##0.00 1250.75 1.250,75
#,##0 1250 1.250
0.00 250.75 250,75
#,##0.000 1250.7 1.250,700

O separador de milhar usa . e o decimal usa , (convenção brasileira). Para outros separadores use currency:BRL ou currency:USD.

{
  "type": "field",
  "id": "price",
  "x": 300,
  "y": 5,
  "width": 100,
  "binding": "amount",
  "format": "currency:BRL"
}

Arredondamento#

Para campos numéricos, é possível configurar o arredondamento:

{
  "type": "field",
  "id": "avg",
  "x": 0,
  "y": 0,
  "width": 100,
  "binding": "value",
  "format": "number:2",
  "rounding": {
    "precision": 2,
    "mode": "half_even"
  }
}

Modos de arredondamento (exemplos com precisão 2):

Modo O que faz 2.545 2.534
half_even No empate (dígito 5), vai para o par mais próximo. Padrão bancário, evita viés. 2.54 2.53
half_up No empate, arredonda para cima. O arredondamento clássico. 2.55 2.53
half_down No empate, arredonda para baixo. 2.54 2.53
up Sempre para cima (direção +∞). 2.55 2.54
down Sempre para baixo (direção −∞). 2.54 2.53
truncate Corta as casas decimais excedentes. 2.54 2.53

Agregados#

AggregateElement calcula valores sobre todos os registros de um data source:

{
  "type": "aggregate",
  "id": "total",
  "x": 300,
  "y": 10,
  "width": 100,
  "verb": "SUM",
  "dataSourceId": "items",
  "targetKey": "price",
  "format": "currency:BRL"
}

Verbos disponíveis: SUM, COUNT, AVG, MAX, MIN.

Expressões avançadas#

O ExpressionEvaluator suporta funções, comparações e ternários. Ver a referência completa de expressões.

Exemplos rápidos:

quantity * price           → aritmética
UPPER(customer)            → texto
if(amount > 1000, 'VIP', 'Regular') → ternário
TODAY()                    → data atual

Pipeline no código#

final engine = SulfiteEngineImpl();
final report = await engine.parseReport(jsonString);
final context = await engine.processData(report, payload);

// context contém '_processedData', 'detailRows', 'aggregates', etc.
// Passe direto para qualquer renderer:
final pdf = await engine.renderToPdf(context);

O processData retorna um Map<String, dynamic> que deve ser passado intacto ao renderer.

Próximo passo#

Visão geral dos elementos →