diff --git a/crud.py b/crud.py new file mode 100644 index 00000000..969c93c9 --- /dev/null +++ b/crud.py @@ -0,0 +1,34 @@ +from sqlalchemy.orm import Session +from schemas import AuthorCreate, BookCreate +import models + + +def get_author(db: Session, author_id: int): + return db.query(models.Author).filter(models.Author.id == author_id).first() + + +def get_authors(db: Session, skip: int, limit: int): + return db.query(models.Author).offset(skip).limit(limit).all() + + +def create_author(db: Session, author: AuthorCreate): + db_author = models.Author(**author.model_dump()) + db.add(db_author) + db.commit() + db.refresh(db_author) + return db_author + + +def get_books(db: Session, skip: int, limit: int, author_id: int = None): + query = db.query(models.Book) + if author_id: + query = query.filter(models.Book.author_id == author_id) + return query.offset(skip).limit(limit).all() + + +def create_book(db: Session, book: BookCreate): + db_book = models.Book(**book.model_dump()) + db.add(db_book) + db.commit() + db.refresh(db_book) + return db_book \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 00000000..3682656f --- /dev/null +++ b/database.py @@ -0,0 +1,12 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import declarative_base +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = "sqlite:///./library.db" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} +) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() diff --git a/main.py b/main.py new file mode 100644 index 00000000..3b80ad72 --- /dev/null +++ b/main.py @@ -0,0 +1,48 @@ +from sqlalchemy.orm import Session +import crud +from database import engine, SessionLocal +from models import Base +from schemas import AuthorCreate, AuthorResponse, BookResponse, BookCreate +from fastapi import FastAPI, Depends, HTTPException +from typing import List + + +Base.metadata.create_all(bind=engine) + +app = FastAPI() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@app.post("/authors", response_model=AuthorResponse) +def create_author(author: AuthorCreate, db: Session = Depends(get_db)): + return crud.create_author(db=db, author=author) + + +@app.get("/authors", response_model=List[AuthorResponse]) +def read_authors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + return crud.get_authors(db, skip=skip, limit=limit) + + +@app.get("/authors/{author_id}", response_model=AuthorResponse) +def read_author(author_id: int, db: Session = Depends(get_db)): + author = crud.get_author(db, author_id=author_id) + if not author: + raise HTTPException(status_code=404, detail="Author not found") + return author + +@app.post("/authors/{author_id}/books", response_model=BookResponse) +def create_book(author_id: int, book: BookCreate, db: Session = Depends(get_db)): + author = crud.get_author(db, author_id=author_id) + if not author: + raise HTTPException(status_code=404, detail="Author not found") + return crud.create_book(db=db, book=book) + + +@app.get("/books", response_model=List[BookResponse]) +def read_books(skip: int = 0, limit: int = 100, author_id: int = None, db: Session = Depends(get_db)): + return crud.get_books(db, skip=skip, limit=limit, author_id=author_id) diff --git a/models.py b/models.py new file mode 100644 index 00000000..84b35b97 --- /dev/null +++ b/models.py @@ -0,0 +1,24 @@ +from datetime import date +from sqlalchemy import String, ForeignKey +from sqlalchemy.orm import Mapped, mapped_column, relationship +from database import Base + + +class Author(Base): + __tablename__ = "author" + + id: Mapped[int] = mapped_column(primary_key=True, index=True) + name: Mapped[str] = mapped_column(String(255), nullable=False, unique=True) + bio: Mapped[str] = mapped_column(String(511), nullable=False) + books: Mapped[list["Book"]] = relationship(back_populates="author") + + +class Book(Base): + __tablename__ = "book" + + id: Mapped[int] = mapped_column(primary_key=True, index=True) + title: Mapped[str] = mapped_column(String(255), nullable=False,) + summary: Mapped[str] + publication_date: Mapped[date] + author_id: Mapped[int] = mapped_column(ForeignKey("author.id")) + author : Mapped["Author"] = relationship(back_populates="books") diff --git a/schemas.py b/schemas.py new file mode 100644 index 00000000..7678fc66 --- /dev/null +++ b/schemas.py @@ -0,0 +1,33 @@ +from pydantic import BaseModel, ConfigDict +from datetime import date + + +class AuthorBase(BaseModel): + name: str + bio: str + + +class AuthorCreate(AuthorBase): + pass + + +class AuthorResponse(AuthorBase): + id: int + books: list["BookResponse"] + model_config = ConfigDict(from_attributes=True) + + +class BookBase(BaseModel): + title: str + summary: str + publication_date: date + author_id: int + + +class BookCreate(BookBase): + pass + + +class BookResponse(BookBase): + id: int + model_config = ConfigDict(from_attributes=True)