diff --git a/fooder/app.py b/fooder/app.py index aedfc5a..624976a 100644 --- a/fooder/app.py +++ b/fooder/app.py @@ -1,6 +1,17 @@ from fastapi import FastAPI from .router import router +from .settings import Settings +from fastapi.middleware.cors import CORSMiddleware app = FastAPI(title="Fooder") app.include_router(router) + + +app.add_middleware( + CORSMiddleware, + allow_origins=Settings().ALLOWED_ORIGINS, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) diff --git a/fooder/controller/product.py b/fooder/controller/product.py index da2550e..fc9df83 100644 --- a/fooder/controller/product.py +++ b/fooder/controller/product.py @@ -1,4 +1,4 @@ -from typing import AsyncIterator +from typing import AsyncIterator, Optional from fastapi import HTTPException @@ -24,9 +24,11 @@ class CreateProduct(AuthorizedController): class ListProduct(AuthorizedController): - async def call(self, limit: int, offset: int) -> AsyncIterator[Product]: + async def call( + self, limit: int, offset: int, q: Optional[str] + ) -> AsyncIterator[Product]: async with self.async_session() as session: async for product in DBProduct.list_all( - session, limit=limit, offset=offset + session, limit=limit, offset=offset, q=q ): yield Product.from_orm(product) diff --git a/fooder/domain/product.py b/fooder/domain/product.py index 0cb082b..d7973f5 100644 --- a/fooder/domain/product.py +++ b/fooder/domain/product.py @@ -1,7 +1,7 @@ from sqlalchemy.orm import Mapped from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession -from typing import AsyncIterator +from typing import AsyncIterator, Optional from .base import Base, CommonMixin @@ -24,8 +24,15 @@ class Product(Base, CommonMixin): return self.protein * 4 + self.carb * 4 + self.fat * 9 @classmethod - async def list_all(cls, session: AsyncSession, offset: int, limit: int): - query = select(cls).offset(offset).limit(limit) + async def list_all( + cls, session: AsyncSession, offset: int, limit: int, q: Optional[str] = None + ) -> AsyncIterator["Product"]: + query = select(cls) + + if q: + query = query.filter(cls.name.ilike(f"%{q.lower()}%")) + + query = query.offset(offset).limit(limit) stream = await session.stream_scalars(query.order_by(cls.id)) async for row in stream: yield row diff --git a/fooder/settings.py b/fooder/settings.py index 0d05e30..7d004bc 100644 --- a/fooder/settings.py +++ b/fooder/settings.py @@ -1,4 +1,5 @@ from pydantic import BaseSettings +from typing import List class Settings(BaseSettings): @@ -10,3 +11,5 @@ class Settings(BaseSettings): SECRET_KEY: str ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 + + ALLOWED_ORIGINS: List[str] = ["*"] diff --git a/fooder/view/product.py b/fooder/view/product.py index 9b608df..55efe07 100644 --- a/fooder/view/product.py +++ b/fooder/view/product.py @@ -1,6 +1,7 @@ from fastapi import APIRouter, Depends, Request from ..model.product import Product, CreateProductPayload, ListProductPayload from ..controller.product import ListProduct, CreateProduct +from typing import Optional router = APIRouter(tags=["product"]) @@ -12,9 +13,10 @@ async def list_product( controller: ListProduct = Depends(ListProduct), limit: int = 10, offset: int = 0, + q: Optional[str] = None, ): return ListProductPayload( - products=[p async for p in controller.call(limit=limit, offset=offset)] + products=[p async for p in controller.call(limit=limit, offset=offset, q=q)] )