Add requirements, cli commands. New project structure

This commit is contained in:
2024-05-10 12:15:18 +04:00
parent e426c281b9
commit 698cca0aeb
12 changed files with 94 additions and 33 deletions

14
cli_commands.py Normal file
View File

@@ -0,0 +1,14 @@
from asyncio import run as aiorun
import typer
import database
cli = typer.Typer()
@cli.command(name="create")
def create_database(): aiorun(database.create_all())
@cli.command(name="drop")
def drop_database(): aiorun(database.drop_all())
@cli.command(name="recreate")
def recreate_database(): aiorun(database.recreate_all())

View File

@@ -1,3 +1,4 @@
from .crud import * from .crud import *
from .schemas import * from .schemas import *
from .database import get_session, init_models from .database import get_session, drop_all, create_all, recreate_all
from .crud import *

View File

@@ -1,8 +0,0 @@
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from .models import *
async def get_user(db: AsyncSession, user_id: int):
return await db.get(User, user_id)

View File

@@ -0,0 +1 @@
from .games import *

16
database/crud/games.py Normal file
View File

@@ -0,0 +1,16 @@
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from .. import models as mdl
from .. import schemas as sch
from ..database import add_transaction
async def add_game(db: AsyncSession, game_info: sch.GameCreate, user_id: int):
game = mdl.Game(**game_info.model_dump(), owner_id=user_id)
return await add_transaction(db, game)
async def get_games(db: AsyncSession):
return (await db.execute(select(mdl.Game))).scalars().all()
async def get_game(db: AsyncSession, game_id: int):
return await db.get(mdl.Game, game_id)

View File

@@ -19,8 +19,23 @@ async def get_session() -> AsyncSession: # type: ignore
async with async_session() as session: # type: ignore async with async_session() as session: # type: ignore
yield session yield session
async def drop_all():
async def init_models():
async with engine.begin() as conn: async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.drop_all)
async def create_all():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all) await conn.run_sync(Base.metadata.create_all)
async def recreate_all():
await drop_all()
await create_all()
async def add_transaction[T](db: AsyncSession, entity: T) -> T:
try:
db.add(entity)
await db.commit()
await db.refresh(entity)
return entity
except Exception as ex:
await db.rollback()
raise ex

View File

@@ -1,5 +1,5 @@
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from .database import Base from .database import Base
@@ -9,8 +9,10 @@ class Game(Base):
__tablename__ = "games" __tablename__ = "games"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
title = Column(String) cover = Column(String)
title = Column(String, nullable=False)
description = Column(String) description = Column(String)
torrent_file = Column(String, nullable=False)
language = Column(String) language = Column(String)
version = Column(String) version = Column(String)
download_size = Column(String) download_size = Column(String)
@@ -30,8 +32,8 @@ class User(Base):
__tablename__ = "users" __tablename__ = "users"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
email = Column(String, unique=True) email = Column(String, nullable=False, unique=True)
name = Column(String) name = Column(String, nullable=False)
hash_of_password = Column(String) hash_of_password = Column(String, nullable=False)
games = relationship("Game", back_populates="owner") games = relationship("Game", back_populates="owner")

View File

@@ -2,8 +2,10 @@ from pydantic import BaseModel
class GameBase(BaseModel): class GameBase(BaseModel):
cover: str | None = None
title: str title: str
description: str | None = None description: str | None = None
torrent_file: str
language: str | None = None language: str | None = None
version: str | None = None version: str | None = None
download_size: str | None = None download_size: str | None = None
@@ -25,7 +27,7 @@ class Game(GameBase):
owner_id: int owner_id: int
class Config: class Config:
orm_mode = True from_attributes = True
class UserBase(BaseModel): class UserBase(BaseModel):
@@ -42,4 +44,4 @@ class User(UserBase):
games: list[Game] = [] games: list[Game] = []
class Config: class Config:
orm_mode = True from_attributes = True

22
main.py
View File

@@ -1,22 +1,14 @@
from typing import Union
from fastapi import Depends, FastAPI, HTTPException from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
import typer
from database import * import cli_commands
from routes import *
app = FastAPI() app = FastAPI()
app.include_router(games_router)
cli = typer.Typer()
cli.add_typer(cli_commands.cli, name="database")
@app.on_event("startup") if(__name__ == "__main__"): cli()
async def startup_event():
await init_models()
@app.get("/users/{user_id}", response_model=User)
async def read_user(user_id: int, db: AsyncSession = Depends(get_session)):
db_user = await get_user(db, user_id=user_id)
print(db_user)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user

5
requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
fastapi==0.111.0
pydantic==2.7.1
SQLAlchemy==2.0.30
aiosqlite==0.20.0
typer==0.12.3

1
routes/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .games import router as games_router

20
routes/games.py Normal file
View File

@@ -0,0 +1,20 @@
from fastapi import APIRouter, Depends, HTTPException
from database import *
router = APIRouter(prefix="/games", tags=["Games"])
@router.get("/", response_model=list[Game])
async def get_games(db: AsyncSession = Depends(get_session)):
try: return await crud.get_games(db)
except Exception as ex: raise HTTPException(500)
@router.get("/{game_id}", response_model=Game)
async def get_game(game_id: int, db: AsyncSession = Depends(get_session)):
return await crud.get_game(db, game_id)
@router.post("/", response_model=Game)
async def add_game(game: GameCreate, user_id: int, db:AsyncSession = Depends(get_session)):
try: return await crud.add_game(db, game, user_id)
except Exception as ex: raise HTTPException(500)