feat(shell): auto-commit con 31 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
---
|
||||
name: pg_insert_rows
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def pg_insert_rows(dsn: str, table: str, rows: list[dict], add_snapshot_date: bool = True) -> int"
|
||||
description: "Inserta filas (lista de dicts) en una tabla PostgreSQL de forma append-only via psycopg2.extras.execute_values. Deriva columnas de las claves del dict (union si difieren, rellena con None). Opcionalmente inyecta snapshot_date = date.today(). Insercion parametrizada (sin format de strings, evita inyeccion SQL). Commit y cierre de conexion. Retorna el numero de filas insertadas."
|
||||
tags: [postgres, market-intel, infra]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [psycopg2]
|
||||
params:
|
||||
- name: dsn
|
||||
desc: "Cadena de conexion PostgreSQL en formato postgresql://user:pass@host:port/dbname."
|
||||
- name: table
|
||||
desc: "Nombre de la tabla destino (debe existir previamente)."
|
||||
- name: rows
|
||||
desc: "Lista de dicts; cada dict es una fila, sus claves son nombres de columna. Si los esquemas difieren se usa la union de claves y se rellena con None."
|
||||
- name: add_snapshot_date
|
||||
desc: "Si True y una fila no trae snapshot_date, inyecta snapshot_date = date.today() antes de insertar. Default True."
|
||||
output: "Numero entero de filas insertadas (0 si rows esta vacio)."
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "python/functions/infra/pg_insert_rows.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "python", "functions"))
|
||||
from infra.pg_insert_rows import pg_insert_rows
|
||||
|
||||
dsn = "postgresql://scraper:secret@localhost:5432/captacion"
|
||||
rows = [
|
||||
{"name": "Cliente A", "city": "Madrid", "score": 87},
|
||||
{"name": "Cliente B", "city": "Sevilla"}, # sin score -> NULL
|
||||
]
|
||||
# snapshot_date = hoy se inyecta en cada fila automaticamente
|
||||
n = pg_insert_rows(dsn, "leads_raw", rows)
|
||||
print(f"insertadas {n} filas") # insertadas 2 filas
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando escribes datos scrapeados a Postgres en lote append-only y quieres la columna
|
||||
`snapshot_date` poblada sin codigo extra. Usala antes de cualquier dashboard/consulta de
|
||||
market-intel sobre el dato bruto. Cada llamada acumula una nueva foto historica.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- La tabla debe existir antes de llamar — esta funcion NO crea schema (usa `pg_apply_sql` para eso).
|
||||
- Es append-only: NO hace upsert ni deduplica. Llamadas repetidas duplican filas (por diseno, para historico).
|
||||
- El esquema efectivo es la UNION de las claves de todas las filas; columnas ausentes en una fila se insertan como NULL. Si una clave no existe como columna en la tabla, Postgres lanza error y la transaccion entera hace rollback.
|
||||
- `add_snapshot_date=True` solo rellena filas que NO traen ya `snapshot_date`; si tu dict ya la incluye, se respeta.
|
||||
- Requiere `psycopg2` instalado en el venv (import perezoso: el modulo se importa sin la dependencia, pero la llamada falla con RuntimeError claro si falta).
|
||||
- Conexion nueva por llamada (sin pool). Para muchas inserciones pequenas en bucle, agrupa las filas en una sola llamada.
|
||||
Reference in New Issue
Block a user