Formato compute
Representação plana de um filtro de eventos como lista de condições, em snake_case, para consumidores de analytics.
GET /api/event-criterias/:id?format=compute
Retorna um filtro de eventos como uma lista plana de condições, em vez da árvore
completa. É o outro ramo do query param format de
GET /event-criterias/:id.
Auth: Obrigatória — permissão event-criteria:view
Esta representação é mais estreita que a definição: transporta condições de linha
sobre um único bloco de consulta. Um filtro cuja definição não cabe nela é rejeitado com
422 e um código que diz exatamente o que não cabe — nunca se retorna uma versão
degradada do filtro.
Parâmetros de rota
| Parâmetro | Tipo | Descrição |
|---|---|---|
id | UUID | ID do filtro de eventos. |
Parâmetros de consulta
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
format | string | Não | Envie compute para pedir esta representação. Omiti-lo —ou enviar detail— retorna o detalhe completo. |
Exemplo
curl "https://api.reten.ai/api/event-criterias/9f3a1c22-4b7e-4c31-9a8d-2f5e6b7c8d90?format=compute" \
-H "Authorization: Bearer <token>" \
-H "x-tenant-id: <tenant-id>" \
-H "x-project-id: <project-id>"import axios from 'axios';
const id = '9f3a1c22-4b7e-4c31-9a8d-2f5e6b7c8d90';
const response = await axios.get(
`https://api.reten.ai/api/event-criterias/${id}`,
{
headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' },
params: { format: 'compute' },
},
);
const computeCriteria = response.data;Forma da resposta 200 OK
Os campos desta resposta usam snake_case (sub_filters, match_all),
diferentemente do resto do recurso, que usa camelCase.
IComputeEventCriteria:
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID do filtro. |
name | string | Nome do filtro. |
conditions | IComputeCondition[] | Condições a aplicar. São combinadas com AND. [] é válido. |
Cada elemento de conditions é uma de duas formas, distinguíveis pelo seu operator:
Condição escalar
| Campo | Tipo | Descrição |
|---|---|---|
field | string | Caminho da coluna dentro de source. |
operator | Operador do subconjunto | Qualquer um menos CONTAINS_RECORD. |
value | escalar | array | Ausente —não null— para IS NULL e IS NOT NULL. Array para IN e NOT IN. Escalar para o resto. |
source | string | Tabela de onde vem a condição. |
Condição de registro
| Campo | Tipo | Descrição |
|---|---|---|
field | string | Coluna RECORD REPEATED dentro de source. |
operator | "CONTAINS_RECORD" | Só existe nesta forma. |
source | string | Tabela de onde vem a condição. |
match_all | boolean | Como os sub_filters são combinados dentro de um elemento (ver abaixo). |
sub_filters | array | Condições sobre os sub-campos do elemento: field, operator, value — sem source. |
Os quatro casos
1 · Condição escalar
Eventos cujo status é Facturada.
{
"id": "9f3a1c22-4b7e-4c31-9a8d-2f5e6b7c8d90",
"name": "Venta oficial — solo facturada",
"conditions": [
{
"field": "status",
"operator": "=",
"value": "Facturada",
"source": "event_transactions"
}
]
}2 · Registro com dois sub-filtros
Eventos com um atributo cuja key é documento_tipo e cujo value é factura.
{
"id": "1c7d2e83-5a90-4f62-8b31-6d4e5f70a1b2",
"name": "Documentos tipo factura",
"conditions": [
{
"field": "attributes",
"operator": "CONTAINS_RECORD",
"source": "event_transactions",
"match_all": true,
"sub_filters": [
{ "field": "key", "operator": "=", "value": "documento_tipo" },
{ "field": "value", "operator": "=", "value": "factura" }
]
}
]
}3 · Escalar + registro
Vendas faturadas com pelo menos uma linha que não é uma devolução.
{
"id": "4b8e0f15-2c76-4a03-9d58-7e1f2a3b4c5d",
"name": "Ventas con ítems no-devolución",
"conditions": [
{
"field": "status",
"operator": "=",
"value": "Facturada",
"source": "event_transactions"
},
{
"field": "items",
"operator": "CONTAINS_RECORD",
"source": "event_transactions",
"match_all": true,
"sub_filters": [
{ "field": "category", "operator": "NOT IN", "value": ["devolucion"] }
]
}
]
}4 · Escalar + tabela relacionada
Vendas faturadas com pelo menos uma linha cujo produto é da categoria Food Service ou
HORECA. A condição sobre a tabela relacionada chega no mesmo nível que as demais,
distinguida pelo seu source: o caminho até product_properties não viaja.
{
"id": "6d2a9c41-7e35-48b0-b1c9-0f8e7d6c5b4a",
"name": "Proyecto Food Service",
"conditions": [
{
"field": "status",
"operator": "=",
"value": "Facturada",
"source": "event_transactions"
},
{
"field": "categorization.category_name",
"operator": "IN",
"value": ["Food Service", "HORECA"],
"source": "product_properties"
}
]
}Um filtro de tabela relacionada com vários sub-filtros emite uma condição por
sub-filtro, todas com o mesmo source. É a única folha cuja cardinalidade de saída
não é 1.
O que significa match_all
É onde uma integração mais facilmente erra, então fica explícito:
match_allcombina ossub_filtersdentro do elemento, não entre os elementos.match_all: truesignifica que existe um elemento do array que satisfaz todos ossub_filters. Um elemento que corresponde só emkeyou só emvaluenão o satisfaz.match_all: falseé o mesmo existencial comORdentro: existe um elemento que satisfaz pelo menos um dossub_filters. Nunca significa "todos os elementos".- Com um único
sub_filtersempre viajamatch_all: true. Com menos de dois sub-filtros o conectivo não muda o resultado, etrueé a forma canônica. CONTAINS_RECORDé existencial também com operadores negativos.itemscomcategory NOT IN ["devolucion"]ematch_all: truesignifica "existe um item que não é devolução", não "nenhum item é devolução". Esta representação não consegue expressar quantificação universal.- Um array vazio ou
NULLnunca satisfaz umCONTAINS_RECORD, e um sub-campo emNULLnão corresponde, nem mesmo com um operador negativo.
O que significa field
O field é o caminho completo relativo ao seu escopo, e o escopo nunca se repete:
| Onde aparece | O que contém | Exemplo |
|---|---|---|
| Condição escalar de primeiro nível | Caminho da coluna dentro de source. | pricing.final_amount |
| Condição de registro | Nome da coluna RECORD REPEATED dentro de source. | attributes |
Dentro de sub_filters | Caminho relativo ao registro, sem o seu prefixo. | key — não attributes.key |
| Condição vinda de uma tabela relacionada | Caminho completo dentro dessa tabela, com source = a tabela relacionada. | categorization.category_name |
Subconjunto de operadores
Os operadores viajam como literais SQL, não como os membros do enum da definição:
comparisonOperator da definição | operator desta resposta |
|---|---|
EQUALS | = |
NOT_EQUALS | != |
GREATER_THAN | > |
GREATER_THAN_OR_EQUAL | >= |
LESS_THAN | < |
LESS_THAN_OR_EQUAL | <= |
IN | IN |
NOT_IN | NOT IN |
IS_NULL | IS NULL |
IS_NOT_NULL | IS NOT NULL |
CONTAINS_RECORD não traduz nenhum operador de comparação: quem o emite é a folha de registro.
Estes operadores não estão no subconjunto, e um filtro que os use é rejeitado com 422
e código OPERATOR_UNSUPPORTED:
CONTAINS·NOT_CONTAINS·STARTS_WITH·ENDS_WITH— os operadores de texto.BETWEEN— emitir o par como lista o transformaria em umIN, que é outro filtro.
Tipo JSON do value
Com qual tipo JSON o valor viaja é fixado pelo tipo da coluna no catálogo, não pela forma em que a definição ficou salva:
| Tipo da coluna | Tipo JSON do value |
|---|---|
STRING | string |
TIMESTAMP | string |
BOOLEAN | boolean |
FLOAT64 | number |
INT64 | number |
NUMERIC | string |
BIGNUMERIC | string |
A definição aceita as duas formas para vários tipos —100 e "100" valem igual para um
FLOAT64—, então emitir o que ficou salvo faria a mesma coluna viajar ora como número,
ora como texto, dependendo de quem a escreveu, e deixaria um IN misturar as duas formas
em uma única lista. NUMERIC e BIGNUMERIC viajam como string porque como número
perderiam os dígitos exatos que o seu tipo garante.
Resposta 422 Unprocessable Entity
O filtro é válido e compila para SQL; o que não existe é a sua projeção para esta representação. O corpo traz o diagnóstico:
Este corpo de erro viaja sem envelope: é code, path e message puros, sem
o statusCode nem o error que os demais erros da API trazem.
{
"code": "TIME_WINDOW_UNSUPPORTED",
"path": "queryBlocks[0].timeWindow",
"message": "No se puede proyectar queryBlocks[0].timeWindow (TIME_WINDOW_UNSUPPORTED): el wire no transporta la ventana IN_THE_LAST"
}| Campo | Tipo | Descrição |
|---|---|---|
code | string | Um dos doze códigos abaixo. |
path | string | Caminho até o nó da árvore que não tem projeção, em notação de acesso (queryBlocks[0].where.children[1].subWhere). É o que precisa mudar. |
message | string | Descrição legível da rejeição. |
Os doze códigos
code | O que o dispara | path |
|---|---|---|
MULTIPLE_QUERY_BLOCKS | O filtro tem mais de um bloco de consulta. Esta representação é de um único bloco. | queryBlocks |
AGGREGATION_UNSUPPORTED | O bloco agrega: groupBy não vazio, um agregado no select, ou um having com condições. | queryBlocks[0] |
TIME_WINDOW_UNSUPPORTED | O bloco declara uma janela temporal diferente de ALL_TIME. | queryBlocks[0].timeWindow |
JOIN_UNSUPPORTED | O bloco declara joins. | queryBlocks[0].from.joins |
TOP_LEVEL_OR_UNSUPPORTED | A árvore de filtros de primeiro nível é combinada com OR. A lista é unida com AND. | queryBlocks[0].where |
MIXED_LOGICAL_OPERATORS_UNSUPPORTED | Um mesmo escopo mistura AND e OR em grupos aninhados. Só se admite um conectivo por escopo. | O grupo mais superficial onde o conflito é detectado |
OPERATOR_UNSUPPORTED | Um operador fora do subconjunto (CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, BETWEEN). | A folha que o usa |
NESTED_RECORD_UNSUPPORTED | Um filtro de registro aninhado dentro de outro. Os sub_filters são planos e escalares. | A folha aninhada |
SEMI_JOIN_OR_UNSUPPORTED | A sub-árvore de um filtro de tabela relacionada é combinada com OR. Achatada viraria AND: um filtro mais estrito. | O subWhere da folha |
MULTIPLE_SEMI_JOINS_SAME_SOURCE | Dois escopos diferentes emitiriam o mesmo source. São dois existenciais independentes que, achatados, se aplicariam à mesma linha. | A segunda folha que reivindica esse source |
EMPTY_PREDICATE_GROUP | Uma sub-árvore relativa sem condições: não restringiria nada. | A sub-árvore vazia |
VALUE_NOT_REPRESENTABLE | Um operador que precisa de valor e não o traz, ou um INT64 fora do intervalo exato de um número JSON. | A folha |
Estes códigos dizem o que esta representação não consegue expressar, não o que a API não suporta: todas essas formas são definições válidas que compilam para SQL e funcionam em Gerar SQL, Validar e Pré-visualizar.
Relação com conditionCount
O conditionCount da listagem conta as
folhas da árvore da definição e não coincide necessariamente com o tamanho de
conditions. Um filtro com uma folha de tabela relacionada de três sub-filtros tem
conditionCount: 1 e retorna três condições. Os dois números estão corretos e medem
coisas diferentes.
Respostas de erro
| Status | Descrição |
|---|---|
400 | O id não é um UUID válido, format não é detail nem compute, ou o filtro salvo já não compila para SQL contra o catálogo atual. |
401 | Falta ou é inválido o Authorization: Bearer. |
403 | O usuário não tem a permissão event-criteria:view, ou o x-tenant-id não está autorizado. |
404 | Não existe um filtro de eventos com esse id no tenant (Event criteria not found). |
422 | O filtro é válido mas não tem projeção para esta representação (ver os doze códigos). |