Files
fn_registry/python/functions/infra/mssql_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

82 lines
4.0 KiB
Markdown

---
name: mssql_connect
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "def mssql_connect(host: str, database: str, user: str, password: str, port: int = 1433, login_timeout: int = 15, query_timeout: int = 30) -> pymssql.Connection"
description: "Abre una conexion pymssql a un Microsoft SQL Server (donde corre Navision). Las credenciales llegan siempre por argumento (el caller las saca de pass/env), nunca hardcodeadas. login_timeout acota la fase de conexion/login para evitar cuelgues con un host inalcanzable. Devuelve el objeto conexion pymssql para iterar queries despues."
tags: [mssql, sqlserver, navision, sql-connect, infra]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [pymssql]
params:
- name: host
desc: "Host o IP del servidor SQL Server. Desde WSL2 debe ser la IP LAN de Windows (ej. 10.0.0.5), no localhost."
- name: database
desc: "Nombre de la base de datos a la que conectar (ej. navdb)."
- name: user
desc: "Usuario de login de SQL Server (ej. sa)."
- name: password
desc: "Contrasena del usuario de login. Se pasa desde pass/env, nunca como literal."
- name: port
desc: "Puerto TCP del SQL Server. Por defecto 1433. La funcion lo convierte a string porque pymssql lo exige asi."
- name: login_timeout
desc: "Segundos permitidos para la fase de conexion/login antes de fallar. Por defecto 15. Evita que un host inalcanzable cuelgue indefinidamente."
- name: query_timeout
desc: "Segundos permitidos para cada query ejecutada sobre la conexion devuelta antes de hacer timeout. Por defecto 30."
output: "Un objeto pymssql.Connection abierto. El caller es responsable de cerrarlo con .close() al terminar."
tested: true
tests: ["test_golden_connect_passes_string_port_and_kwargs", "test_error_path_wraps_failure_with_host"]
test_file_path: "python/functions/infra/mssql_connect_test.py"
file_path: "python/functions/infra/mssql_connect.py"
---
## Ejemplo
```python
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "python", "functions"))
from infra.mssql_connect import mssql_connect
# La IP debe ser la IP LAN del servidor Windows: desde WSL2 "localhost" NO
# llega al host Windows. La contrasena llega del entorno, nunca literal.
conn = mssql_connect(
host="10.0.0.5",
database="navdb",
user="sa",
password=os.environ["MSSQL_PASSWORD"],
port=1433,
login_timeout=15,
)
try:
with conn.cursor() as cur:
cur.execute("SELECT TOP 1 name FROM sys.databases")
print(cur.fetchone())
finally:
conn.close()
```
## Cuando usarla
Usala cuando necesites abrir una conexion a un Microsoft SQL Server (donde
corre Navision) antes de iterar queries con `mssql_query`. Es el primer paso
de cualquier pipeline que lea datos de Navision: abre la conexion una vez,
reutilizala para varias queries, y cierrala al final. Triggers: "conecta a
Navision", "lee de SQL Server", "abre conexion mssql".
## Gotchas
- WSL2 -> Windows: usa la IP LAN del servidor Windows, NUNCA `localhost`. Desde dentro de WSL2 `localhost` no alcanza el host Windows (el reenvio de localhost solo funciona Windows -> WSL, no al reves).
- pymssql necesita el puerto como string. La funcion ya convierte `port` a `str(port)` internamente, asi que tu pasas un int normal.
- `login_timeout` esta acotado (15s por defecto) precisamente para que un host inalcanzable o mal configurado falle con un RuntimeError claro en vez de colgarse indefinidamente. Ajustalo si la red es lenta, pero no lo dejes sin limite.
- Credenciales NUNCA hardcodeadas: `user`/`password` llegan por argumento desde `pass`/env. No las escribas literales en el codigo del caller.
- Cierra la conexion con `.close()` al terminar (idealmente en un `finally`). La funcion devuelve un handle abierto y no gestiona su ciclo de vida.
- Requiere `pymssql` instalado en el venv (import perezoso: el modulo importa sin la dependencia, pero la llamada falla con RuntimeError claro si falta).