Added full CRUD operations for filaments

This commit is contained in:
Donkie
2023-04-01 23:39:42 +02:00
parent 2fa91b0632
commit 43dd74c223
4 changed files with 83 additions and 43 deletions

View File

@@ -3,12 +3,14 @@
from typing import Annotated, Optional, Union from typing import Annotated, Optional, Union
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from fastapi.exceptions import RequestValidationError
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from pydantic.error_wrappers import ErrorWrapper
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from spoolson.api.v1.models import Filament, Vendor from spoolson.api.v1.models import Filament, Message
from spoolson.database import filament
from spoolson.database.database import get_db_session from spoolson.database.database import get_db_session
from spoolson.database.filament import create_filament
router = APIRouter( router = APIRouter(
prefix="/filament", prefix="/filament",
@@ -37,30 +39,23 @@ class FilamentParameters(BaseModel):
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this filament type.") comment: Optional[str] = Field(max_length=1024, description="Free text comment about this filament type.")
class FilamentUpdateParameters(FilamentParameters):
density: Optional[float] = Field(gt=0, description="The density of this filament in g/cm3.")
diameter: Optional[float] = Field(gt=0, description="The diameter of this filament in mm.")
@router.get("/") @router.get("/")
async def find(_vendor: Union[int, None] = None) -> list[Filament]: async def find(_vendor: Union[int, None] = None) -> list[Filament]:
return [] return []
@router.get("/{filament_id}") @router.get("/{filament_id}")
async def get(_filament_id: int) -> Filament: async def get(
return Filament( db: Annotated[AsyncSession, Depends(get_db_session)],
id=0, filament_id: int,
name=None, ) -> Filament:
vendor=Vendor( db_item = await filament.get_by_id(db, filament_id)
id=0, return Filament.from_db(db_item)
name="asdf",
comment=None,
),
material=None,
price=None,
density=1,
diameter=1,
weight=None,
spool_weight=None,
article_number=None,
comment=None,
)
@router.post("/") @router.post("/")
@@ -68,7 +63,7 @@ async def create(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
body: FilamentParameters, body: FilamentParameters,
) -> Filament: ) -> Filament:
db_item = await create_filament( db_item = await filament.create(
db=db, db=db,
density=body.density, density=body.density,
diameter=body.diameter, diameter=body.diameter,
@@ -85,27 +80,32 @@ async def create(
return Filament.from_db(db_item) return Filament.from_db(db_item)
@router.put("/{filament_id}") @router.patch("/{filament_id}")
async def update() -> Filament: async def update(
return Filament( db: Annotated[AsyncSession, Depends(get_db_session)],
id=0, filament_id: int,
name=None, body: FilamentUpdateParameters,
vendor=Vendor( ) -> Filament:
id=0, patch_data = body.dict(exclude_unset=True)
name="asdf",
comment=None, if "density" in patch_data and body.density is None:
), raise RequestValidationError([ErrorWrapper(ValueError("density cannot be unset"), ("query", "density"))])
material=None, if "diameter" in patch_data and body.diameter is None:
price=None, raise RequestValidationError([ErrorWrapper(ValueError("diameter cannot be unset"), ("query", "diameter"))])
density=1,
diameter=1, db_item = await filament.update(
weight=None, db=db,
spool_weight=None, filament_id=filament_id,
article_number=None, data=patch_data,
comment=None,
) )
return Filament.from_db(db_item)
@router.delete("/{filament_id}") @router.delete("/{filament_id}")
async def delete() -> None: async def delete(
pass db: Annotated[AsyncSession, Depends(get_db_session)],
filament_id: int,
) -> Message:
await filament.delete(db, filament_id)
return Message(message="Success!")

View File

@@ -8,6 +8,10 @@ from pydantic import BaseModel, Field
from spoolson.database import models from spoolson.database import models
class Message(BaseModel):
message: str = Field()
class Vendor(BaseModel): class Vendor(BaseModel):
id: int = Field(description="Unique internal ID of this vendor.") id: int = Field(description="Unique internal ID of this vendor.")
name: str = Field(max_length=64, description="Vendor name.") name: str = Field(max_length=64, description="Vendor name.")

View File

@@ -7,7 +7,7 @@ from starlette.responses import Response
from spoolson.exceptions import ItemNotFoundError from spoolson.exceptions import ItemNotFoundError
from . import filament, spool, vendor from . import filament, models, spool, vendor
# ruff: noqa: D103 # ruff: noqa: D103
@@ -15,6 +15,7 @@ app = FastAPI(
title="Spoolson REST API v1", title="Spoolson REST API v1",
version="1.0.0", version="1.0.0",
root_path_in_servers=False, root_path_in_servers=False,
responses={404: {"model": models.Message}},
) )

View File

@@ -5,9 +5,10 @@ from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from spoolson.database import models, vendor from spoolson.database import models, vendor
from spoolson.exceptions import ItemNotFoundError
async def create_filament( async def create(
*, *,
db: AsyncSession, db: AsyncSession,
density: float, density: float,
@@ -41,3 +42,37 @@ async def create_filament(
db.add(db_item) db.add(db_item)
await db.flush() await db.flush()
return db_item 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)