Files
egutierrez 7913116a8e chore: auto-commit (129 archivos)
- .claude/agents/fn-analizador/SKILL.md
- .claude/agents/fn-constructor/SKILL.md
- .claude/agents/fn-executor/SKILL.md
- .claude/agents/fn-mejorador/SKILL.md
- .claude/agents/fn-orquestador/SKILL.md
- .claude/agents/fn-recopilador/SKILL.md
- .claude/commands/app.md
- .claude/commands/compile.md
- .claude/commands/cpp-app.md
- .claude/commands/create_functions.md
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 22:23:12 +02:00

3.4 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, params, output, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types params output returns returns_optional error_type imports tested tests test_file_path file_path
metabase_mbql_validate function py core 1.0.0 pure def metabase_mbql_validate(dataset_query: dict) -> list[str] Valida la estructura de un dataset_query MBQL sin I/O. Detecta UUIDs duplicados, stage mixing (aggregations + expressions que referencian slots en la misma stage), slot refs rotas (sum_X inexistente), case structures invalidas y name collisions en expressions. Retorna lista de errores, vacia si el query es valido.
metabase
mbql
validation
pure
query
dataset_query
name desc
dataset_query Dict completo del dataset_query MBQL tal como lo devuelve GET /api/card/:id. Debe tener clave 'stages' con lista de stage dicts. Cada stage puede tener 'expressions', 'aggregation', 'filters'.
Lista de strings con errores encontrados. Lista vacia si el query supera todos los checks. Cada error incluye la ubicacion (stage[N]) y descripcion del problema.
false
true
DQ valido retorna lista vacia
UUID duplicado genera error
Stage mixing con slot refs genera error
Slot sum_99 inexistente genera error
Case con casos no pares genera error
Name collision en expressions genera error
stages ausente devuelve error de estructura
python/functions/metabase/test_metabase_mbql_validate.py python/functions/metabase/metabase_mbql_validate.py

Checks implementados

1. UUIDs duplicados

Metabase requiere que cada lib/uuid sea unico globalmente dentro del dataset_query. Un UUID repetido (por ejemplo al copiar-pegar un nodo MBQL) causa errores silenciosos o 400 en la API.

2. Stage mixing

Si una stage tiene aggregation y expressions, las expressions NO deben referenciar los slot names generados por las aggregations (sum, avg, sum_1, etc.). Esas references deben ir en la stage siguiente. Si estan en la misma stage, Metabase retorna 500.

3. Slot refs rotas

Una expression ["field", {sin base-type}, "sum_X"] referencia la X-esima aggregation de tipo sum. Si X >= cantidad de sums en la stage, el slot no existe y la query falla.

4. Case structure

Los nodos ["case", meta, cases] deben tener cases como lista de pares [cond, result]. Una estructura malformada (e.g., lista de un solo elemento) causa errores de parsing en Metabase.

5. Name collision

Dos expressions con el mismo lib/expression-name en la misma stage generan conflictos de alias en la query SQL generada.

Ejemplo

import sys
sys.path.insert(0, '$HOME/fn_registry/python/functions')
from metabase import MetabaseClient
from metabase.metabase_mbql_validate import metabase_mbql_validate

client = MetabaseClient('https://metabase.example.com', 'token...')
card = client.request('GET', '/api/card/5705')

errors = metabase_mbql_validate(card['dataset_query'])
if errors:
    for e in errors:
        print(f'ERROR: {e}')
else:
    print('Query valida')

Notas

Funcion 100% pura: sin I/O, sin estado mutable, determinista. Solo stdlib Python.

Los slots reconocidos como aggregation slots son: sum, avg, count, min, max, distinct, cum-sum, cum-count, share, stddev (y sus variantes _N).

Un field con base-type en su metadata NO se considera slot ref — es una referencia a columna real. Solo los fields sin base-type se tratan como slots de aggregation.