feat(metabase): nuevos modulos — snippets, notifications, dashboard_filters

Tres modulos nuevos con funciones CRUD completas:
- snippets: list, get, create, update, archive (SQL reutilizable)
- notifications: list, create_card_alert, create_dashboard_subscription, update, delete
- dashboard_filters: add_dashboard_filter (parameter_mappings sobre cards existentes)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 19:03:08 +02:00
parent 7081c3b4d1
commit 4299482b75
14 changed files with 1105 additions and 0 deletions
@@ -0,0 +1,70 @@
---
name: metabase_create_snippet
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "def metabase_create_snippet(client: MetabaseClient, name: str, content: str, description: str = \"\", collection_id: int = 0) -> dict"
description: "Crea un nuevo SQL snippet reutilizable en Metabase. El snippet se referencia en queries nativas con {{snippet: nombre}}."
tags: [metabase, snippet, create, api, python]
uses_functions: []
uses_types: [MetabaseClient_go_infra]
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [httpx]
params:
- name: client
desc: "instancia autenticada de MetabaseClient"
- name: name
desc: "nombre del snippet; se usa en queries con la sintaxis {{snippet: nombre}}"
- name: content
desc: "SQL del snippet: puede ser una CTE completa, subquery o cualquier fragmento SQL reutilizable"
- name: description
desc: "descripcion opcional del proposito del snippet"
- name: collection_id
desc: "ID de la coleccion donde guardar el snippet; 0 para la raiz (Our analytics)"
output: "dict: snippet creado con id asignado por Metabase, name, content, description, collection_id, created_at"
tested: false
tests: []
test_file_path: ""
file_path: "python/functions/metabase/snippets.py"
---
## Ejemplo
```python
# Crear snippet con CTE reutilizable
snippet = metabase_create_snippet(
client,
"supply_orders_cte",
"""
WITH supply_full AS (
SELECT so.id, so.service_request_id,
sr.channel_id, ch.name AS channel_name
FROM supply_orders so
LEFT JOIN service_requests sr ON so.service_request_id = sr.id
LEFT JOIN channels ch ON sr.channel_id = ch.id
)
""",
description="CTE base de supply_orders con 6 JOINs para cruce con NAV",
)
print(snippet["id"], snippet["name"])
# Usar el snippet en una card
from metabase.cards import metabase_create_card
card = metabase_create_card(client, "Revenue", {
"database": 6,
"type": "native",
"native": {
"query": "{{snippet: supply_orders_cte}} SELECT channel_name, COUNT(*) FROM supply_full GROUP BY 1"
}
})
```
## Notas
El campo `name` debe ser unico en Metabase — el servidor retorna 400 si ya existe un snippet con ese nombre.
Si `collection_id` es 0 o no se provee, el snippet se guarda en la raiz.
Solo se envian al body los campos no vacios/cero para evitar conflictos con defaults del servidor.