import os import sqlalchemy from databases import Database from sqlalchemy import MetaData, Table, Column, Integer, String, Float, DateTime # Environment: Postgres/TimescaleDB connection URL DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:password@localhost:5432/dereth") # Async database client database = Database(DATABASE_URL) # Metadata for SQLAlchemy Core metadata = MetaData() # Telemetry events hypertable schema telemetry_events = Table( "telemetry_events", metadata, Column("id", Integer, primary_key=True), Column("character_name", String, nullable=False), Column("char_tag", String, nullable=True), Column("session_id", String, nullable=False, index=True), Column("timestamp", DateTime(timezone=True), nullable=False, index=True), Column("ew", Float, nullable=False), Column("ns", Float, nullable=False), Column("z", Float, nullable=False), Column("kills", Integer, nullable=False), Column("kills_per_hour", Float, nullable=True), Column("onlinetime", String, nullable=True), Column("deaths", Integer, nullable=False), Column("rares_found", Integer, nullable=False), Column("prismatic_taper_count", Integer, nullable=False), Column("vt_state", String, nullable=True), # New telemetry metrics Column("mem_mb", Float, nullable=True), Column("cpu_pct", Float, nullable=True), Column("mem_handles", Integer, nullable=True), Column("latency_ms", Float, nullable=True), ) # Persistent kill statistics per character char_stats = Table( "char_stats", metadata, Column("character_name", String, primary_key=True), Column("total_kills", Integer, nullable=False, default=0), ) async def init_db_async(): """Create tables and enable TimescaleDB hypertable for telemetry_events.""" # Create tables in Postgres engine = sqlalchemy.create_engine(DATABASE_URL) metadata.create_all(engine) # Enable TimescaleDB extension and convert telemetry_events to hypertable with engine.connect() as conn: conn.execute("CREATE EXTENSION IF NOT EXISTS timescaledb;") conn.execute( "SELECT create_hypertable('telemetry_events', 'timestamp', if_not_exists => true);" )