user repo/usecases/session/di
This commit is contained in:
0
api/infrastructure/__init__.py
Normal file
0
api/infrastructure/__init__.py
Normal file
0
api/infrastructure/dependencies/__init__.py
Normal file
0
api/infrastructure/dependencies/__init__.py
Normal file
42
api/infrastructure/dependencies/adapters.py
Normal file
42
api/infrastructure/dependencies/adapters.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from collections.abc import AsyncIterable
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import (
|
||||
AsyncEngine,
|
||||
AsyncSession,
|
||||
async_sessionmaker,
|
||||
create_async_engine,
|
||||
)
|
||||
|
||||
from api.application.abstractions import UnitOfWork
|
||||
from api.infrastructure.dependencies.stub import Stub
|
||||
from api.infrastructure.persistence.uow import SqlAlchemyUnitOfWork
|
||||
|
||||
|
||||
def new_unit_of_work(
|
||||
session: Annotated[AsyncSession, Depends(Stub(AsyncSession))],
|
||||
) -> UnitOfWork:
|
||||
return SqlAlchemyUnitOfWork(session)
|
||||
|
||||
|
||||
def create_engine() -> AsyncEngine:
|
||||
return create_async_engine("postgresql+asyncpg://postgresql+asyncpg//demo_user:user_pass@db:5432/serviceman_db")
|
||||
|
||||
|
||||
def create_session_maker(
|
||||
engine: Annotated[AsyncEngine, Depends(Stub(AsyncEngine))],
|
||||
) -> async_sessionmaker[AsyncSession]:
|
||||
maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||
print("session_maker id:", id(maker))
|
||||
return maker
|
||||
|
||||
|
||||
async def new_session(
|
||||
session_maker: Annotated[
|
||||
async_sessionmaker[AsyncSession],
|
||||
Depends(Stub(async_sessionmaker[AsyncSession])),
|
||||
],
|
||||
) -> AsyncIterable[AsyncSession]:
|
||||
async with session_maker() as session:
|
||||
yield session
|
17
api/infrastructure/dependencies/repositories.py
Normal file
17
api/infrastructure/dependencies/repositories.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from api.domain.user import UserRepository
|
||||
from api.infrastructure.persistence.repositories.user_repository import (
|
||||
SqlAlchemyUserRepository,
|
||||
)
|
||||
|
||||
from .stub import Stub
|
||||
|
||||
|
||||
def get_user_repository(
|
||||
session: Annotated[AsyncSession, Depends(Stub(AsyncSession))],
|
||||
) -> UserRepository:
|
||||
return SqlAlchemyUserRepository(session)
|
41
api/infrastructure/dependencies/stub.py
Normal file
41
api/infrastructure/dependencies/stub.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
class Stub:
|
||||
"""
|
||||
This class is used to prevent fastapi from digging into
|
||||
real dependencies attributes detecting them as request data
|
||||
|
||||
So instead of
|
||||
`interactor: Annotated[Interactor, Depends()]`
|
||||
Write
|
||||
`interactor: Annotated[Interactor, Depends(Stub(Interactor))]`
|
||||
|
||||
And then you can declare how to create it:
|
||||
`app.dependency_overrids[Interactor] = some_real_factory`
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, dependency: Callable, **kwargs):
|
||||
self._dependency = dependency
|
||||
self._kwargs = kwargs
|
||||
|
||||
def __call__(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if isinstance(other, Stub):
|
||||
return self._dependency == other._dependency and self._kwargs == other._kwargs
|
||||
else:
|
||||
if not self._kwargs:
|
||||
return self._dependency == other
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
if not self._kwargs:
|
||||
return hash(self._dependency)
|
||||
serial = (
|
||||
self._dependency,
|
||||
*self._kwargs.items(),
|
||||
)
|
||||
return hash(serial)
|
14
api/infrastructure/dependencies/usecases.py
Normal file
14
api/infrastructure/dependencies/usecases.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
|
||||
from api.application.abstractions.uow import UnitOfWork
|
||||
from api.application.usecase.create_user import CreateUser
|
||||
from api.domain.user.repository import UserRepository
|
||||
|
||||
|
||||
def provide_create_user(
|
||||
user_repository: Annotated[UserRepository, Depends()],
|
||||
uow: Annotated[UnitOfWork, Depends()],
|
||||
) -> CreateUser:
|
||||
return CreateUser(uow=uow, user_repository=user_repository)
|
0
api/infrastructure/persistence/__init__.py
Normal file
0
api/infrastructure/persistence/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from api.domain.user import User, UserRepository
|
||||
|
||||
|
||||
class SqlAlchemyUserRepository(UserRepository):
|
||||
def __init__(self, session: AsyncSession) -> None:
|
||||
self.session = session
|
||||
|
||||
async def create_user(self, user: User) -> None:
|
||||
pass
|
||||
|
||||
async def get_user(self, filter: dict) -> User | None:
|
||||
pass
|
||||
|
||||
async def get_users(self) -> list[User]:
|
||||
return []
|
14
api/infrastructure/persistence/uow.py
Normal file
14
api/infrastructure/persistence/uow.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from api.application.abstractions import UnitOfWork
|
||||
|
||||
|
||||
class SqlAlchemyUnitOfWork(UnitOfWork):
|
||||
def __init__(self, session: AsyncSession) -> None:
|
||||
self.session = session
|
||||
|
||||
async def commit(self) -> None:
|
||||
await self.session.commit()
|
||||
|
||||
async def rollback(self) -> None:
|
||||
await self.session.rollback()
|
Reference in New Issue
Block a user