Files
fn_registry/docs/capabilities/sql-connect.md
T
egutierrez 86d68dc9f0 feat(infra): conexion y consulta directa a SQL Server (Navision) via pymssql
Grupo de capacidad nuevo 'sql-connect' (3 funciones) para conectar a un
Microsoft SQL Server (donde corre Navision) y consultar directamente, en
lugar del ida y vuelta manual de pegar CSVs.

- mssql_connect_py_infra: abre conexion pymssql (login_timeout acotado,
  credenciales por argumento, RuntimeError claro si falla).
- mssql_query_py_infra: SELECT parametrizada con binding seguro (sin
  inyeccion) sobre conexion abierta; devuelve {columns, rows, row_count};
  0 filas -> lista vacia; max_rows con fetchmany; read-only.
- run_mssql_query_py_pipelines: one-shot que compone connect+query y cierra
  siempre; CLI imprime JSON o CSV; contrasena desde env var (pass).

Pagina madre docs/capabilities/sql-connect.md + fila en INDEX.md.
Dependencia pymssql>=2.3.13 anadida a python/pyproject.toml + uv.lock.
Tests mock-based (11) verdes; error path verificado end-to-end contra el
driver real (host inalcanzable -> RuntimeError, acotado por login_timeout).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:29:49 +02:00

5.4 KiB

Capability: sql-connect

Conexión directa y consulta a un Microsoft SQL Server desde el registry, con el caso prioritario de Navision (el ERP corre sobre SQL Server). Las funciones Python usan el driver pymssql (más simple en Linux/WSL que pyodbc: trae FreeTDS embebido, no necesita ODBC driver manager).

Existe para eliminar el ida y vuelta manual con Navision: en vez de escribir una query, que el usuario la ejecute en su SGBD y pegue el CSV, estas funciones se conectan al servidor y devuelven las filas — iteración rápida sobre una query en un solo comando.

Funciones

ID Firma Que hace
mssql_connect_py_infra mssql_connect(host, database, user, password, port=1433, login_timeout=15, query_timeout=30) -> pymssql.Connection Abre una conexión a SQL Server vía pymssql. Credenciales por argumento (nunca hardcodeadas). login_timeout acota la fase de login para que un host inalcanzable no cuelgue. Devuelve la conexión abierta; el caller la cierra con .close(). Lanza RuntimeError claro (host:port/db) si falla.
mssql_query_py_infra mssql_query(conn, sql, params=None, max_rows=None) -> dict Ejecuta una SELECT parametrizada sobre una conexión abierta y mapea las filas a dicts. Binding seguro del driver (placeholders %s/%(nombre)s, sin inyección). Devuelve {columns, rows:[{col:val}], row_count}. 0 filas → lista vacía sin error. max_rows limita con fetchmany. Read-only (no commit), no cierra la conexión.
run_mssql_query_py_pipelines run_mssql_query(host, database, user, password, sql, params=None, port=1433, max_rows=None, login_timeout=15, query_timeout=30) -> dict Pipeline one-shot: compone mssql_connect + mssql_query y cierra siempre la conexión (try/finally). CLI imprime JSON o CSV. Para iterar sobre una query de Navision en un solo fn run.

Ejemplo canónico

One-shot para iterar sobre Navision (la contraseña se lee de una env var, nunca se pasa por la línea de comandos):

cd /home/egutierrez/fn_registry
MSSQL_PASSWORD=$(pass navision/password) \
  ./fn run run_mssql_query \
    --host 10.0.0.5 --database navdb --user sa \
    --sql "SELECT TOP 5 [No_], [Amount] FROM [dbo].[Cartera] WHERE [Customer No_] = %s" \
    --param CLI-0001 \
    --format csv

Conexión persistente para muchas queries seguidas (abrir una vez, consultar N veces):

import os, sys
sys.path.insert(0, "python/functions")
from infra.mssql_connect import mssql_connect
from infra.mssql_query import mssql_query

conn = mssql_connect("10.0.0.5", "navdb", "sa", os.environ["MSSQL_PASSWORD"])
try:
    abiertos = mssql_query(
        conn,
        "SELECT [No_], [Amount] FROM [dbo].[Cartera] WHERE [Open] = 1 AND [Customer No_] = %s",
        params=("CLI-0001",),
    )
    print(abiertos["row_count"], abiertos["columns"])
    posted = mssql_query(conn, "SELECT TOP 10 [Document No_], [Amount] FROM [dbo].[Posted Cartera]")
    print(posted["rows"])
finally:
    conn.close()

Gotchas del grupo

  • Conectividad WSL2 → Windows: el host debe ser la IP LAN del Windows que corre SQL Server, NO localhost (desde WSL2 localhost no alcanza al host Windows). Ver memoria wsl2-localhost-forwarding. Probablemente el servidor real de Navision no sea alcanzable desde un entorno aislado sin red a la oficina + credenciales.
  • Credenciales desde pass, nunca hardcodeadas. Patrón: MSSQL_PASSWORD=$(pass navision/password) ./fn run run_mssql_query .... La función recibe la contraseña como argumento; el caller la resuelve. --password literal existe pero queda visible en la lista de procesos — usa --password-env.
  • Placeholders pymssql son %s (posicional) y %(nombre)s (nombrado), NO ? (eso es pyodbc). Pasa los valores como params, jamás concatenados en el SQL (inyección).
  • mssql_query no abre ni cierra la conexión — la toma prestada. Para ráfagas de queries, abre con mssql_connect una vez y reúsala; el pipeline run_mssql_query abre y cierra por llamada (cómodo, no eficiente en ráfaga).
  • Read-only por uso: pensado para SELECT (Navision: cartera, posted cartera, movimientos). No hace commit.
  • Requiere pymssql instalado en el venv (uv add pymssql). Import perezoso: el módulo carga sin la dependencia, pero la llamada falla con RuntimeError claro si falta.
  • Datos sintéticos en ejemplos [POL-MMNSEG-001-1.0]: los No_/Customer No_ de los ejemplos son ficticios. Sobre datos reales de Navision aplica la política de protección de datos.

Fronteras

  • Solo SQL Server (Navision). No es una capa SQL genérica: para PostgreSQL usa el grupo postgres; para DuckDB el grupo duckdb. Generalizar a MySQL/otros engines sería especulativo (KISS) hasta que haya un caso real.
  • No es ETL ni BI: solo conecta y devuelve filas. Para llevar datos de Navision a un destino analítico, compón con los grupos duckdb/postgres (cargar las filas) o léelas en un notebook.
  • No gestiona el servidor (no crea bases, no administra logins). Solo cliente de lectura.

Relación con otros grupos

  • postgres / duckdb — capas CRUD para otros engines; mismo espíritu (conectar + consultar), distinto motor. SQL Server (Navision) es la fuente; esos son destinos analíticos/BI.
  • metabase / bigquery — el trabajo Aurgi consume datos ya en BigQuery/Metabase; este grupo abre la puerta a leer Navision en origen para iterar queries antes de modelarlas.