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,105 @@
# myapp/repositories/service.py
# ------------------------------------------------------------
# Persistence layer for Servicerelated models.
# ------------------------------------------------------------
from __future__ import annotations
from datetime import date, datetime
from typing import List, Optional, Sequence, Any
from ..db import BaseRepository
from ..models import Service as ServiceModel
# ----------------------------------------------------------------------
# ServiceRepository handles the ``Services`` table
# ----------------------------------------------------------------------
class ServiceRepository(BaseRepository[ServiceModel]):
"""
CRUD + query helpers for the ``Services`` table.
Business rules (e.g. “do not schedule past services”) belong in a
service layer that composes this repository with the others.
"""
_TABLE = "Services"
_PK = "ServiceId"
# ------------------------------
# Basic CRUD
# ------------------------------
def create(
self,
service_type_id: int,
service_date: date,
) -> ServiceModel:
"""
Insert a new service row.
``service_date`` can be a ``datetime.date`` or an ISO8601 string.
"""
svc = ServiceModel(
ServiceId=-1, # placeholder will be overwritten
ServiceTypeId=service_type_id,
ServiceDate=service_date,
)
return self._insert(self._TABLE, svc, self._PK)
def get_by_id(self, service_id: int) -> Optional[ServiceModel]:
sql = f"SELECT * FROM {self._TABLE} WHERE {self._PK} = ?"
row = self.db.fetchone(sql, (service_id,))
return ServiceModel.from_row(row) if row else None
def list_all(self) -> List[ServiceModel]:
return self._select_all(self._TABLE, ServiceModel)
# ------------------------------
# Domainspecific queries
# ------------------------------
def upcoming(self, after: Optional[date] = None, limit: int = 100) -> List[ServiceModel]:
"""
Return services that occur on or after ``after`` (defaults to today).
Results are ordered chronologically.
"""
after_date = after or date.today()
sql = f"""
SELECT *
FROM {self._TABLE}
WHERE ServiceDate >= ?
ORDER BY ServiceDate ASC
LIMIT ?
"""
rows = self.db.fetchall(sql, (after_date.isoformat(), limit))
return [ServiceModel.from_row(r) for r in rows]
def by_type(self, service_type_ids: Sequence[int]) -> List[ServiceModel]:
"""
Fetch all services whose ``ServiceTypeId`` is in the supplied list.
Empty input → empty list (no DB roundtrip).
"""
if not service_type_ids:
return []
placeholders = ",".join("?" for _ in service_type_ids)
sql = f"""
SELECT *
FROM {self._TABLE}
WHERE ServiceTypeId IN ({placeholders})
ORDER BY ServiceDate ASC
"""
rows = self.db.fetchall(sql, tuple(service_type_ids))
return [ServiceModel.from_row(r) for r in rows]
# ------------------------------
# Update helpers (optional)
# ------------------------------
def reschedule(self, service_id: int, new_date: date) -> None:
"""
Change the ``ServiceDate`` of an existing service.
"""
sql = f"""
UPDATE {self._TABLE}
SET ServiceDate = ?
WHERE {self._PK} = ?
"""
self.db.execute(sql, (new_date.isoformat(), service_id))