from __future__ import annotations import uuid from typing import Literal from sqlalchemy.orm import Session from app.core.errors import AppError from app.models import Project from app.schemas.project import ProjectCreate, ProjectRead, ProjectUpdate class ProjectService: @staticmethod def list_projects( db: Session, limit: int = 50, offset: int = 0, name: str | None = None, project_status: Literal["active", "archived", "all"] = "active", ) -> tuple[list[ProjectRead], int]: query = db.query(Project).filter(Project.status != "deleted") if project_status != "all": query = query.filter(Project.status == project_status) if name: query = query.filter(Project.name == name.strip()) query = query.order_by(Project.created_at.desc()) total = query.count() items = query.offset(offset).limit(limit).all() return [ProjectRead.model_validate(item) for item in items], total @staticmethod def create_project(db: Session, payload: ProjectCreate) -> ProjectRead: project = Project( name=payload.name.strip(), description=(payload.description or "").strip() or None, region=payload.region or "Belgium and Belgian North Sea", ) db.add(project) db.commit() db.refresh(project) return ProjectRead.model_validate(project) @staticmethod def get_project(db: Session, project_id: uuid.UUID) -> ProjectRead | None: project = db.get(Project, project_id) if not project or project.status == "deleted": return None return ProjectRead.model_validate(project) @staticmethod def update_project(db: Session, project_id: uuid.UUID, payload: ProjectUpdate) -> ProjectRead | None: project = db.get(Project, project_id) if not project or project.status == "deleted": return None payload_data = payload.model_dump(exclude_unset=True) changed = False for key, value in payload_data.items(): if value is None: continue setattr(project, key, value) changed = True if not changed: raise AppError(code="NO_CHANGES", message="No updatable fields provided", status_code=422) db.add(project) db.commit() db.refresh(project) return ProjectRead.model_validate(project) @staticmethod def delete_project(db: Session, project_id: uuid.UUID) -> bool: project = db.get(Project, project_id) if not project or project.status == "deleted": return False project.status = "deleted" db.add(project) db.commit() return True