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

View File

@@ -0,0 +1,158 @@
# myapp/repositories/service_availability.py
# ------------------------------------------------------------
# Persistence layer for the ServiceAvailability table.
# ------------------------------------------------------------
from __future__ import annotations
from typing import List, Optional, Sequence, Any
from ..db import BaseRepository
from ..models import ServiceAvailability as ServiceAvailabilityModel
class ServiceAvailabilityRepository(BaseRepository[ServiceAvailabilityModel]):
"""
CRUD + query helpers for the ``ServiceAvailability`` table.
The table records which members are allowed to receive which
servicetype slots (e.g. “9AM”, “11AM”, “6PM”). All SQL is
parameterised to stay safe from injection attacks.
"""
# ------------------------------------------------------------------
# Tablelevel constants change them in one place if the schema evolves.
# ------------------------------------------------------------------
_TABLE = "ServiceAvailability"
_PK = "ServiceAvailabilityId"
# ------------------------------------------------------------------
# Basic CRUD helpers
# ------------------------------------------------------------------
def create(
self,
member_id: int,
service_type_id: int,
) -> ServiceAvailabilityModel:
"""
Insert a new availability row.
The ``UNIQUE (MemberId, ServiceTypeId)`` constraint guarantees
idempotency if the pair already exists SQLite will raise an
``IntegrityError``. To make the operation truly idempotent we
first check for an existing row and return it unchanged.
"""
existing = self.get(member_id, service_type_id)
if existing:
return existing
avail = ServiceAvailabilityModel(
ServiceAvailabilityId=-1, # placeholder will be overwritten
MemberId=member_id,
ServiceTypeId=service_type_id,
)
return self._insert(self._TABLE, avail, self._PK)
def get(
self,
member_id: int,
service_type_id: int,
) -> Optional[ServiceAvailabilityModel]:
"""
Retrieve a single availability record for the given member /
servicetype pair, or ``None`` if it does not exist.
"""
sql = f"""
SELECT *
FROM {self._TABLE}
WHERE MemberId = ?
AND ServiceTypeId = ?
"""
row = self.db.fetchone(sql, (member_id, service_type_id))
return ServiceAvailabilityModel.from_row(row) if row else None
def delete(self, availability_id: int) -> None:
"""
Harddelete an availability row by its primary key.
Use with care most callers will prefer ``revoke`` (by member &
service type) which is a bit more expressive.
"""
sql = f"DELETE FROM {self._TABLE} WHERE {self._PK} = ?"
self.db.execute(sql, (availability_id,))
# ------------------------------------------------------------------
# Convenience “grant / revoke” helpers (the most common ops)
# ------------------------------------------------------------------
def grant(self, member_id: int, service_type_id: int) -> ServiceAvailabilityModel:
"""
Public API to give a member permission for a particular service slot.
Internally delegates to ``create`` which already handles the
idempotentcheck.
"""
return self.create(member_id, service_type_id)
def revoke(self, member_id: int, service_type_id: int) -> None:
"""
Remove a members permission for a particular service slot.
"""
sql = f"""
DELETE FROM {self._TABLE}
WHERE MemberId = ?
AND ServiceTypeId = ?
"""
self.db.execute(sql, (member_id, service_type_id))
# ------------------------------------------------------------------
# Query helpers used by the scheduling service
# ------------------------------------------------------------------
def list_by_member(self, member_id: int) -> List[ServiceAvailabilityModel]:
"""
Return every ``ServiceAvailability`` row that belongs to the given
member. Handy for building a members personal “available slots”
view.
"""
sql = f"""
SELECT *
FROM {self._TABLE}
WHERE MemberId = ?
"""
rows = self.db.fetchall(sql, (member_id,))
return [ServiceAvailabilityModel.from_row(r) for r in rows]
def list_by_service_type(self, service_type_id: int) -> List[ServiceAvailabilityModel]:
"""
Return all members that are allowed to receive the given service type.
"""
sql = f"""
SELECT *
FROM {self._TABLE}
WHERE ServiceTypeId = ?
"""
rows = self.db.fetchall(sql, (service_type_id,))
return [ServiceAvailabilityModel.from_row(r) for r in rows]
def list_all(self) -> List[ServiceAvailabilityModel]:
"""
Return every row in the table useful for admin dashboards or
bulkexport scripts.
"""
return self._select_all(self._TABLE, ServiceAvailabilityModel)
# ------------------------------------------------------------------
# Helper for the roundrobin scheduler
# ------------------------------------------------------------------
def members_for_type(self, service_type_id: int) -> List[int]:
"""
Return a flat list of ``MemberId`` values that are eligible for the
supplied ``service_type_id``. The scheduling service can then
intersect this list with the pool of members that have the correct
classification, activity flag, etc.
"""
sql = f"""
SELECT MemberId
FROM {self._TABLE}
WHERE ServiceTypeId = ?
"""
rows = self.db.fetchall(sql, (service_type_id,))
# ``rows`` is a sequence of sqlite3.Row objects; each row acts like a dict.
return [row["MemberId"] for row in rows]