diff --git a/api/__pycache__/__init__.cpython-311.pyc b/api/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..912a19f Binary files /dev/null and b/api/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/__pycache__/app.cpython-311.pyc b/api/__pycache__/app.cpython-311.pyc new file mode 100644 index 0000000..0053790 Binary files /dev/null and b/api/__pycache__/app.cpython-311.pyc differ diff --git a/api/__pycache__/di.cpython-311.pyc b/api/__pycache__/di.cpython-311.pyc new file mode 100644 index 0000000..7039985 Binary files /dev/null and b/api/__pycache__/di.cpython-311.pyc differ diff --git a/api/app.py b/api/app.py index c541c5e..4cfbeb7 100644 --- a/api/app.py +++ b/api/app.py @@ -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 diff --git a/api/di.py b/api/di.py index 442f356..f480d03 100644 --- a/api/di.py +++ b/api/di.py @@ -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( diff --git a/api/migrations/__pycache__/env.cpython-311.pyc b/api/migrations/__pycache__/env.cpython-311.pyc new file mode 100644 index 0000000..e04ea99 Binary files /dev/null and b/api/migrations/__pycache__/env.cpython-311.pyc differ diff --git a/api/migrations/versions/__pycache__/ec1380cb4f18_initial.cpython-311.pyc b/api/migrations/versions/__pycache__/ec1380cb4f18_initial.cpython-311.pyc new file mode 100644 index 0000000..d024d3c Binary files /dev/null and b/api/migrations/versions/__pycache__/ec1380cb4f18_initial.cpython-311.pyc differ diff --git a/api/model/__pycache__/__init__.cpython-311.pyc b/api/model/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..fbe8d68 Binary files /dev/null and b/api/model/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/model/__pycache__/user.cpython-311.pyc b/api/model/__pycache__/user.cpython-311.pyc new file mode 100644 index 0000000..a2737ef Binary files /dev/null and b/api/model/__pycache__/user.cpython-311.pyc differ diff --git a/api/model/user.py b/api/model/user.py index f4b0a50..045ea8a 100644 --- a/api/model/user.py +++ b/api/model/user.py @@ -1,6 +1,6 @@ from sqlalchemy import Boolean, Column, Integer, String -from .database import Base +from api.uow.database import Base class User(Base): diff --git a/api/repository/__pycache__/__init__.cpython-311.pyc b/api/repository/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..05f6a27 Binary files /dev/null and b/api/repository/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/repository/__pycache__/user.cpython-311.pyc b/api/repository/__pycache__/user.cpython-311.pyc new file mode 100644 index 0000000..ee346a3 Binary files /dev/null and b/api/repository/__pycache__/user.cpython-311.pyc differ diff --git a/api/repository/user.py b/api/repository/user.py index 47c6c52..f288c7e 100644 --- a/api/repository/user.py +++ b/api/repository/user.py @@ -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() diff --git a/api/router/__pycache__/__init__.cpython-311.pyc b/api/router/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..399db48 Binary files /dev/null and b/api/router/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/router/__pycache__/user.cpython-311.pyc b/api/router/__pycache__/user.cpython-311.pyc new file mode 100644 index 0000000..fc4e085 Binary files /dev/null and b/api/router/__pycache__/user.cpython-311.pyc differ diff --git a/api/router/user.py b/api/router/user.py index f1eda84..f233579 100644 --- a/api/router/user.py +++ b/api/router/user.py @@ -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") diff --git a/api/service/__pycache__/__init__.cpython-311.pyc b/api/service/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..86db8f4 Binary files /dev/null and b/api/service/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/service/__pycache__/user.cpython-311.pyc b/api/service/__pycache__/user.cpython-311.pyc new file mode 100644 index 0000000..09f6379 Binary files /dev/null and b/api/service/__pycache__/user.cpython-311.pyc differ diff --git a/api/service/user.py b/api/service/user.py index 1cac4c3..b27887f 100644 --- a/api/service/user.py +++ b/api/service/user.py @@ -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() diff --git a/api/uow/__pycache__/__init__.cpython-311.pyc b/api/uow/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..70b4361 Binary files /dev/null and b/api/uow/__pycache__/__init__.cpython-311.pyc differ diff --git a/api/uow/__pycache__/database.cpython-311.pyc b/api/uow/__pycache__/database.cpython-311.pyc new file mode 100644 index 0000000..6cad726 Binary files /dev/null and b/api/uow/__pycache__/database.cpython-311.pyc differ diff --git a/api/uow/__pycache__/uow_base.cpython-311.pyc b/api/uow/__pycache__/uow_base.cpython-311.pyc new file mode 100644 index 0000000..1380165 Binary files /dev/null and b/api/uow/__pycache__/uow_base.cpython-311.pyc differ diff --git a/api/uow/database.py b/api/uow/database.py index 93f78d1..acb81b5 100644 --- a/api/uow/database.py +++ b/api/uow/database.py @@ -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() diff --git a/api/uow/uow_base.py b/api/uow/uow_base.py new file mode 100644 index 0000000..ec93aae --- /dev/null +++ b/api/uow/uow_base.py @@ -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() diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..1f78bf2 --- /dev/null +++ b/manage.py @@ -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, + )