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: update filter library #121

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
22 changes: 19 additions & 3 deletions app/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import OAuth2PasswordRequestForm
from fastapi.templating import Jinja2Templates
from fastapi_filter import FilterDepends
from fastapi_filters import FilterValues, SortingValues, create_filters, create_sorting
from fastapi_filters.ext.sqlalchemy import apply_filters_and_sorting, apply_sorting
from fastapi_pagination import Page, add_pagination
from fastapi_pagination.ext.sqlalchemy import paginate
from openfoodfacts.utils import get_logger
from sqlalchemy import select
from sqlalchemy.orm import Session

from app import crud, schemas, tasks
from app.auth import OAuth2PasswordBearerOrAuthCookie
from app.config import settings
from app.db import session
from app.enums import ProofTypeEnum
from app.models import Product
from app.utils import init_sentry

logger = get_logger(level=settings.log_level.to_int())
Expand Down Expand Up @@ -167,10 +170,13 @@ def authentication(

@app.get("/api/v1/prices", response_model=Page[schemas.PriceFull], tags=["Prices"])
def get_price(
filters: schemas.PriceFilter = FilterDepends(schemas.PriceFilter),
db: Session = Depends(get_db),
filters: FilterValues = Depends(create_filters(**schemas.PRICE_FILTERS)),
sorting: SortingValues = Depends(create_sorting("date", "price")),
):
return paginate(db, crud.get_prices_query(filters=filters))
return paginate(
db, apply_filters_and_sorting(crud.get_prices_query(), filters, sorting)
)


@app.post(
Expand Down Expand Up @@ -267,6 +273,16 @@ def get_product_by_code(product_code: str, db: Session = Depends(get_db)):
return db_product


@app.get(
"/api/v1/products", response_model=Page[schemas.ProductBase], tags=["Products"]
)
def get_products(
db: Session = Depends(get_db),
sorting: SortingValues = Depends(create_sorting(("unique_scans_n", "smaller"))),
):
return paginate(db, apply_sorting(select(Product), sorting))


@app.get(
"/api/v1/products/{product_id}",
response_model=schemas.ProductBase,
Expand Down
12 changes: 3 additions & 9 deletions app/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
LocationCreate,
PriceBase,
PriceCreate,
PriceFilter,
ProductBase,
ProductCreate,
UserBase,
Expand Down Expand Up @@ -105,23 +104,18 @@ def update_product(db: Session, product: ProductBase, update_dict: dict):

# Prices
# ------------------------------------------------------------------------------
def get_prices_query(
with_join_product=True, with_join_location=True, filters: PriceFilter | None = None
):
def get_prices_query(with_join_product=True, with_join_location=True):
"""Useful for pagination."""
query = select(Price)
if with_join_product:
query = query.options(joinedload(Price.product))
if with_join_location:
query = query.options(joinedload(Price.location))
if filters:
query = filters.filter(query)
query = filters.sort(query)
return query


def get_prices(db: Session, filters: PriceFilter | None = None):
return db.execute(get_prices_query(filters=filters)).all()
def get_prices(db: Session):
return db.execute(get_prices_query()).all()


def create_price(db: Session, price: PriceCreate, user: UserBase):
Expand Down
62 changes: 33 additions & 29 deletions app/schemas.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import datetime
from typing import Optional

from fastapi_filter.contrib.sqlalchemy import Filter
from fastapi_filters import FilterField, FilterOperator
from openfoodfacts import Flavor
from openfoodfacts.taxonomy import get_taxonomy
from pydantic import (
Expand All @@ -14,7 +13,6 @@
)

from app.enums import CurrencyEnum, LocationOSMEnum, ProofTypeEnum
from app.models import Price


class UserBase(BaseModel):
Expand Down Expand Up @@ -277,29 +275,35 @@ class ProofBase(BaseModel):
created: datetime.datetime


class PriceFilter(Filter):
product_code: Optional[str] | None = None
product_id: Optional[int] | None = None
category_tag: Optional[str] | None = None
labels_tags__like: Optional[str] | None = None
origins_tags__like: Optional[str] | None = None
location_osm_id: Optional[int] | None = None
location_osm_type: Optional[LocationOSMEnum] | None = None
location_id: Optional[int] | None = None
price: Optional[int] | None = None
price__gt: Optional[int] | None = None
price__gte: Optional[int] | None = None
price__lt: Optional[int] | None = None
price__lte: Optional[int] | None = None
currency: Optional[str] | None = None
date: Optional[str] | None = None
date__gt: Optional[str] | None = None
date__gte: Optional[str] | None = None
date__lt: Optional[str] | None = None
date__lte: Optional[str] | None = None
owner: Optional[str] | None = None

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

class Constants(Filter.Constants):
model = Price
PRICE_FILTERS = {
"product_code": FilterField(str, operators={FilterOperator.eq}),
"product_id": FilterField(int, operators={FilterOperator.eq}),
"category_tag": FilterField(str, operators={FilterOperator.eq}),
"labels_tags": FilterField(list[str], operators={FilterOperator.like}),
"origins_tags": FilterField(list[str], operators={FilterOperator.like}),
"location_osm_id": FilterField(int, operators={FilterOperator.eq}),
"location_osm_type": FilterField(LocationOSMEnum, operators={FilterOperator.eq}),
"location_id": FilterField(int, operators={FilterOperator.eq}),
"price": FilterField(
float,
operators={
FilterOperator.eq,
FilterOperator.gt,
FilterOperator.lt,
FilterOperator.ge,
FilterOperator.le,
},
),
"currency": FilterField(str, operators={FilterOperator.eq}),
"date": FilterField(
datetime.date,
operators={
FilterOperator.eq,
FilterOperator.gt,
FilterOperator.lt,
FilterOperator.ge,
FilterOperator.le,
},
),
"owner": FilterField(str, operators={FilterOperator.eq}),
}
Loading
Loading