main
Сергей Ванюшкин 2024-03-04 10:15:28 +00:00
parent 4df5770e76
commit 92c52954c8
25 changed files with 80 additions and 114 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,13 +1,13 @@
from fastapi import FastAPI
from api.di import Container
from api.router.user import router
from api.router.user import router as user_router
def create_app() -> FastAPI:
app = FastAPI()
app.container = Container()
app.include_router(router)
app.include_router(user_router)
return app

View File

@ -1,16 +1,21 @@
import os
from dependency_injector import containers, providers
from repository.user import UserRepository
from service.user import UserService
from uow.database import Database
from api.repository.user import UserRepository
from api.service.user import UserService
from api.uow.database import Database
from api.uow.uow_base import UowBase
class Container(containers.DeclarativeContainer):
wiring_config = containers.WiringConfiguration(modules=["router.user"])
wiring_config = containers.WiringConfiguration(modules=["api.router.user"])
config = providers.Configuration(yaml_files=[f"{os.getenv('CONFIG_PATH')}"])
if os.getenv("INDOCKER"):
config.db.host.update("db")
db = providers.Singleton(
Database,
db_url="postgresql+asyncpg://{}:{}@{}:{}/{}".format(
@ -23,9 +28,14 @@ class Container(containers.DeclarativeContainer):
),
)
uow = providers.Factory(
UowBase,
session_factory=db.provided.session,
)
user_repository = providers.Factory(
UserRepository,
session_factory=db.provided.session,
uow=uow,
)
user_service = providers.Factory(

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,6 @@
from sqlalchemy import Boolean, Column, Integer, String
from .database import Base
from api.uow.database import Base
class User(Base):

Binary file not shown.

Binary file not shown.

View File

@ -1,48 +1,9 @@
from contextlib import AbstractContextManager
from typing import Callable
from model.user import User
from sqlalchemy.orm import Session
from api.uow.uow_base import UowBase
class UserRepository:
def __init__(self, session_factory: Callable[..., AbstractContextManager[Session]]) -> None:
self.session_factory = session_factory
def __init__(self, uow: UowBase) -> None:
self.uow = uow
def get_all(self):
with self.session_factory() as session:
return session.query(User).all()
def get_by_id(self, user_id: int) -> User:
with self.session_factory() as session:
user = session.query(User).filter(User.id == user_id).first()
if not user:
raise UserNotFoundError(user_id)
return user
def add(self, email: str, password: str, is_active: bool = True) -> User:
with self.session_factory() as session:
user = User(email=email, hashed_password=password, is_active=is_active)
session.add(user)
session.commit()
session.refresh(user)
return user
def delete_by_id(self, user_id: int) -> None:
with self.session_factory() as session:
entity: User = session.query(User).filter(User.id == user_id).first()
if not entity:
raise UserNotFoundError(user_id)
session.delete(entity)
session.commit()
class NotFoundError(Exception):
entity_name: str
def __init__(self, entity_id):
super().__init__(f"{self.entity_name} not found, id: {entity_id}")
class UserNotFoundError(NotFoundError):
entity_name: str = "User"
async def get_all_users(self):
return await self.uow.get_all_users()

Binary file not shown.

Binary file not shown.

View File

@ -1,53 +1,18 @@
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, Response, status
from fastapi import APIRouter, Depends
from ..di import Container
from ..repository.user import NotFoundError
from ..service.user import UserService
from api.di import Container
from api.service.user import UserService
router = APIRouter()
@router.get("/users")
@inject
def get_list(
async def get_user_list(
user_service: UserService = Depends(Provide[Container.user_service]),
):
return user_service.get_users()
@router.get("/users/{user_id}")
@inject
def get_by_id(
user_id: int,
user_service: UserService = Depends(Provide[Container.user_service]),
):
try:
return user_service.get_user_by_id(user_id)
except NotFoundError:
return Response(status_code=status.HTTP_404_NOT_FOUND)
@router.post("/users", status_code=status.HTTP_201_CREATED)
@inject
def add(
user_service: UserService = Depends(Provide[Container.user_service]),
):
return user_service.create_user()
@router.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
@inject
def remove(
user_id: int,
user_service: UserService = Depends(Provide[Container.user_service]),
):
try:
user_service.delete_user_by_id(user_id) # type: ignore
except NotFoundError:
return Response(status_code=status.HTTP_404_NOT_FOUND)
else:
return Response(status_code=status.HTTP_204_NO_CONTENT)
return await user_service.get_all_users()
@router.get("/status")

Binary file not shown.

Binary file not shown.

View File

@ -1,22 +1,10 @@
from uuid import uuid4
from model.user import User
from repository.user import UserRepository
from api.repository.user import UserRepository
from api.uow.uow_base import UowBase
class UserService:
def __init__(self, user_repository: UserRepository) -> None:
self._repository: UserRepository = user_repository
self.user_repository = user_repository
def get_users(self):
return self._repository.get_all()
def get_user_by_id(self, user_id: int) -> User:
return self._repository.get_by_id(user_id)
async def create_user(self) -> User:
uid = uuid4()
return await self._repository.add(email=f"{uid}@email.com", password="pwd")
async def delete_user_by_id(self, user_id: int) -> None:
return await self._repository.delete_by_id(user_id)
async def get_all_users(self):
return await self.user_repository.get_all_users()

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,11 @@
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from contextlib import (AbstractContextManager, asynccontextmanager,
contextmanager)
from typing import Callable
from sqlalchemy.ext.asyncio import (AsyncSession, async_sessionmaker,
create_async_engine)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
Base = declarative_base()
@ -7,16 +13,18 @@ Base = declarative_base()
class Database:
def __init__(self, db_url: str) -> None:
self._engine = create_async_engine(db_url, echo=True)
self._async_session = async_sessionmaker(
self._session_factory = async_sessionmaker(
self._engine,
class_=AsyncSession,
expire_on_commit=False,
)
@property
def session(self):
return self._session_factory()
async def __aenter__(self):
async with self._async_session() as session:
self.session = session
return self
return self
async def __aexit__(self, *args):
await self.session.rollback()

23
api/uow/uow_base.py Normal file
View File

@ -0,0 +1,23 @@
from contextlib import AbstractContextManager
from typing import Iterable
from dependency_injector.providers import Callable
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from sqlalchemy.orm import Session
from api.model.user import User
class UowBase:
def __init__(
self,
session_factory,
) -> None:
self.session = session_factory
async def get_all_users(self):
async with self.session as s:
query = select(User)
rr = await s.execute(query)
return rr.scalars().all()

11
manage.py Normal file
View File

@ -0,0 +1,11 @@
if __name__ == "__main__":
import uvicorn
uvicorn.run(
app="api.app:create_app",
host="0.0.0.0",
port=8000,
reload=True,
factory=True,
workers=1,
)