from datetime import date from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import text from app.database import get_db router = APIRouter(prefix="/books", tags=["Books"]) @router.get("/") async def get_all_books(db: AsyncSession = Depends(get_db)): result = await db.execute(text(""" SELECT b.id, b.title, b.genre, b.published, a.name AS author FROM books b JOIN authors a ON a.id = b.author_id ORDER BY b.title """)) return result.mappings().all() @router.get("/{book_id}") async def get_book(book_id: int, db: AsyncSession = Depends(get_db)): result = await db.execute( text(""" SELECT b.*, a.name AS author_name FROM books b JOIN authors a ON a.id = b.author_id WHERE b.id = :id """), {"id": book_id} ) book = result.mappings().one_or_none() if not book: raise HTTPException(status_code=404, detail="Book not found") return book @router.post("/", status_code=201) async def create_book( title: str, author_id: int, genre: str = None, published: date = None, description: str = None, db: AsyncSession = Depends(get_db) ): # Check author exists result = await db.execute( text("SELECT id FROM authors WHERE id = :id"), {"id": author_id} ) if not result.one_or_none(): raise HTTPException(status_code=404, detail="Author not found") await db.execute( text(""" INSERT INTO books (title, author_id, genre, published, description) VALUES (:title, :author_id, :genre, :published, :description) """), {"title": title, "author_id": author_id, "genre": genre, "published": published, "description": description} ) await db.commit() return {"message": f"Book '{title}' created"} @router.put("/{book_id}") async def update_book( book_id: int, title: str = None, genre: str = None, description: str = None, db: AsyncSession = Depends(get_db) ): result = await db.execute( text("SELECT id FROM books WHERE id = :id"), {"id": book_id} ) if not result.one_or_none(): raise HTTPException(status_code=404, detail="Book not found") await db.execute( text(""" UPDATE books SET title = COALESCE(:title, title), genre = COALESCE(:genre, genre), description = COALESCE(:description, description) WHERE id = :id """), {"id": book_id, "title": title, "genre": genre, "description": description} ) await db.commit() return {"message": "Book updated"} @router.delete("/{book_id}", status_code=204) async def delete_book(book_id: int, db: AsyncSession = Depends(get_db)): result = await db.execute( text("SELECT id FROM books WHERE id = :id"), {"id": book_id} ) if not result.one_or_none(): raise HTTPException(status_code=404, detail="Book not found") await db.execute( text("DELETE FROM books WHERE id = :id"), {"id": book_id} ) await db.commit()