86d68dc9f0
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>
5.4 KiB
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
hostdebe ser la IP LAN del Windows que corre SQL Server, NOlocalhost(desde WSL2 localhost no alcanza al host Windows). Ver memoriawsl2-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.--passwordliteral 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 comoparams, jamás concatenados en el SQL (inyección). mssql_queryno abre ni cierra la conexión — la toma prestada. Para ráfagas de queries, abre conmssql_connectuna vez y reúsala; el pipelinerun_mssql_queryabre 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
pymssqlinstalado en el venv (uv add pymssql). Import perezoso: el módulo carga sin la dependencia, pero la llamada falla conRuntimeErrorclaro 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 grupoduckdb. 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.