mirror of
https://github.com/flibusta-apps/book_library_server.git
synced 2025-12-06 15:15:36 +01:00
79 lines
2.2 KiB
Python
79 lines
2.2 KiB
Python
from typing import Union
|
|
|
|
from fastapi import HTTPException, status
|
|
|
|
from app.models import Book as BookDB, Author as AuthorDB
|
|
|
|
from app.services.common import TRGMSearchService
|
|
from app.serializers.book import CreateBook, CreateRemoteBook
|
|
|
|
|
|
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'
|
|
)
|
|
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", "authors", "translators", "annotations"]
|
|
GET_OBJECT_IDS_QUERY = GET_OBJECT_IDS_QUERY
|
|
|
|
|
|
class BookCreator:
|
|
@classmethod
|
|
def _raise_bad_request(cls):
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND)
|
|
|
|
@classmethod
|
|
async def _create_book(cls, data: CreateBook) -> BookDB:
|
|
data_dict = data.dict()
|
|
|
|
author_ids = data_dict.pop("authors", [])
|
|
authors = await AuthorDB.objects.filter(id__in=author_ids).all()
|
|
|
|
if len(author_ids) != len(authors):
|
|
cls._raise_bad_request()
|
|
|
|
book = await BookDB.objects.create(
|
|
**data_dict
|
|
)
|
|
|
|
for author in authors:
|
|
await book.authors.add(author)
|
|
|
|
return book
|
|
|
|
@classmethod
|
|
async def _create_remote_book(cls, data: CreateRemoteBook) -> BookDB:
|
|
data_dict = data.dict()
|
|
|
|
author_ids = data_dict.pop("remote_authors", [])
|
|
authors = await AuthorDB.objects.filter(source__id=data.source, remote_id__in=author_ids).all()
|
|
|
|
if len(author_ids) != len(authors):
|
|
cls._raise_bad_request()
|
|
|
|
book = await BookDB.objects.create(
|
|
**data_dict
|
|
)
|
|
|
|
for author in authors:
|
|
await book.authors.add(author)
|
|
|
|
return book
|
|
|
|
@classmethod
|
|
async def create(cls, data: Union[CreateBook, CreateRemoteBook]) -> BookDB:
|
|
if isinstance(data, CreateBook):
|
|
return await cls._create_book(data)
|
|
if isinstance(data, CreateRemoteBook):
|
|
return await cls._create_remote_book(data)
|