feat(backend): refactor mono repository

This commit is contained in:
2025-08-27 11:04:56 -04:00
parent d0dbba21fb
commit be1c729220
37 changed files with 2534 additions and 452 deletions

164
backend/tests/conftest.py Normal file
View File

@@ -0,0 +1,164 @@
# tests/conftest.py
import os
import pytest
# ----------------------------------------------------------------------
# Import the concrete classes from your backend package.
# Adjust the import path if your package layout differs.
# ----------------------------------------------------------------------
from backend.db import DatabaseConnection
from backend.repositories import (
MemberRepository,
ClassificationRepository,
ServiceTypeRepository,
ServiceAvailabilityRepository,
)
# ----------------------------------------------------------------------
# Path to the full schema (DDL) that creates every table, including
# ServiceAvailability.
# ----------------------------------------------------------------------
@pytest.fixture(scope="session")
def schema_path() -> str:
"""Absolute path to the SQL file that creates the test schema."""
return os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "schema.sql")
)
# ----------------------------------------------------------------------
# Fresh inmemory SQLite DB with the full schema applied.
# ----------------------------------------------------------------------
@pytest.fixture
def db_connection(schema_path: str) -> DatabaseConnection:
conn = DatabaseConnection(":memory:")
# Load the DDL.
with open(schema_path, "r", encoding="utf-8") as f:
ddl = f.read()
conn._conn.executescript(ddl) # apply the whole schema
conn._conn.commit()
yield conn
conn.close()
# ----------------------------------------------------------------------
# Seed lookup tables that have foreignkey relationships.
# ----------------------------------------------------------------------
@pytest.fixture
def seed_lookup_tables(db_connection: DatabaseConnection):
"""
Insert rows into lookup tables that other tables reference.
Currently we need:
• Classifications for Member tests
• ServiceTypes for ServiceTypeRepository tests
• ServiceAvailability for the repo we are testing now
"""
# ---- Classifications -------------------------------------------------
classifications = [
("Soprano",), # ClassificationId = 1
("Alto / Mezzo",), # ClassificationId = 2
("Tenor",), # ClassificationId = 3
("Baritone",), # ClassificationId = 4
]
for name in classifications:
db_connection.execute(
"INSERT INTO Classifications (ClassificationName) VALUES (?)",
name,
)
# ---- ServiceTypes ----------------------------------------------------
# These are the three timeslot examples you asked for.
service_types = [("9AM",), ("11AM",), ("6PM",)]
for name in service_types:
db_connection.execute(
"INSERT INTO ServiceTypes (TypeName) VALUES (?)",
name,
)
# ---- ServiceAvailability ---------------------------------------------
# We need a couple of members first, otherwise the FK constraints will
# reject the inserts. We'll create two dummy members (Alice = 1,
# Bob = 2) and then map them to the three slots.
#
# NOTE: In a real test suite you would probably use the MemberRepository
# to create these rows, but inserting directly keeps the fixture fast and
# independent of the Member repo implementation.
dummy_members = [
("Alice", "Smith", "alice@example.com", None, None, 1, None, 1),
("Bob", "Jones", "bob@example.com", None, None, 2, None, 1),
]
for (
fn, ln, email, phone, notes,
classification_id, is_active, member_id_placeholder,
) in dummy_members:
# The MemberId column is AUTOINCREMENT, so we omit it.
db_connection.execute(
"""
INSERT INTO Members
(FirstName, LastName, Email, PhoneNumber, Notes,
ClassificationId, IsActive)
VALUES (?, ?, ?, ?, ?, ?, ?)
""",
(fn, ln, email, phone, notes, classification_id, is_active),
)
# At this point SQLite has assigned MemberIds 1 and 2.
# Map them to the three servicetype slots:
# Alice → 9AM (id=1) and 6PM (id=3)
# Bob → 11AM (id=2) and 6PM (id=3)
availability = [
(1, 1), # Alice 9AM
(1, 3), # Alice 6PM
(2, 2), # Bob 11AM
(2, 3), # Bob 6PM
]
for member_id, service_type_id in availability:
db_connection.execute(
"""
INSERT INTO ServiceAvailability (MemberId, ServiceTypeId)
VALUES (?, ?)
""",
(member_id, service_type_id),
)
# Commit everything so downstream fixtures see the data.
db_connection._conn.commit()
# ----------------------------------------------------------------------
# Repository factories each receives the same fresh DB that already has
# the lookup data seeded.
# ----------------------------------------------------------------------
@pytest.fixture
def member_repo(
db_connection: DatabaseConnection,
seed_lookup_tables,
) -> MemberRepository:
return MemberRepository(db_connection)
@pytest.fixture
def classification_repo(
db_connection: DatabaseConnection,
seed_lookup_tables,
) -> ClassificationRepository:
return ClassificationRepository(db_connection)
@pytest.fixture
def service_type_repo(
db_connection: DatabaseConnection,
seed_lookup_tables,
) -> ServiceTypeRepository:
return ServiceTypeRepository(db_connection)
@pytest.fixture
def service_availability_repo(
db_connection: DatabaseConnection,
seed_lookup_tables,
) -> ServiceAvailabilityRepository:
return ServiceAvailabilityRepository(db_connection)