refact: phase 1

This commit is contained in:
2025-08-05 06:13:54 +02:00
parent 6de8dc066f
commit b7d8194c51
24 changed files with 1379 additions and 76 deletions

1
repositories/__init__.py Normal file
View File

@@ -0,0 +1 @@
# Repositories module

View File

@@ -0,0 +1,79 @@
from typing import List, Optional
from sqlalchemy.orm import joinedload
from sqlalchemy import and_
from models import Assessment, ClassGroup, Exercise
from .base_repository import BaseRepository
class AssessmentRepository(BaseRepository[Assessment]):
"""Repository pour les évaluations."""
def __init__(self):
super().__init__(Assessment)
def find_by_filters(
self,
trimester: Optional[int] = None,
class_id: Optional[int] = None,
sort_by: str = 'date_desc'
) -> List[Assessment]:
"""Trouve les évaluations selon les filtres."""
query = Assessment.query.options(
joinedload(Assessment.class_group)
)
# Application des filtres
filters = []
if trimester:
filters.append(Assessment.trimester == trimester)
if class_id:
filters.append(Assessment.class_group_id == class_id)
if filters:
query = query.filter(and_(*filters))
# Application du tri
query = self._apply_sorting(query, sort_by)
return query.all()
def find_with_full_details(self, id: int) -> Optional[Assessment]:
"""Trouve une évaluation avec tous ses détails."""
return Assessment.query.options(
joinedload(Assessment.class_group),
joinedload(Assessment.exercises).joinedload(Exercise.grading_elements)
).filter_by(id=id).first()
def find_recent(self, limit: int = 5) -> List[Assessment]:
"""Trouve les évaluations récentes."""
return Assessment.query.order_by(
Assessment.date.desc()
).limit(limit).all()
def find_by_class_group(self, class_group_id: int) -> List[Assessment]:
"""Trouve toutes les évaluations d'une classe."""
return Assessment.query.filter_by(
class_group_id=class_group_id
).order_by(Assessment.date.desc()).all()
def find_by_trimester(self, trimester: int) -> List[Assessment]:
"""Trouve toutes les évaluations d'un trimestre."""
return Assessment.query.filter_by(
trimester=trimester
).order_by(Assessment.date.desc()).all()
def count_by_class_group(self, class_group_id: int) -> int:
"""Compte les évaluations d'une classe."""
return Assessment.query.filter_by(class_group_id=class_group_id).count()
def _apply_sorting(self, query, sort_by: str):
"""Applique le tri à la requête."""
if sort_by == 'date_desc':
return query.order_by(Assessment.date.desc())
elif sort_by == 'date_asc':
return query.order_by(Assessment.date.asc())
elif sort_by == 'title':
return query.order_by(Assessment.title.asc())
elif sort_by == 'class':
return query.join(ClassGroup).order_by(ClassGroup.name.asc())
return query

View File

@@ -0,0 +1,37 @@
from abc import ABC, abstractmethod
from typing import TypeVar, Generic, List, Optional, Dict, Any
from sqlalchemy.orm import Query
from models import db
T = TypeVar('T')
class BaseRepository(Generic[T], ABC):
"""Repository de base avec opérations CRUD."""
def __init__(self, model_class: type):
self.model_class = model_class
self.session = db.session
def find_by_id(self, id: int) -> Optional[T]:
return self.session.get(self.model_class, id)
def find_all(self) -> List[T]:
return self.model_class.query.all()
def save(self, entity: T) -> T:
self.session.add(entity)
return entity
def delete(self, entity: T) -> None:
self.session.delete(entity)
def commit(self) -> None:
self.session.commit()
def rollback(self) -> None:
self.session.rollback()
def flush(self) -> None:
"""Flush pour obtenir les IDs sans committer."""
self.session.flush()