DATTAX — Referência da Linguagem
Escrever a mesma análise três vezes — uma em SQL, outra em Cypher, outra na linguagem do índice de busca — é retrabalho que não gera valor. DATTAX é a linguagem declarativa do DATTA para consultar, transformar e materializar dados em qualquer fonte cadastrada (PostgreSQL, Neo4j, Iceberg, Kafka e dezenas de outras): você escreve uma sintaxe única e a plataforma traduz para o dialeto do destino. Esta página é a referência completa da linguagem; para uma introdução guiada, comece pelo guia da linguagem.
Versão
1.4.0(2026-05). Versionamento semântico — bump menor adiciona funções/features backward-compat; bump maior pode quebrar scripts antigos.
Estrutura de um script
LET windowDays = 30;
DEFINE DATASET vendas
FROM JDBC "postgres-vendas"
SELECT cliente_id, valor, data
WHERE data >= NOW() - DAYS(windowDays);
EVALUATE
vendas
| GROUP BY cliente_id
| AGG total = SUM(valor), pedidos = COUNT(*);Instruções de topo:
LET nome = expr;— variável local imutável.DEFINE DATASET nome FROM <source> ...— declara um dataset reutilizável.DATASET nome = <pipeline>;— nomeia um pipeline inteiro (com os|>) para reaproveitar emEVALUATEouMATERIALIZE.EVALUATE expr— query final; devolve as linhas ao chamador (gráfico, materialização).MATERIALIZE nome FROM <source> ...— persiste o resultado em um destino (Iceberg, Neo4j, cache da plataforma).
Camada semântica universal (USL)
Você pode referenciar entidades pelo nome de negócio definido na ontologia (ex: Contribuinte) em vez do nome físico da tabela ou do índice. Antes de interpretar o script, a plataforma substitui textualmente os tokens conceituais pelas referências físicas resolvidas:
| Token | Resolve para | Exemplo |
|---|---|---|
${entity:<Nome>} | dataset físico da entidade | ${entity:Contribuinte} → TB_RF_01 |
${entity:<ontologyId>.<Nome>} | idem, com ontologia explícita | ${entity:cnpj.Empresa} → dataset físico da ontologia cnpj |
${conn:<Nome>} | conexão resolvida da entidade | ${conn:Contribuinte} → id da conexão |
Formato do token: ${(entity|conn):(<ontologyId>.)?<Nome>}.
Como a resolução acontece. A plataforma consulta o catálogo de ontologia e recebe a referência da entidade — o dataset físico mais a conexão (ou o espaço de nomes) correspondente. O resultado fica em cache de duas camadas (memória local + cache distribuído da plataforma) sob a chave datta:dattax:catalog:ontology:<ontologyId>:<entity>, com TTL de 30 minutos (datta.dattax.cache.ontology-ttl-minutes) — scripts que repetem as mesmas entidades não pagam o custo da resolução de novo.
Comportamento seguro:
- Token não resolvido é preservado textualmente (com aviso no registro de execução) — o script falha de forma informativa, em vez de gerar SQL/Cypher incorreto em silêncio.
- Com a ontologia desabilitada, o pré-processamento não faz nada: o script segue exatamente como você escreveu.
Fontes (FROM <source>)
| Token | Tipo | Conector |
|---|---|---|
GRAPH "name" | Neo4j | Driver nativo (Cypher + algoritmos de grafo) |
INDEX "name" | OpenSearch | Cliente REST nativo |
ELASTIC "name" | Elasticsearch | Cliente REST nativo |
JDBC "name" | Qualquer banco JDBC catalogado | 38 drivers homologados no catálogo oficial |
TRINO "name" | Trino | Federação SQL via trino-jdbc |
ICEBERG "table" | Apache Iceberg | iceberg-java + REST catalog |
FILE "path" | CSV/Parquet/JSON local | Parser nativo |
CASSANDRA "name" | Cassandra/ScyllaDB | Driver Java DataStax (paginação assíncrona) |
MONGO "name" | MongoDB | Driver MongoDB (aggregation pipeline) |
BIGQUERY "name" | Google BigQuery | google-cloud-bigquery + Storage Read API |
| `STREAM "topic" KAFKA \ | PULSAR \ | CDC \ |
Toda fonte é referenciada pelo nome da conexão cadastrada em — endereços e credenciais nunca aparecem no script.
Transformações
O pipe | encadeia transformações sobre o dataset:
| Transformação | Sintaxe | Equivalente SQL/DAX |
|---|---|---|
| Filter | `\ | FILTER expr` |
| Project | `\ | SELECT cols...` |
| Mutate | `\ | MUTATE col = expr` |
| Join | `\ | JOIN [INNER\ |
| Group | `\ | GROUP BY cols... SUMMARIZE name=fn(col)` |
| Sort | `\ | ORDER BY col [DESC]` |
| Limit | `\ | LIMIT n` |
| Window | `\ | WINDOW TUMBLING("5m")` |
| Union | `\ | UNION [ALL\ |
Há mais de 50 transformações adicionais definidas na gramática da linguagem — as mais usadas no dia a dia estão no guia da linguagem.
Tipos de JOIN (1.2.0+)
| Tipo | Comportamento | Caso de uso típico |
|---|---|---|
INNER (default) | Apenas linhas com correspondência em ambos os lados. | Cruzar vendas com clientes (ambos obrigatórios). |
LEFT | Mantém todas as linhas da esquerda; sem match → as colunas da direita ficam NULL. | Listar clientes com (ou sem) último pedido. |
RIGHT | Inverso de LEFT. | Listar metas com (ou sem) vendedor. |
FULL | União dos LEFT + RIGHT. | Reconciliação de duas fontes. |
CROSS | Produto cartesiano (ignora ON). | Grade calendário × cliente. |
ANTI | Linhas da esquerda sem correspondência na direita. Esquema do resultado = esquema da esquerda (não traz colunas da direita). | Clientes sem pedido; produtos não vendidos; registros órfãos. |
EVALUATE clientes
|> JOIN ANTI pedidos ON id = cliente_id ;
-- Retorna clientes que nunca compraram.Operadores de filtro (1.2.0+)
Além de =, !=, <, >, <=, >=, AND, OR e NOT, a linguagem aceita os operadores SQL-like abaixo, com precedência entre aritmética e comparação (i.e. x + 1 IS NULL é interpretado como (x + 1) IS NULL):
| Operador | Sintaxe | Semântica |
|---|---|---|
| Nulo | col IS NULL / col IS NOT NULL | Igual a SQL — só verdadeiro se a célula for NULL. |
| Intervalo | col BETWEEN a AND b / col NOT BETWEEN a AND b | Inclusivo nos dois extremos. NULL em qualquer lado → NULL (3-valued logic). |
| Lista | col IN ("a", "b", "c") / col NOT IN (...) | Comparação solta (1 casa com "1"). |
| Texto | CONTAINS(col, "x"), NOT_CONTAINS(col, "x"), STARTS_WITH(col, "x"), ENDS_WITH(col, "x") | Funções, não operadores. |
Exemplo (§5.7 da especificação funcional):
EVALUATE FROM JDBC "warehouse"
"SELECT * FROM vendas"
|> FILTER status IN ("concluido", "pago")
AND valor BETWEEN 100 AND 5000
AND cancelado_em IS NULL
AND cliente_id IS NOT NULL
AND NOT_CONTAINS(observacao, "teste") ;UNION — validação de schema
UNION emite um aviso não-fatal (UNION_SCHEMA_MISMATCH) quando os dois lados têm conjuntos de colunas diferentes. A execução continua: as colunas faltantes são preenchidas com NULL na linha alvo. A execução termina com o status "concluído com alertas" — o contador de avisos do evento final vem maior que zero.
Data Quality — |> DATA_QUALITY (1.3.0+)
Atende §5.14 da especificação funcional. Executa verificações declarativas sobre o dataset corrente e emite avisos não-fatais para cada violação. Cada aviso tem um código fixo que a interface usa para cor e ícone.
| Check | Sintaxe | Código de aviso |
|---|---|---|
| Coluna sem nulos | CHECK NOT NULL col | DQ_NULLS_FOUND |
| Chave única | CHECK UNIQUE col1, col2 | DQ_DUPLICATES_FOUND |
| Intervalo | CHECK RANGE col BETWEEN 0 AND 100 | DQ_RANGE_VIOLATION |
| Não vazio | CHECK NOT EMPTY | DQ_EMPTY_DATASET |
| Cardinalidade exata | CHECK EXPECTED ROWS 1000 | DQ_EXPECTED_ROWS_MISMATCH |
| Cardinalidade em faixa | CHECK EXPECTED ROWS BETWEEN 100 AND 5000 | DQ_EXPECTED_ROWS_OUT_OF_RANGE |
| Schema esperado | CHECK EXPECTED COLUMNS id, nome, valor | DQ_MISSING_COLUMNS |
| % nulos máximo | CHECK PCT_NULL col < 5 | DQ_PCT_NULL_EXCEEDED |
| Predicado custom | CHECK CUSTOM "msg" predicate | DQ_CUSTOM_VIOLATION |
EVALUATE FROM JDBC "warehouse" "SELECT * FROM vendas"
|> DATA_QUALITY
CHECK NOT NULL cliente_id,
CHECK UNIQUE pedido_id,
CHECK RANGE valor BETWEEN 0 AND 1000000,
CHECK PCT_NULL desconto < 10,
CHECK EXPECTED ROWS BETWEEN 100 AND 5000000,
CHECK CUSTOM "data futura" data_venda <= NOW()
|> SELECT * ;DQ é observação — não filtra. Para descartar linhas inválidas, combine com FILTER. O dataset passa para a próxima etapa intocado.
Estados granulares de execução — 1.3.0+
Atende §5.16 da especificação. Cada execução reporta progresso em tempo real na tela, estágio a estágio:
| Estágio | Quando | O que você vê |
|---|---|---|
dattax | Início da execução | Execução iniciada |
connecting | Resolvendo a conexão com a fonte | Nome da fonte sendo conectada |
extracting | Lendo da fonte | Contagem de registros lidos |
transforming | Aplicando transformações | "Etapa N/M: FILTER" e similares |
materialize | Persistindo | Progresso da gravação |
Ao final, o evento de conclusão carrega o número de avisos acumulados: se for maior que zero, a execução aparece como "concluído com alertas" — você sabe que terminou e sabe que vale conferir os avisos.
Modos de persistência — MATERIALIZE ... MODE ... PARTITION BY ... (1.3.0+)
Atende §5.15. Sintaxe:
MATERIALIZE vendas_consolidadas AS ICEBERG TABLE "gold.vendas"
MODE INCREMENTAL
PARTITION BY ano, mes
WATERMARK data_venda ;Modos suportados (cada destino mapeia para a semântica nativa do motor):
| Modo | Semântica |
|---|---|
OVERWRITE | Substitui todos os dados existentes. |
APPEND | Acrescenta novos registros sem tocar nos antigos. |
UPDATE | Atualiza registros existentes (requer chave). |
INCREMENTAL | APPEND + UPDATE baseado em WATERMARK <col>. |
HISTORICAL | Mantém histórico por data de processamento. |
VERSIONED | Cria nova versão do dataset (snapshot). |
PARTITION BY é repassado aos destinos que suportam particionamento (Iceberg, Parquet/Delta). Destinos sem suporte (índice OpenSearch simples, label Neo4j) emitem o aviso MATERIALIZE_PARTITION_IGNORED e seguem com o padrão.
MATERIALIZE ... AS NEO4J — banco de destino obrigatório
A persistência em Neo4j nunca adivinha o banco de destino. Abrir uma sessão de escrita amarrada a um banco "default" silencioso é receita para dado no lugar errado: o destino tem de ser uma decisão explícita.
Sintaxe explícita
A cláusula DATABASE é obrigatória, seguida do label e da chave de merge — todos obrigatórios:
materializeNeo4j : 'NEO4J' 'DATABASE' STRING 'LABEL' IDENT 'KEY' IDENT ;Na prática, o script informa o banco como literal de string, o label como identificador e a propriedade-chave usada no MERGE:
MATERIALIZE grafo_partes AS NEO4J
DATABASE "processotributario"
LABEL Parte
KEY documento
MODE UPDATE ;Omitir DATABASE é erro de sintaxe — o script é rejeitado antes de qualquer execução, porque a cláusula não é opcional na gramática.
Validação em tempo de execução (banco vazio)
Mesmo que o valor chegue vazio (nulo ou em branco) durante a execução, a gravação é rejeitada antes de abrir qualquer sessão no grafo, com esta mensagem exata:
Banco de destino da materializacao Neo4j e obrigatorio — nunca adivinhado.Não há fallback para "neo4j" nem para nenhum outro nome. O label (validado contra o padrão [A-Za-z_][A-Za-z0-9_]*) e a chave de merge são conferidos na mesma etapa, antes da gravação.
MATERIALIZE ... AS AUTO — a plataforma escolhe o motor
Quando você escreve MATERIALIZE <ds> AS AUTO, a plataforma pontua os motores disponíveis (Iceberg, Neo4j, OpenSearch) e escolhe o mais adequado ao formato do resultado. Se o Neo4j vencer, o resultado é depositado no banco de sistema padrão do grafo ("neo4j"). Isso não é fallback silencioso: uma materialização AUTO é um artefato derivado pela própria plataforma, sem contexto de domínio escolhido por você, então o destino padrão é uma escolha deliberada e documentada — distinta dos uploads, que sempre carregam um contexto de destino explícito. Para um destino específico, use a forma explícita com DATABASE.
| Forma | Quem decide o banco | Origem do valor |
|---|---|---|
AS NEO4J DATABASE "<db>" LABEL <l> KEY <k> | Você | Cláusula DATABASE da gramática (obrigatória). |
AS AUTO (motor resolvido = Neo4j) | A plataforma | Banco de sistema padrão do grafo — escolha deliberada, não fallback. |
| (banco vazio em runtime) | — | Rejeitado com a mensagem em português acima. |
Standard Library (F11+)
Funções chamáveis em qualquer expressão — cerca de 40 na versão 1.1.0, organizadas em 4 categorias. O editor DATTAX oferece autocomplete com todas elas.
Math (category: math)
| Função | Assinatura |
|---|---|
SUM(values) | number[] -> number |
AVG(values) | number[] -> number |
COUNT(values) | any[] -> number |
COUNT_DISTINCT(values) | any[] -> number |
MIN(values) | comparable[] -> any |
MAX(values) | comparable[] -> any |
MEDIAN(values) | number[] -> number |
ROUND(value, decimals?) | number -> number |
FLOOR(value) / CEIL(value) | number -> number |
ABS(value) | number -> number |
POWER(base, exp) | (number, number) -> number |
SQRT(value) | number -> number |
String (category: string)
| Função | Assinatura |
|---|---|
CONCAT(parts...) | any... -> string |
UPPER(value) / LOWER(value) | string -> string |
LENGTH(value) | string -> number |
SUBSTRING(value, start, length?) | string -> string |
TRIM(value) | string -> string |
REPLACE(value, target, replacement) | string -> string |
REGEX_EXTRACT(value, pattern, group?) | string -> string |
SPLIT(value, sep, index?) | `string -> string[]\ |
STARTS_WITH(value, prefix) / ENDS_WITH(value, suffix) | string -> boolean |
Date (category: date)
Aceita string ISO-8601, instante, data ou epoch millis. Fuso padrão America/Sao_Paulo.
| Função | Assinatura |
|---|---|
NOW() | -> instant |
TODAY() | -> date |
DATE_PARSE(value, pattern?) | string -> instant |
DATE_FORMAT(value, pattern) | (date, string) -> string |
DATE_ADD(value, amount, unit) | `unit: SECOND\ |
DATE_DIFF(start, end, unit) | `unit: SECOND\ |
YEAR / MONTH / DAY / QUARTER / WEEK_OF_YEAR / DAY_OF_WEEK | date -> number |
Time Intelligence (category: time-intelligence, 1.1.0+)
Funções sobre séries temporais. Recebem (rows, dateColumn, valueColumn, refDate?) e operam em janela determinada pela função.
| Função | Janela |
|---|---|
YTD(rows, date, value, ref?) | 01/jan ano atual → ref |
MTD(rows, date, value, ref?) | 1º dia mês atual → ref |
QTD(rows, date, value, ref?) | 1º dia trimestre atual → ref |
SAMEPERIODLASTYEAR(rows, date, value, ref?) | 01/jan ano-1 → ref-1ano |
GROWTH_PCT(current, previous) | (current - previous) / previous * 100 |
ROLLING_AVG(rows, date, value, windowDays, ref?) | últimos N dias até ref |
Medidas tipo YoY e Q vs Q-1 saem prontas, sem você reescrever a query — o mesmo conforto que se espera do Power BI ou do Tableau. Para o mapa completo de equivalências com DAX, veja DATTAX × DAX.
Exemplo prático — pipeline completo com qualidade e materialização
Cenário: consolidar as vendas válidas do warehouse numa tabela gold do Iceberg, com checagens de qualidade no meio do caminho.
- Abra o editor DATTAX.
- Confirme que a conexão
warehouseexiste em . - Cole e execute o script — ele declara o dataset consolidado e, em seguida, materializa esse dataset na tabela gold:
DATASET vendas_mensais =
FROM JDBC "warehouse" "SELECT * FROM vendas"
|> FILTER status IN ("concluido", "pago") AND cancelado_em IS NULL
|> DATA_QUALITY
CHECK NOT NULL cliente_id,
CHECK UNIQUE pedido_id,
CHECK PCT_NULL desconto < 10
|> MUTATE ano = YEAR(data_venda), mes = MONTH(data_venda)
|> GROUP BY ano, mes SUMMARIZE total = SUM(valor), pedidos = COUNT(*),
ultima_venda = MAX(data_venda) ;
MATERIALIZE vendas_mensais AS ICEBERG TABLE "gold.vendas_mensais"
MODE INCREMENTAL
PARTITION BY ano, mes
WATERMARK ultima_venda ;- Acompanhe os estágios (
connecting→extracting→transforming→materialize) em tempo real. Se alguma checagem de qualidade falhar, a execução termina como "concluído com alertas" — os avisos ficam listados, mas a tabela é gravada.
Versionamento e compatibilidade
- A versão corrente da biblioteca padrão é
1.1.0, e a plataforma carrega apenas as funções cuja versão de introdução seja menor ou igual a ela. - Scripts antigos em produção continuam executando após upgrades — funções novas entram por bump menor, sem quebrar o que já existe.
- Funções descontinuadas geram avisos na execução, mas seguem disponíveis até o próximo bump maior. Você tem tempo de migrar no seu ritmo.
- Uma função nova é adicionada declarando um método estático anotado no pacote da biblioteca padrão — o catálogo a descobre sozinho na inicialização, sem editar a gramática (funções entram pelo
funcCallgenérico que já existe).
Evolução da linguagem
1.3.0—ANTI JOIN; operadores SQL-like (IS NULL,BETWEEN,IN,NOT_CONTAINS,ENDS_WITH);UNIONcom validação de schema; avisos não-fatais e "concluído com alertas"; estados granulares de execução (connecting/extracting/transforming/persisting); transformaçãoDATA_QUALITYcom 9 tipos de checks (§5.14); modos de persistência (MODE,PARTITION BY,WATERMARK, §5.15); Excel (.xlsx) como fonte de arquivo (§5.3); pausa, retries e fuso configurável no agendador (§5.17); mascaramento de PII no designer (§5.19); duplicação de etapa (§5.6); cards do canvas com schema visível + desfazer/refazer.1.4.0(atual) — editor com syntax highlight e autocomplete de toda a biblioteca padrão e dos comandos principais (EVALUATE / FROM JDBC / FILTER / JOIN / GROUP BY / DATA_QUALITY / MATERIALIZE), alimentado pelo catálogo da biblioteca padrão que a plataforma publica (ver referência de API); quoting correto por dialeto ao empurrar consultas para a fonte (MySQL `backticks, MSSQL[brackets], BigQuerybackticks, Oracle/PostgreSQL"double quotes"); monitoramento de pastas com padrões glob (/data/incoming/.csv,/data//.parquet); métricas de execução (fontes acessadas, avisos, estágio do erro, registros descartados) persistidas no Neo4j e visíveis no monitor de pipelines; ciclo de vida completo do pipeline (pausar, retomar, arquivar, ativar — também disponível pela **referência de API**); templates de notificação por email/webhook com variáveis ({{pipelineName}},{{status}}`); conversão do pipeline visual em script DATTAX, fechando o loop entre o canvas e a linguagem.- Ainda em aberto para
1.4.0—CALCULATE(expr, modifiers...)e contextos de filtro formalizados (RowContext vs FilterContext, equivalente DAX); visualizador de plano de consulta; diálogo visual de configuração de JOIN/aresta no designer; cardinalidade automática 1:1 / 1:N / N:1 / N:N. 2.0.0(planejado) — pushdown completo de filtros (§5.7 —WHEREtraduzido para o dialeto da fonte); modos de gravação totalmente implementados em todos os destinos (não só na gramática); interface de execução de produção; novas famílias de fonte (GraphQL, SaaS, cloud storage, ODBC); tipagem estática opcional; otimizador de consultas com eliminação de subexpressões comuns.