55 lines
1.5 KiB
Python
55 lines
1.5 KiB
Python
|
|
"""
|
||
|
|
shared.py — fleettickets · minimal DB + helper utilities.
|
||
|
|
|
||
|
|
Self-contained replacement for the handful of helpers the loader used to import
|
||
|
|
from the tracksolid repo's `ts_shared_rev`, so fleettickets stands alone.
|
||
|
|
Connection comes from the DATABASE_URL env var (points at the shared
|
||
|
|
`tracksolid_db`, where the `tickets` schema lives).
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import logging
|
||
|
|
import os
|
||
|
|
from contextlib import contextmanager
|
||
|
|
from typing import Any, Optional
|
||
|
|
|
||
|
|
import psycopg2
|
||
|
|
|
||
|
|
|
||
|
|
def get_logger(name: str) -> logging.Logger:
|
||
|
|
logger = logging.getLogger(f"fleettickets.{name}")
|
||
|
|
if not logger.handlers:
|
||
|
|
h = logging.StreamHandler()
|
||
|
|
h.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(name)s — %(message)s",
|
||
|
|
datefmt="%Y-%m-%d %H:%M:%S"))
|
||
|
|
logger.addHandler(h)
|
||
|
|
logger.setLevel(os.getenv("LOG_LEVEL", "INFO"))
|
||
|
|
return logger
|
||
|
|
|
||
|
|
|
||
|
|
@contextmanager
|
||
|
|
def get_conn():
|
||
|
|
"""DB connection context manager. Auto-commits on success, rolls back on error."""
|
||
|
|
dsn = os.environ.get("DATABASE_URL")
|
||
|
|
if not dsn:
|
||
|
|
raise RuntimeError("DATABASE_URL is not set")
|
||
|
|
conn = psycopg2.connect(dsn)
|
||
|
|
try:
|
||
|
|
conn.autocommit = False
|
||
|
|
yield conn
|
||
|
|
conn.commit()
|
||
|
|
except Exception:
|
||
|
|
conn.rollback()
|
||
|
|
raise
|
||
|
|
finally:
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
|
||
|
|
def clean(v: Any) -> Optional[str]:
|
||
|
|
"""Trimmed string, or None if empty/None."""
|
||
|
|
if v is None:
|
||
|
|
return None
|
||
|
|
s = str(v).strip()
|
||
|
|
return s if s != "" else None
|