Implemented find queries

This commit is contained in:
Donkie
2023-04-05 21:29:39 +02:00
parent 6a58caa2ec
commit b51d0a3183
6 changed files with 199 additions and 25 deletions

View File

@@ -1,8 +1,8 @@
"""Filament related endpoints."""
from typing import Annotated, Optional, Union
from typing import Annotated, Optional
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
@@ -19,7 +19,7 @@ router = APIRouter(
tags=["filament"],
)
# ruff: noqa: D103
# ruff: noqa: D103, B008
class FilamentParameters(BaseModel):
@@ -74,12 +74,43 @@ class FilamentUpdateParameters(FilamentParameters):
response_model_exclude_none=True,
)
async def find(
vendor_id: Optional[int] = None,
name: Optional[str] = None,
material: Optional[str] = None,
article_number: Optional[str] = None,
*,
db: Annotated[AsyncSession, Depends(get_db_session)],
vendor_name: Optional[str] = Query(
default=None,
title="Vendor Name",
description="Partial case-insensitive search term for the filament vendor name.",
),
vendor_id: Optional[int] = Query(
default=None,
title="Vendor ID",
description="Match an exact vendor ID.",
),
name: Optional[str] = Query(
default=None,
title="Filament Name",
description="Partial case-insensitive search term for the filament name.",
),
material: Optional[str] = Query(
default=None,
title="Filament Material",
description="Partial case-insensitive search term for the filament material.",
),
article_number: Optional[str] = Query(
default=None,
title="Filament Article Number",
description="Partial case-insensitive search term for the filament article number.",
),
) -> list[Filament]:
return [] # TODO: Implement
db_items = await filament.find(
db=db,
vendor_name=vendor_name,
vendor_id=vendor_id,
name=name,
material=material,
article_number=article_number,
)
return [Filament.from_db(db_item) for db_item in db_items]
@router.get(

View File

@@ -1,9 +1,9 @@
"""Spool related endpoints."""
from datetime import datetime
from typing import Annotated, Optional, Union
from typing import Annotated, Optional
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
@@ -20,7 +20,7 @@ router = APIRouter(
tags=["spool"],
)
# ruff: noqa: D103
# ruff: noqa: D103,B008
class SpoolParameters(BaseModel):
@@ -64,14 +64,55 @@ class SpoolUseParameters(BaseModel):
response_model_exclude_none=True,
)
async def find(
filament_id: Optional[int] = None,
name: Optional[str] = None,
material: Optional[str] = None,
vendor: Optional[str] = None,
location: Optional[str] = None,
lot_nr: Optional[str] = None,
*,
db: Annotated[AsyncSession, Depends(get_db_session)],
filament_name: Optional[int] = Query(
default=None,
title="Filament Name",
description="Partial case-insensitive search term for the filament name.",
),
filament_id: Optional[int] = Query(
default=None,
title="Filament ID",
description="Match an exact filament ID.",
),
filament_material: Optional[str] = Query(
default=None,
title="Filament Material",
description="Partial case-insensitive search term for the filament material.",
),
vendor_name: Optional[str] = Query(
default=None,
title="Vendor Name",
description="Partial case-insensitive search term for the filament vendor name.",
),
vendor_id: Optional[int] = Query(
default=None,
title="Vendor ID",
description="Match an exact vendor ID.",
),
location: Optional[str] = Query(
default=None,
title="Location",
description="Partial case-insensitive search term for the spool location.",
),
lot_nr: Optional[str] = Query(
default=None,
title="Lot/Batch Number",
description="Partial case-insensitive search term for the spool lot number.",
),
) -> list[Spool]:
return [] # TODO: Implement
db_items = await spool.find(
db=db,
filament_name=filament_name,
filament_id=filament_id,
filament_material=filament_material,
vendor_name=vendor_name,
vendor_id=vendor_id,
location=location,
lot_nr=lot_nr,
)
return [Spool.from_db(db_item) for db_item in db_items]
@router.get(

View File

@@ -1,8 +1,8 @@
"""Vendor related endpoints."""
from typing import Annotated, Optional, Union
from typing import Annotated, Optional
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from fastapi.exceptions import RequestValidationError
from pydantic import BaseModel, Field
from pydantic.error_wrappers import ErrorWrapper
@@ -17,7 +17,7 @@ router = APIRouter(
tags=["vendor"],
)
# ruff: noqa: D103
# ruff: noqa: D103,B008
class VendorParameters(BaseModel):
@@ -44,8 +44,19 @@ class VendorUpdateParameters(VendorParameters):
description="Get a list of vendors that matches the search query.",
response_model_exclude_none=True,
)
async def find(name: Optional[str] = None) -> list[Vendor]:
return [] # TODO: Implement
async def find(
db: Annotated[AsyncSession, Depends(get_db_session)],
name: Optional[str] = Query(
default=None,
title="Vendor Name",
description="Partial case-insensitive search term for the vendor name.",
),
) -> list[Vendor]:
db_items = await vendor.find(
db=db,
name=name,
)
return [Vendor.from_db(db_item) for db_item in db_items]
@router.get(

View File

@@ -2,8 +2,10 @@
from typing import Optional
from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import contains_eager, joinedload
from spoolman.database import models, vendor
from spoolman.exceptions import ItemDeleteError, ItemNotFoundError
@@ -47,12 +49,42 @@ async def create(
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)
filament = await db.get(
models.Filament,
filament_id,
options=[joinedload("*")], # Load all nested objects as well
)
if filament is None:
raise ItemNotFoundError(f"No filament with ID {filament_id} found.")
return filament
async def find(
*,
db: AsyncSession,
vendor_name: Optional[str] = None,
vendor_id: Optional[int] = None,
name: Optional[str] = None,
material: Optional[str] = None,
article_number: Optional[str] = None,
) -> list[models.Filament]:
"""Find a list of filament objects by search criteria."""
stmt = select(models.Filament).options(contains_eager(models.Filament.vendor)).join(models.Filament.vendor)
if vendor_name is not None:
stmt = stmt.where(models.Vendor.name.ilike(f"%{vendor_name}%"))
if vendor_id is not None:
stmt = stmt.where(models.Filament.vendor_id == vendor_id)
if name is not None:
stmt = stmt.where(models.Filament.name.ilike(f"%{name}%"))
if material is not None:
stmt = stmt.where(models.Filament.material.ilike(f"%{material}%"))
if article_number is not None:
stmt = stmt.where(models.Filament.article_number.ilike(f"%{article_number}%"))
rows = await db.execute(stmt)
return list(rows.scalars().all())
async def update(
*,
db: AsyncSession,

View File

@@ -3,7 +3,9 @@
from datetime import datetime
from typing import Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import contains_eager, joinedload
from spoolman.database import filament, models
from spoolman.exceptions import ItemCreateError, ItemNotFoundError
@@ -44,12 +46,54 @@ async def create(
async def get_by_id(db: AsyncSession, spool_id: int, with_for_update: Optional[bool] = None) -> models.Spool:
"""Get a spool object from the database by the unique ID."""
spool = await db.get(models.Spool, spool_id, with_for_update=with_for_update) # type: ignore # noqa: PGH003
spool = await db.get(
models.Spool,
spool_id,
with_for_update=with_for_update, # type: ignore # noqa: PGH003
options=[joinedload("*")], # Load all nested objects as well
)
if spool is None:
raise ItemNotFoundError(f"No spool with ID {spool_id} found.")
return spool
async def find(
*,
db: AsyncSession,
filament_name: Optional[int] = None,
filament_id: Optional[int] = None,
filament_material: Optional[str] = None,
vendor_name: Optional[str] = None,
vendor_id: Optional[int] = None,
location: Optional[str] = None,
lot_nr: Optional[str] = None,
) -> list[models.Spool]:
"""Find a list of spool objects by search criteria."""
stmt = (
select(models.Spool)
.join(models.Spool.filament)
.join(models.Filament.vendor)
.options(contains_eager(models.Spool.filament).contains_eager(models.Filament.vendor))
)
if filament_name is not None:
stmt = stmt.where(models.Filament.name.ilike(f"%{filament_name}%"))
if filament_id is not None:
stmt = stmt.where(models.Spool.filament_id == filament_id)
if filament_material is not None:
stmt = stmt.where(models.Filament.material.ilike(f"%{filament_material}%"))
if vendor_name is not None:
stmt = stmt.where(models.Vendor.name.ilike(f"%{vendor_name}%"))
if vendor_id is not None:
stmt = stmt.where(models.Filament.vendor_id == vendor_id)
if location is not None:
stmt = stmt.where(models.Spool.location.ilike(f"%{location}%"))
if lot_nr is not None:
stmt = stmt.where(models.Spool.lot_nr.ilike(f"%{lot_nr}%"))
rows = await db.execute(stmt)
return list(rows.scalars().all())
async def update(
*,
db: AsyncSession,

View File

@@ -2,6 +2,7 @@
from typing import Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from spoolman.database import models
@@ -32,6 +33,20 @@ async def get_by_id(db: AsyncSession, vendor_id: int) -> models.Vendor:
return vendor
async def find(
*,
db: AsyncSession,
name: Optional[str] = None,
) -> list[models.Vendor]:
"""Find a list of vendor objects by search criteria."""
stmt = select(models.Vendor)
if name is not None:
stmt = stmt.where(models.Vendor.name.ilike(f"%{name}%"))
rows = await db.execute(stmt)
return list(rows.scalars().all())
async def update(
*,
db: AsyncSession,