generated from gilles/template-webapp
claude code
This commit is contained in:
171
backend/app/repositories/location.py
Normal file
171
backend/app/repositories/location.py
Normal file
@@ -0,0 +1,171 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user