diff --git a/crud.py b/crud.py new file mode 100644 index 00000000..e75c9d79 --- /dev/null +++ b/crud.py @@ -0,0 +1,45 @@ +from sqlalchemy import select +from sqlalchemy.orm import Session + +import models +import schemas + + +def get_authors(db: Session) -> list[models.DBAuthor]: + return db.scalars(select(models.DBAuthor)).all() + + +def get_author_by_id(db: Session, author_id: int) -> models.DBAuthor | None: + return db.scalar(select(models.DBAuthor).where(models.DBAuthor.id == author_id)) + +def create_author(db: Session, data: schemas.AuthorCreate) -> models.DBAuthor: + new_author = models.DBAuthor( + name=data.name, + bio=data.bio + ) + db.add(new_author) + db.commit() + db.refresh(new_author) + return new_author + + +def get_books(db: Session) -> list[models.DBBook]: + return db.scalars(select(models.DBBook)).all() + + +def get_book_by_id(db: Session, book_id: int) -> models.DBBook | None: + return db.scalar(select(models.DBBook).where(models.DBBook.id == book_id)) + + +def create_book(db: Session, data: schemas.BookCreate, author_id: int) -> models.DBBook: + new_book = models.DBBook( + title=data.title, + summary=data.summary, + publication_date=data.publication_date, + author_id=author_id + ) + db.add(new_book) + db.commit() + db.refresh(new_book) + + return new_book \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 00000000..b9726285 --- /dev/null +++ b/database.py @@ -0,0 +1,15 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = "sqlite:///./library.db" + +engine = create_engine( + url=SQLALCHEMY_DATABASE_URL, + connect_args={"check_same_thread": False} +) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +class Base(DeclarativeBase): + pass diff --git a/library.db b/library.db new file mode 100644 index 00000000..2ad2744a Binary files /dev/null and b/library.db differ diff --git a/main.py b/main.py new file mode 100644 index 00000000..1768ac32 --- /dev/null +++ b/main.py @@ -0,0 +1,69 @@ +from fastapi import FastAPI, Depends, HTTPException +from sqlalchemy.orm import Session + +import models +import schemas +import crud +from database import SessionLocal, engine + + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +@app.get("/") +def root(): + return "Hello World" + + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@app.post("/create_author", response_model=schemas.AuthorBase) +def create_author(data: schemas.AuthorCreate, db: Session = Depends(get_db)): + return crud.create_author(db, data) + +@app.get("/authors", response_model=list[schemas.AuthorRead]) +def get_authors(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + authors = crud.get_authors(db) + return authors[skip: skip + limit] + +@app.get("/author/{author_id}", response_model=schemas.AuthorRead) +def get_author_by_id(author_id: int, db: Session = Depends(get_db)): + author = crud.get_author_by_id(db=db, author_id=author_id) + if author is None: + raise HTTPException(status_code=404, detail=f"There is not author with id {author_id}") + return author + + +@app.post("/author/{author_id}/create_book", response_model=schemas.BookBase) +def create_book(author_id: int, data: schemas.BookCreate, db: Session = Depends(get_db)): + author = crud.get_author_by_id(db=db,author_id=author_id) + if author is None: + raise HTTPException(status_code=404, detail="You can't create a book for this author, because this author doesn't exist!") + return crud.create_book(db=db, data=data, author_id=author_id) + + +@app.get("/book/{book_id}", response_model=schemas.BookRead) +def get_book_by_id(book_id: int, db: Session = Depends(get_db)): + book = crud.get_book_by_id(db=db, book_id=book_id) + if book is None: + raise HTTPException(status_code=404, detail="Book not found!") + return book + +@app.get("/books", response_model=list[schemas.BookRead]) +def get_books(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + books = crud.get_books(db=db) + return books[skip: skip + limit] + +@app.get("/author/{author_id}/books", response_model=list[schemas.BookRead]) +def get_books_by_author(author_id: int, skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): + books = crud.get_books(db=db) + if author_id is not None: + books = [b for b in books if b.author_id == author_id] + return books[skip: skip + limit] \ No newline at end of file diff --git a/models.py b/models.py new file mode 100644 index 00000000..e40acd2c --- /dev/null +++ b/models.py @@ -0,0 +1,23 @@ +from database import Base +from sqlalchemy import String, ForeignKey, Integer, Date +from sqlalchemy.orm import relationship, Mapped, mapped_column +from datetime import date + +class DBAuthor(Base): + __tablename__ = "author_model" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) + name: Mapped[str] = mapped_column(String(100), nullable=False, unique=True) + bio: Mapped[str] = mapped_column(String(250)) + books: Mapped[list["DBBook"]] = relationship(back_populates="author") + + +class DBBook(Base): + __tablename__ = "books_model" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) + title: Mapped[str] = mapped_column(String(150), nullable=False, unique=True) + summary: Mapped[str] = mapped_column(String(200)) + publication_date: Mapped[date] = mapped_column(Date()) + author_id: Mapped[int] = mapped_column(ForeignKey("author_model.id")) + author: Mapped["DBAuthor"] = relationship(back_populates="books") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..f14f39d5 Binary files /dev/null and b/requirements.txt differ diff --git a/schemas.py b/schemas.py new file mode 100644 index 00000000..1f461aa9 --- /dev/null +++ b/schemas.py @@ -0,0 +1,31 @@ +from pydantic import BaseModel +from typing import Optional +from datetime import date + +class AuthorBase(BaseModel): + name: str + bio: Optional[str] = None + +class AuthorCreate(AuthorBase): + pass + +class AuthorRead(AuthorBase): + id: int + + class Config: + from_attributes = True + +class BookBase(BaseModel): + title: str + summary: str + publication_date: date + +class BookCreate(BookBase): + pass + +class BookRead(BookBase): + id: int + author_id: int + + class Config: + from_attributes = True