API find nested filters now specified using period

Previously you used underscore, like vendor_name. This made fields like filament_article_number have ambiguous underscores.
This commit is contained in:
Donkie
2023-09-04 21:11:10 +02:00
parent 3bba0b1dce
commit 826fde6967
4 changed files with 169 additions and 56 deletions

View File

@@ -115,12 +115,28 @@ class FilamentUpdateParameters(FilamentParameters):
async def find( async def find(
*, *,
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
vendor_name_old: Optional[str] = Query(
alias="vendor_name",
default=None,
title="Vendor Name",
description="Partial case-insensitive search term for the filament vendor name.",
deprecated=True,
),
vendor_id_old: Optional[int] = Query(
alias="vendor_id",
default=None,
title="Vendor ID",
description="Match an exact vendor ID.",
deprecated=True,
),
vendor_name: Optional[str] = Query( vendor_name: Optional[str] = Query(
alias="vendor.name",
default=None, default=None,
title="Vendor Name", title="Vendor Name",
description="Partial case-insensitive search term for the filament vendor name.", description="Partial case-insensitive search term for the filament vendor name.",
), ),
vendor_id: Optional[int] = Query( vendor_id: Optional[int] = Query(
alias="vendor.id",
default=None, default=None,
title="Vendor ID", title="Vendor ID",
description="Match an exact vendor ID.", description="Match an exact vendor ID.",
@@ -167,8 +183,8 @@ async def find(
db_items, total_count = await filament.find( db_items, total_count = await filament.find(
db=db, db=db,
vendor_name=vendor_name, vendor_name=vendor_name if vendor_name is not None else vendor_name_old,
vendor_id=vendor_id, vendor_id=vendor_id if vendor_id is not None else vendor_id_old,
name=name, name=name,
material=material, material=material,
article_number=article_number, article_number=article_number,

View File

@@ -73,27 +73,67 @@ class SpoolUseParameters(BaseModel):
async def find( async def find(
*, *,
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
filament_name_old: Optional[str] = Query(
alias="filament_name",
default=None,
title="Filament Name",
description="Partial case-insensitive search term for the filament name.",
deprecated=True,
),
filament_id_old: Optional[int] = Query(
alias="filament_id",
default=None,
title="Filament ID",
description="Match an exact filament ID.",
deprecated=True,
),
filament_material_old: Optional[str] = Query(
alias="filament_material",
default=None,
title="Filament Material",
description="Partial case-insensitive search term for the filament material.",
deprecated=True,
),
vendor_name_old: Optional[str] = Query(
alias="vendor_name",
default=None,
title="Vendor Name",
description="Partial case-insensitive search term for the filament vendor name.",
deprecated=True,
),
vendor_id_old: Optional[int] = Query(
alias="vendor_id",
default=None,
title="Vendor ID",
description="Match an exact vendor ID.",
deprecated=True,
),
filament_name: Optional[str] = Query( filament_name: Optional[str] = Query(
alias="filament.name",
default=None, default=None,
title="Filament Name", title="Filament Name",
description="Partial case-insensitive search term for the filament name.", description="Partial case-insensitive search term for the filament name.",
), ),
filament_id: Optional[int] = Query( filament_id: Optional[int] = Query(
alias="filament.id",
default=None, default=None,
title="Filament ID", title="Filament ID",
description="Match an exact filament ID.", description="Match an exact filament ID.",
), ),
filament_material: Optional[str] = Query( filament_material: Optional[str] = Query(
alias="filament.material",
default=None, default=None,
title="Filament Material", title="Filament Material",
description="Partial case-insensitive search term for the filament material.", description="Partial case-insensitive search term for the filament material.",
), ),
vendor_name: Optional[str] = Query( vendor_name: Optional[str] = Query(
alias="vendor.name",
default=None, default=None,
title="Vendor Name", title="Vendor Name",
description="Partial case-insensitive search term for the filament vendor name.", description="Partial case-insensitive search term for the filament vendor name.",
), ),
vendor_id: Optional[int] = Query( vendor_id: Optional[int] = Query(
alias="vendor.id",
default=None, default=None,
title="Vendor ID", title="Vendor ID",
description="Match an exact vendor ID.", description="Match an exact vendor ID.",
@@ -119,7 +159,7 @@ async def find(
description=( description=(
'Sort the results by the given field. Should be a comma-separate string with "field:direction" items.' 'Sort the results by the given field. Should be a comma-separate string with "field:direction" items.'
), ),
example="filament.name:asc,location:desc", example="filament.name:asc,vendor.id:asc,location:desc",
), ),
limit: Optional[int] = Query( limit: Optional[int] = Query(
default=None, default=None,
@@ -140,11 +180,11 @@ async def find(
db_items, total_count = await spool.find( db_items, total_count = await spool.find(
db=db, db=db,
filament_name=filament_name, filament_name=filament_name if filament_name is not None else filament_name_old,
filament_id=filament_id, filament_id=filament_id if filament_id is not None else filament_id_old,
filament_material=filament_material, filament_material=filament_material if filament_material is not None else filament_material_old,
vendor_name=vendor_name, vendor_name=vendor_name if vendor_name is not None else vendor_name_old,
vendor_id=vendor_id, vendor_id=vendor_id if vendor_id is not None else vendor_id_old,
location=location, location=location,
lot_nr=lot_nr, lot_nr=lot_nr,
allow_archived=allow_archived, allow_archived=allow_archived,

View File

@@ -1,15 +1,24 @@
"""Integration tests for the Filament API endpoint.""" """Integration tests for the Filament API endpoint."""
from collections.abc import Iterable
from dataclasses import dataclass
from typing import Any from typing import Any
import httpx import httpx
import pytest
URL = "http://spoolman:8000" URL = "http://spoolman:8000"
def test_find_filaments(random_vendor: dict[str, Any]): @dataclass
"""Test finding filaments from the database.""" class Fixture:
# Setup filaments: list[dict[str, Any]]
filaments_by_id: dict[str, dict[str, Any]]
@pytest.fixture()
def filaments(random_vendor: dict[str, Any]) -> Iterable[Fixture]:
"""Add some filaments to the database."""
result = httpx.post( result = httpx.post(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
json={ json={
@@ -46,24 +55,57 @@ def test_find_filaments(random_vendor: dict[str, Any]):
result.raise_for_status() result.raise_for_status()
filament_2 = result.json() filament_2 = result.json()
result = httpx.post(
f"{URL}/api/v1/filament",
json={
"name": "Filament Y",
"material": "PETG",
"price": 200,
"density": 1.25,
"diameter": 1.75,
"weight": 1000,
"spool_weight": 250,
"article_number": "abc",
"comment": "abcdefghåäö",
},
)
result.raise_for_status()
filament_3 = result.json()
added_filaments_by_id = { added_filaments_by_id = {
filament_1["id"]: filament_1, filament_1["id"]: filament_1,
filament_2["id"]: filament_2, filament_2["id"]: filament_2,
filament_3["id"]: filament_3,
} }
# Execute - find all filaments yield Fixture(
filaments=[filament_1, filament_2, filament_3],
filaments_by_id=added_filaments_by_id,
)
httpx.delete(f"{URL}/api/v1/filament/{filament_1['id']}").raise_for_status()
httpx.delete(f"{URL}/api/v1/filament/{filament_2['id']}").raise_for_status()
httpx.delete(f"{URL}/api/v1/filament/{filament_3['id']}").raise_for_status()
def test_find_all_filaments(filaments: Fixture):
"""Test finding filaments from the database."""
# Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
) )
result.raise_for_status() result.raise_for_status()
# Verify # Verify
filaments = result.json() filaments_result = result.json()
assert len(filaments) == 2 assert len(filaments_result) == 3
for filament in filaments: for filament in filaments_result:
assert filament == added_filaments_by_id[filament["id"]] assert filament == filaments.filaments_by_id[filament["id"]]
# Execute - find filaments by name
def test_find_filaments_by_name(filaments: Fixture):
"""Test finding filaments from the database."""
# Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
params={"name": "Filament X"}, params={"name": "Filament X"},
@@ -71,11 +113,14 @@ def test_find_filaments(random_vendor: dict[str, Any]):
result.raise_for_status() result.raise_for_status()
# Verify # Verify
filaments = result.json() filaments_result = result.json()
assert len(filaments) == 1 assert len(filaments_result) == 1
assert filaments[0] == added_filaments_by_id[filament_1["id"]] assert filaments_result[0] == filaments.filaments[0]
# Execute - find filaments by material
def test_find_filaments_by_material(filaments: Fixture):
"""Test finding filaments from the database."""
# Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
params={"material": "abs"}, params={"material": "abs"},
@@ -83,37 +128,48 @@ def test_find_filaments(random_vendor: dict[str, Any]):
result.raise_for_status() result.raise_for_status()
# Verify # Verify
filaments = result.json() filaments_result = result.json()
assert len(filaments) == 1 assert len(filaments_result) == 1
assert filaments[0] == added_filaments_by_id[filament_2["id"]] assert filaments_result[0] == filaments.filaments[1]
# Execute - find filaments by vendor id
@pytest.mark.parametrize("field_name", ["vendor_id", "vendor.id"])
def test_find_filaments_by_vendor_id(filaments: Fixture, field_name: str):
"""Test finding filaments from the database."""
# Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
params={"vendor_id": random_vendor["id"]}, params={field_name: filaments.filaments[0]["vendor"]["id"]},
) )
result.raise_for_status() result.raise_for_status()
# Verify # Verify
filaments = result.json() filaments_result = result.json()
assert len(filaments) == 2 assert len(filaments_result) == 2
for filament in filaments: for filament in filaments_result:
assert filament == added_filaments_by_id[filament["id"]] assert filament == filaments.filaments_by_id[filament["id"]]
# Execute - find filaments by vendor name
@pytest.mark.parametrize("field_name", ["vendor_name", "vendor.name"])
def test_find_filaments_by_vendor_name(filaments: Fixture, field_name: str):
"""Test finding filaments from the database."""
# Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
params={"vendor_name": random_vendor["name"]}, params={field_name: filaments.filaments[0]["vendor"]["name"]},
) )
result.raise_for_status() result.raise_for_status()
# Verify # Verify
filaments = result.json() filaments_result = result.json()
assert len(filaments) == 2 assert len(filaments_result) == 2
for filament in filaments: for filament in filaments_result:
assert filament == added_filaments_by_id[filament["id"]] assert filament == filaments.filaments_by_id[filament["id"]]
# Execute - find filaments by article number
def test_find_filaments_by_article_number(filaments: Fixture):
"""Test finding filaments from the database."""
# Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/filament", f"{URL}/api/v1/filament",
params={"article_number": "321"}, params={"article_number": "321"},
@@ -121,10 +177,6 @@ def test_find_filaments(random_vendor: dict[str, Any]):
result.raise_for_status() result.raise_for_status()
# Verify # Verify
filaments = result.json() filaments_result = result.json()
assert len(filaments) == 1 assert len(filaments_result) == 1
assert filaments[0] == added_filaments_by_id[filament_2["id"]] assert filaments_result[0] == filaments.filaments[1]
# Clean up
httpx.delete(f"{URL}/api/v1/filament/{filament_1['id']}").raise_for_status()
httpx.delete(f"{URL}/api/v1/filament/{filament_2['id']}").raise_for_status()

View File

@@ -1,6 +1,6 @@
"""Integration tests for the Spool API endpoint.""" """Integration tests for the Spool API endpoint."""
from collections.abc import Iterator from collections.abc import Iterable
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any from typing import Any
@@ -18,7 +18,7 @@ class Fixture:
@pytest.fixture() @pytest.fixture()
def spools(random_filament: dict[str, Any]) -> Iterator[Fixture]: def spools(random_filament: dict[str, Any]) -> Iterable[Fixture]:
"""Add some spools to the database.""" """Add some spools to the database."""
result = httpx.post( result = httpx.post(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
@@ -99,12 +99,13 @@ def test_find_all_spools_including_archived(spools: Fixture):
assert spool == spools.spools_by_id[spool["id"]] assert spool == spools.spools_by_id[spool["id"]]
def test_find_spools_by_filament_name(spools: Fixture): @pytest.mark.parametrize("field_name", ["filament_name", "filament.name"])
def test_find_spools_by_filament_name(spools: Fixture, field_name: str):
"""Test finding spools by filament name.""" """Test finding spools by filament name."""
# Execute # Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
params={"filament_name": spools.filament["name"]}, params={field_name: spools.filament["name"]},
) )
result.raise_for_status() result.raise_for_status()
@@ -115,12 +116,13 @@ def test_find_spools_by_filament_name(spools: Fixture):
assert spool == spools.spools_by_id[spool["id"]] assert spool == spools.spools_by_id[spool["id"]]
def test_find_spools_by_filament_id(spools: Fixture): @pytest.mark.parametrize("field_name", ["filament_id", "filament.id"])
def test_find_spools_by_filament_id(spools: Fixture, field_name: str):
"""Test finding spools by filament id.""" """Test finding spools by filament id."""
# Execute # Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
params={"filament_id": spools.filament["id"]}, params={field_name: spools.filament["id"]},
) )
result.raise_for_status() result.raise_for_status()
@@ -131,12 +133,13 @@ def test_find_spools_by_filament_id(spools: Fixture):
assert spool == spools.spools_by_id[spool["id"]] assert spool == spools.spools_by_id[spool["id"]]
def test_find_spools_by_filament_material(spools: Fixture): @pytest.mark.parametrize("field_name", ["filament_material", "filament.material"])
def test_find_spools_by_filament_material(spools: Fixture, field_name: str):
"""Test finding spools by filament material.""" """Test finding spools by filament material."""
# Execute # Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
params={"filament_material": spools.filament["material"]}, params={field_name: spools.filament["material"]},
) )
result.raise_for_status() result.raise_for_status()
@@ -147,12 +150,13 @@ def test_find_spools_by_filament_material(spools: Fixture):
assert spool == spools.spools_by_id[spool["id"]] assert spool == spools.spools_by_id[spool["id"]]
def test_find_spools_by_filament_vendor_name(spools: Fixture): @pytest.mark.parametrize("field_name", ["vendor_name", "vendor.name"])
def test_find_spools_by_filament_vendor_name(spools: Fixture, field_name: str):
"""Test finding spools by filament vendor name.""" """Test finding spools by filament vendor name."""
# Execute # Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
params={"vendor_name": spools.filament["vendor"]["name"]}, params={field_name: spools.filament["vendor"]["name"]},
) )
result.raise_for_status() result.raise_for_status()
@@ -163,12 +167,13 @@ def test_find_spools_by_filament_vendor_name(spools: Fixture):
assert spool == spools.spools_by_id[spool["id"]] assert spool == spools.spools_by_id[spool["id"]]
def test_find_spools_by_filament_vendor_id(spools: Fixture): @pytest.mark.parametrize("field_name", ["vendor_id", "vendor.id"])
def test_find_spools_by_filament_vendor_id(spools: Fixture, field_name: str):
"""Test finding spools by filament vendor id.""" """Test finding spools by filament vendor id."""
# Execute # Execute
result = httpx.get( result = httpx.get(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
params={"vendor_id": spools.filament["vendor"]["id"]}, params={field_name: spools.filament["vendor"]["id"]},
) )
result.raise_for_status() result.raise_for_status()