"""Helper functions for interacting with filament database objects.""" from typing import Optional from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession from spoolman.database import models, vendor from spoolman.exceptions import ItemDeleteError, ItemNotFoundError async def create( *, db: AsyncSession, density: float, diameter: float, name: Optional[str] = None, vendor_id: Optional[int] = None, material: Optional[str] = None, price: Optional[float] = None, weight: Optional[float] = None, spool_weight: Optional[float] = None, article_number: Optional[str] = None, comment: Optional[str] = None, ) -> models.Filament: """Add a new filament to the database.""" vendor_item: Optional[models.Vendor] = None if vendor_id is not None: vendor_item = await vendor.get_by_id(db, vendor_id) db_item = models.Filament( name=name, vendor=vendor_item, material=material, price=price, density=density, diameter=diameter, weight=weight, spool_weight=spool_weight, article_number=article_number, comment=comment, ) db.add(db_item) await db.flush() return db_item async def get_by_id(db: AsyncSession, filament_id: int) -> models.Filament: """Get a filament object from the database by the unique ID.""" filament = await db.get(models.Filament, filament_id) if filament is None: raise ItemNotFoundError(f"No filament with ID {filament_id} found.") return filament async def update( *, db: AsyncSession, filament_id: int, data: dict, ) -> models.Filament: """Update the fields of a filament object.""" filament = await get_by_id(db, filament_id) for k, v in data.items(): if k == "vendor_id": if v is None: filament.vendor = None else: filament.vendor = await vendor.get_by_id(db, v) else: setattr(filament, k, v) await db.flush() return filament async def delete(db: AsyncSession, filament_id: int) -> None: """Delete a filament object.""" filament = await get_by_id(db, filament_id) await db.delete(filament) try: await db.flush() # Flush immediately so any errors are propagated in this request. except IntegrityError as exc: await db.rollback() raise ItemDeleteError("Failed to delete filament.") from exc