Files
home_stock/backend/app/repositories/location.py
2026-01-28 19:22:30 +01:00

172 lines
5.2 KiB
Python

"""Repository pour les emplacements."""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from app.models.location import Location, LocationType
from app.repositories.base import BaseRepository
class LocationRepository(BaseRepository[Location]):
"""Repository pour les opérations sur les emplacements."""
def __init__(self, db: AsyncSession) -> None:
"""Initialise le repository."""
super().__init__(Location, db)
async def get_with_children(self, id: int) -> Location | None:
"""Récupère un emplacement avec ses enfants.
Args:
id: ID de l'emplacement
Returns:
L'emplacement avec ses enfants ou None
"""
result = await self.db.execute(
select(Location)
.options(selectinload(Location.children))
.where(Location.id == id)
)
return result.scalar_one_or_none()
async def get_root_locations(self) -> list[Location]:
"""Récupère tous les emplacements racine (sans parent).
Returns:
Liste des emplacements racine
"""
result = await self.db.execute(
select(Location)
.where(Location.parent_id.is_(None))
.order_by(Location.name)
)
return list(result.scalars().all())
async def get_children(self, parent_id: int) -> list[Location]:
"""Récupère les enfants directs d'un emplacement.
Args:
parent_id: ID du parent
Returns:
Liste des enfants
"""
result = await self.db.execute(
select(Location)
.where(Location.parent_id == parent_id)
.order_by(Location.name)
)
return list(result.scalars().all())
async def get_by_type(self, type: LocationType) -> list[Location]:
"""Récupère tous les emplacements d'un type donné.
Args:
type: Type d'emplacement
Returns:
Liste des emplacements
"""
result = await self.db.execute(
select(Location)
.where(Location.type == type)
.order_by(Location.path)
)
return list(result.scalars().all())
async def get_full_tree(self) -> list[Location]:
"""Récupère l'arborescence complète des emplacements.
Returns:
Liste des emplacements racine avec enfants chargés récursivement
"""
# Charger tous les emplacements avec leurs enfants
result = await self.db.execute(
select(Location)
.options(selectinload(Location.children))
.order_by(Location.path)
)
all_locations = list(result.scalars().all())
# Retourner seulement les racines (les enfants sont déjà chargés)
return [loc for loc in all_locations if loc.parent_id is None]
async def get_with_item_count(self, id: int) -> tuple[Location, int] | None:
"""Récupère un emplacement avec le nombre d'objets.
Args:
id: ID de l'emplacement
Returns:
Tuple (emplacement, nombre d'objets) ou None
"""
result = await self.db.execute(
select(Location)
.options(selectinload(Location.items))
.where(Location.id == id)
)
location = result.scalar_one_or_none()
if location is None:
return None
return location, len(location.items)
async def create_with_path(
self,
name: str,
type: LocationType,
parent_id: int | None = None,
description: str | None = None,
) -> Location:
"""Crée un emplacement avec calcul automatique du chemin.
Args:
name: Nom de l'emplacement
type: Type d'emplacement
parent_id: ID du parent (None si racine)
description: Description optionnelle
Returns:
L'emplacement créé
"""
# Calculer le chemin
if parent_id is None:
path = name
else:
parent = await self.get(parent_id)
if parent is None:
path = name
else:
path = f"{parent.path} > {name}"
return await self.create(
name=name,
type=type,
parent_id=parent_id,
path=path,
description=description,
)
async def update_paths_recursive(self, location: Location) -> None:
"""Met à jour récursivement les chemins après modification.
Args:
location: Emplacement modifié
"""
# Mettre à jour le chemin de cet emplacement
if location.parent_id is None:
location.path = location.name
else:
parent = await self.get(location.parent_id)
if parent:
location.path = f"{parent.path} > {location.name}"
else:
location.path = location.name
# Mettre à jour les enfants
children = await self.get_children(location.id)
for child in children:
child.path = f"{location.path} > {child.name}"
await self.update_paths_recursive(child)