File size: 3,181 Bytes
0cd8655
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356ae73
 
 
 
 
 
 
 
0cd8655
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import os
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker

DB_PATH = os.path.join(os.path.dirname(__file__), "hvac_supervisory.db")
DATABASE_URL = os.getenv("DATABASE_URL") or os.getenv("HVAC_DATABASE_URL") or f"sqlite:///{DB_PATH}"

_connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
_engine_kwargs: dict = {"connect_args": _connect_args, "pool_pre_ping": True}
if not DATABASE_URL.startswith("sqlite"):
    _engine_kwargs.update(
        pool_size=int(os.getenv("HVAC_DB_POOL_SIZE", "10")),
        max_overflow=int(os.getenv("HVAC_DB_MAX_OVERFLOW", "20")),
        pool_recycle=int(os.getenv("HVAC_DB_POOL_RECYCLE", "1800")),
    )
engine = create_engine(DATABASE_URL, **_engine_kwargs)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)


def _allow_create_all() -> bool:
    explicit = os.environ.get("HVAC_ALLOW_CREATE_ALL")
    if explicit is not None:
        return explicit.lower() in ("1", "true", "yes")
    return os.getenv("HVAC_ENV", "development").lower() != "production"


def _run_alembic() -> None:
    try:
        from alembic.config import Config
        from alembic import command

        root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
        cfg = Config(os.path.join(root, "alembic.ini"))
        cfg.set_main_option("script_location", os.path.join(root, "alembic"))
        cfg.set_main_option("sqlalchemy.url", DATABASE_URL)
        command.upgrade(cfg, "head")
    except Exception as exc:
        print(f"[alembic] upgrade skipped or failed: {exc}")


def init_db():
    from database.models import Base
    try:
        import database.models_o1  # noqa: F401
    except Exception:
        pass
    try:
        import database.models_ml  # noqa: F401
    except Exception:
        pass

    _run_alembic()
    if _allow_create_all():
        Base.metadata.create_all(bind=engine)
    try:
        from backend.services.o1_telemetry_service import ensure_point_map_and_config
        ensure_point_map_and_config()
    except Exception as exc:
        print(f"[o1] point map init skipped: {exc}")


def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


def database_ok() -> bool:
    try:
        with engine.connect() as conn:
            conn.execute(text("SELECT 1"))
        return True
    except Exception:
        return False


def alembic_head_ok() -> bool:
    try:
        from alembic.config import Config
        from alembic.script import ScriptDirectory
        from alembic.runtime.migration import MigrationContext

        root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
        cfg = Config(os.path.join(root, "alembic.ini"))
        cfg.set_main_option("script_location", os.path.join(root, "alembic"))
        script = ScriptDirectory.from_config(cfg)
        heads = set(script.get_heads())
        with engine.connect() as conn:
            context = MigrationContext.configure(conn)
            current = set(context.get_current_heads())
        return bool(current) and current.issubset(heads)
    except Exception:
        return True