Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: filter prices by product fields (source, category) (WIP) #272

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from fastapi import UploadFile
from fastapi_filter.contrib.sqlalchemy import Filter
from sqlalchemy import Row, Select, delete, select
from sqlalchemy.orm import Session, joinedload
from sqlalchemy.orm import Session, joinedload, outerjoin
from sqlalchemy.sql import func

from app import config
Expand Down Expand Up @@ -278,7 +278,7 @@ def get_prices_query(
"""Useful for pagination."""
query = select(Price)
if with_join_product:
query = query.options(joinedload(Price.product))
query = query.options(outerjoin(Price.product))
if with_join_location:
query = query.options(joinedload(Price.location))
if with_join_proof:
Expand Down
16 changes: 16 additions & 0 deletions app/schemas.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
from typing import Annotated, Optional

from fastapi_filter import FilterDepends, with_prefix
from fastapi_filter.contrib.sqlalchemy import Filter
from openfoodfacts import Flavor
from openfoodfacts.taxonomy import get_taxonomy
Expand Down Expand Up @@ -428,6 +429,16 @@ class PriceFullWithRelations(PriceFull):

# Filters
# ------------------------------------------------------------------------------
class PriceProductFilter(Filter):
source: Optional[Flavor] | None = None
# categories_tags__contains: Optional[str] | None = None
# labels_tags__contains: Optional[str] | None = None
# brands__like: Optional[str] | None = None

class Constants(Filter.Constants):
model = Product


class PriceFilter(Filter):
product_code: Optional[str] | None = None
product_id: Optional[int] | None = None
Expand All @@ -454,6 +465,11 @@ class PriceFilter(Filter):
created__gte: Optional[str] | None = None
created__lte: Optional[str] | None = None

product: Optional[PriceProductFilter] = FilterDepends(
with_prefix("product", PriceProductFilter)
)
product__categories_tags__contains: Optional[str] | None = None

order_by: Optional[list[str]] | None = None

class Constants(Filter.Constants):
Expand Down
37 changes: 34 additions & 3 deletions tests/integration/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ def override_get_db():
created=datetime.datetime.now(),
updated=datetime.datetime.now(),
)
PRODUCT_4 = ProductFull(
id=4,
code="8710447381472",
source="obf",
product_name="Lessive au savon de Marseille",
product_quantity=4200,
product_quantity_unit="ml",
categories_tags=[],
brands="",
brands_tags=[],
labels_tags=[],
nutriscore_grade=None,
ecoscore_grade=None,
nova_group=None,
unique_scans_n=0,
created=datetime.datetime.now(),
updated=datetime.datetime.now(),
)
LOCATION_1 = LocationFull(
id=1,
osm_id=652825274,
Expand Down Expand Up @@ -580,7 +598,11 @@ def test_get_prices_with_proofs(
assert response.json()["items"][2]["proof"] is None


def test_get_prices_filters(db_session, user_session: SessionModel, clean_prices):
def test_get_prices_filters(
db_session, user_session: SessionModel, clean_products, clean_prices
):
crud.create_product(db_session, PRODUCT_1)
crud.create_product(db_session, PRODUCT_4)
crud.create_price(db_session, PRICE_1, user_session.user)
crud.create_price(
db_session,
Expand Down Expand Up @@ -608,8 +630,13 @@ def test_get_prices_filters(db_session, user_session: SessionModel, clean_prices
),
user_session.user,
)
crud.create_price(
db_session,
PRICE_1.model_copy(update={"product_code": PRODUCT_4.code}),
user_session.user,
)

assert len(crud.get_prices(db_session)) == 4
assert len(crud.get_prices(db_session)) == 5

# 3 prices with the same product_code
response = client.get(f"/api/v1/prices?product_code={PRICE_1.product_code}")
Expand All @@ -630,7 +657,11 @@ def test_get_prices_filters(db_session, user_session: SessionModel, clean_prices
# 2 prices with date = 2023-10-31
response = client.get(f"/api/v1/prices?date={PRICE_1.date}")
assert response.status_code == 200
assert len(response.json()["items"]) == 3
assert len(response.json()["items"]) == 4
# filter by product relationship
response = client.get("/api/v1/prices?product__source=obf")
assert response.status_code == 200
assert len(response.json()["items"]) == 1


def test_get_prices_orders(db_session, user_session: SessionModel, clean_prices):
Expand Down
Loading