Files
Northern-Thailand-Ping-Rive…/src/postgres_history.py
T

67 lines
2.4 KiB
Python

"""Read historical station measurements from PostgreSQL."""
import datetime
import os
from typing import Dict, List, Optional
from sqlalchemy import create_engine, text
class PostgresHistory:
def __init__(self, connection_string: Optional[str] = None, engine=None):
connection_string = connection_string or os.getenv("POSTGRES_CONNECTION_STRING")
if engine is None and not connection_string:
raise RuntimeError("POSTGRES_CONNECTION_STRING is not configured")
self.engine = engine or create_engine(connection_string, pool_pre_ping=True)
def station_history(
self,
station_code: str,
start: datetime.datetime,
end: datetime.datetime,
limit: int = 2000,
) -> List[Dict]:
if not 1 <= limit <= 10000:
raise ValueError("limit must be between 1 and 10000")
if start >= end:
raise ValueError("start must be before end")
query = text(
"""
SELECT m.timestamp, s.station_code, m.water_level,
m.discharge, m.discharge_percent
FROM water_measurements m
JOIN stations s ON m.station_id = s.id
WHERE s.station_code = :station_code
AND m.timestamp >= :start_time
AND m.timestamp <= :end_time
ORDER BY m.timestamp ASC
LIMIT :limit
"""
)
with self.engine.connect() as connection:
rows = connection.execute(
query,
{
"station_code": station_code,
"start_time": start,
"end_time": end,
"limit": limit,
},
)
result = []
for row in rows:
timestamp = row[0]
if isinstance(timestamp, str):
timestamp = datetime.datetime.fromisoformat(timestamp)
result.append(
{
"timestamp": timestamp,
"station_code": row[1],
"water_level": float(row[2]) if row[2] is not None else None,
"discharge": float(row[3]) if row[3] is not None else None,
"discharge_percent": float(row[4]) if row[4] is not None else None,
}
)
return result