diff --git a/fastapi_book_server/app/services/book.py b/fastapi_book_server/app/services/book.py index ae1a0b7..8505beb 100644 --- a/fastapi_book_server/app/services/book.py +++ b/fastapi_book_server/app/services/book.py @@ -1,4 +1,4 @@ -from typing import TypedDict +from typing import TypedDict, Optional from app.models import Book as BookDB from app.services.common import ( @@ -46,7 +46,19 @@ SELECT id FROM filtered_books; """ +GET_OBJECTS_ID_BY_GENRE_QUERY = """ +WITH filtered_books AS ( + SELECT books.id FROM books + LEFT JOIN book_genres ON (book_genres.book = books.id) + WHERE books.is_deleted = 'f' AND book_genres.genre = :genre + AND books.lang = ANY(:langs ::text[]) +) +SELECT id FROM filtered_books; +""" + + class RandomBookServiceQuery(TypedDict): + genre: Optional[int] allowed_langs: frozenset[str] @@ -56,6 +68,19 @@ class GetRandomBookService(GetRandomService[BookDB, RandomBookServiceQuery]): SELECT_RELATED = ["authors", "translators", "annotations"] GET_OBJECTS_ID_QUERY = GET_OBJECTS_ID_QUERY + GET_OBJECTS_ID_BY_GENRE_QUERY = GET_OBJECTS_ID_BY_GENRE_QUERY + + @classmethod + async def _get_objects_from_db(cls, query: RandomBookServiceQuery) -> list[int]: + if query.get("genre") is None: + ex_query = cls.objects_id_query + params = {"langs": query["allowed_langs"]} + else: + ex_query = cls.GET_OBJECTS_ID_BY_GENRE_QUERY + params = {"langs": query["allowed_langs"], "genre": query["genre"]} + + objects = await cls.database.fetch_all(ex_query, params) + return [obj["id"] for obj in objects] class BookMeiliSearchService(MeiliSearchService): diff --git a/fastapi_book_server/app/views/book.py b/fastapi_book_server/app/views/book.py index c662685..6fb9b28 100644 --- a/fastapi_book_server/app/views/book.py +++ b/fastapi_book_server/app/views/book.py @@ -1,3 +1,5 @@ +from typing import Optional + from fastapi import APIRouter, Depends, Request, HTTPException, status from fastapi_pagination import Params @@ -42,9 +44,10 @@ async def get_books( async def get_random_book( request: Request, allowed_langs: frozenset[str] = Depends(get_allowed_langs), + genre: Optional[int] = None, ): book_id = await GetRandomBookService.get_random_id( - {"allowed_langs": allowed_langs}, request.app.state.redis + {"allowed_langs": allowed_langs, "genre": genre}, request.app.state.redis ) book = (