Files
book_library_server/fastapi_book_server/app/services/book.py

98 lines
2.7 KiB
Python

from typing import Optional, TypedDict
from app.models import Book as BookDB
from app.services.common import (
BaseFilterService,
GetRandomService,
MeiliSearchService,
TRGMSearchService,
)
GET_OBJECT_IDS_QUERY = """
SELECT ARRAY(
WITH filtered_books AS (
SELECT id, similarity(title, :query) as sml FROM books
WHERE books.title % :query AND books.is_deleted = 'f'
AND books.lang = ANY(:langs ::text[])
)
SELECT fbooks.id FROM filtered_books as fbooks
ORDER BY fbooks.sml DESC, fbooks.id
LIMIT 210
);
"""
class BookTGRMSearchService(TRGMSearchService):
MODEL_CLASS = BookDB
PREFETCH_RELATED = ["source"]
SELECT_RELATED = ["authors", "translators", "annotations"]
GET_OBJECT_IDS_QUERY = GET_OBJECT_IDS_QUERY
class BookBaseInfoFilterService(BaseFilterService):
MODEL_CLASS = BookDB
PREFETCH_RELATED = []
SELECT_RELATED = []
class BookFilterService(BaseFilterService):
MODEL_CLASS = BookDB
PREFETCH_RELATED = ["source"]
SELECT_RELATED = ["authors", "translators", "annotations"]
GET_OBJECTS_ID_QUERY = """
WITH filtered_books AS (
SELECT id FROM books
WHERE books.is_deleted = 'f' AND books.lang = ANY(:langs ::text[])
)
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]
class GetRandomBookService(GetRandomService[BookDB, RandomBookServiceQuery]):
MODEL_CLASS = BookDB # type: ignore
PREFETCH_RELATED = ["source"]
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):
MODEL_CLASS = BookDB
PREFETCH_RELATED = ["source"]
SELECT_RELATED = ["authors", "translators", "annotations"]
MS_INDEX_NAME = "books"
MS_INDEX_LANG_KEY = "lang"