mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Move the live plan, recommendation, recommendation_materials and (retiring) plan_recommendations tables into a new infrastructure/postgres/modelling/ subpackage as single SQLModel definitions (the epc_property pattern), absorbing the rebuild's partial PlanRow/RecommendationRow mirrors and carrying full legacy column parity plus recommendation.plan_id. Out-of-cluster references are plain indexed ints (mirror convention); the live FKs are owned by the Drizzle schema. backend/app/db/models/recommendations.py becomes a re-export shim (ScenarioModel/InstalledMeasure stay for a later slice). Fix the export conftest to create SQLModel-first (so Base funding_package's FK to the now-SQLModel plan resolves) and skip the redundant drop_all on its function-scoped throwaway DB (the epc enum type is now shared across both metadatas). Resolves the pre-existing dual-definition collision: the rebuild and legacy export suites are now co-runnable. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
65 lines
2.2 KiB
Python
65 lines
2.2 KiB
Python
import pytest
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
from backend.app.db.base import Base
|
|
from sqlmodel import SQLModel
|
|
import backend.app.db.models.organisation # noqa: F401 — registers Organisation with SQLModel.metadata
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
def engine(postgresql):
|
|
"""
|
|
Create a SQLAlchemy engine bound to the ephemeral
|
|
pytest-postgresql database.
|
|
"""
|
|
|
|
# Build SQLAlchemy URL from psycopg connection info
|
|
connection_string = (
|
|
f"postgresql+psycopg://"
|
|
f"{postgresql.info.user}:"
|
|
f"{postgresql.info.password}@"
|
|
f"{postgresql.info.host}:"
|
|
f"{postgresql.info.port}/"
|
|
f"{postgresql.info.dbname}"
|
|
)
|
|
|
|
engine = create_engine(connection_string)
|
|
|
|
# Create tables once per test session. SQLModel first: the Modelling tables
|
|
# (`plan` / `recommendation` / …) are SQLModel definitions, and Base tables
|
|
# FK them (`funding_package` → `plan`), so they must exist before Base's
|
|
# create_all runs (ADR-0017 amendment — single model per table).
|
|
SQLModel.metadata.create_all(engine)
|
|
Base.metadata.create_all(engine)
|
|
|
|
# Yeild will split this function into two phase. 1) setup and 2) teardown, the latter of which will run after all
|
|
# tests have completed
|
|
yield engine
|
|
|
|
# The `postgresql` fixture is function-scoped — a fresh, throwaway database
|
|
# per test — so an explicit drop_all is redundant. We skip it: the `epc`
|
|
# Postgres enum type is now shared across both metadatas (Base `portfolio`
|
|
# tables and the SQLModel `plan`), and a two-phase metadata drop cannot drop
|
|
# a cross-metadata type cleanly (ADR-0017 amendment). Disposing the engine
|
|
# and letting the fixture discard the database is correct and conflict-free.
|
|
engine.dispose()
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
def db_session(engine):
|
|
"""
|
|
Provides a clean transactional session per test.
|
|
|
|
Rolls back after each test to keep isolation.
|
|
"""
|
|
|
|
connection = engine.connect()
|
|
transaction = connection.begin()
|
|
|
|
session = sessionmaker(bind=connection)()
|
|
|
|
yield session
|
|
|
|
session.close()
|
|
transaction.rollback()
|
|
connection.close()
|