remove fucking uow and replace it by TransactionContextManager
parent
12d61e01e1
commit
ad92682eda
|
@ -2,7 +2,7 @@ from fastapi import FastAPI
|
||||||
from sqlalchemy.ext.asyncio import (AsyncEngine, AsyncSession,
|
from sqlalchemy.ext.asyncio import (AsyncEngine, AsyncSession,
|
||||||
async_sessionmaker)
|
async_sessionmaker)
|
||||||
|
|
||||||
from api.application.abstractions.uow import UnitOfWork
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
from api.application.protocols.date_time import DateTimeProvider
|
from api.application.protocols.date_time import DateTimeProvider
|
||||||
from api.application.protocols.jwt import JwtTokenProcessor
|
from api.application.protocols.jwt import JwtTokenProcessor
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
|
@ -16,8 +16,8 @@ from api.domain.user.repository import UserRepository
|
||||||
from api.infrastructure.auth.jwt_settings import JwtSettings
|
from api.infrastructure.auth.jwt_settings import JwtSettings
|
||||||
from api.infrastructure.dependencies.adapters import (create_engine,
|
from api.infrastructure.dependencies.adapters import (create_engine,
|
||||||
create_session_maker,
|
create_session_maker,
|
||||||
new_session,
|
get_transaction_context,
|
||||||
new_unit_of_work)
|
new_session)
|
||||||
from api.infrastructure.dependencies.configs import (app_settings,
|
from api.infrastructure.dependencies.configs import (app_settings,
|
||||||
get_db_settings,
|
get_db_settings,
|
||||||
get_jwt_settings)
|
get_jwt_settings)
|
||||||
|
@ -43,7 +43,7 @@ def init_dependencies(app: FastAPI) -> None:
|
||||||
app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker
|
app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker
|
||||||
app.dependency_overrides[AsyncSession] = new_session
|
app.dependency_overrides[AsyncSession] = new_session
|
||||||
|
|
||||||
app.dependency_overrides[UnitOfWork] = new_unit_of_work
|
app.dependency_overrides[TransactionContextManager] = get_transaction_context
|
||||||
|
|
||||||
app.dependency_overrides[DateTimeProvider] = get_date_time_provider
|
app.dependency_overrides[DateTimeProvider] = get_date_time_provider
|
||||||
app.dependency_overrides[PasswordHasher] = get_password_hasher
|
app.dependency_overrides[PasswordHasher] = get_password_hasher
|
||||||
|
|
|
@ -2,18 +2,27 @@ from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
from api.domain.error import DomainValidationError
|
from api.domain.error import DomainValidationError
|
||||||
from api.domain.user.error import (
|
from api.domain.user.error import (UserAlreadyExistsError,
|
||||||
UserAlreadyExistsError,
|
UserInvalidCredentialsError,
|
||||||
UserInvalidCredentialsError,
|
UserIsNotAuthorizedError)
|
||||||
UserIsNotAuthorizedError,
|
from api.infrastructure.persistence.error import TransactionContextManagerError
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def validation_error_exc_handler(request: Request, exc: DomainValidationError) -> JSONResponse:
|
async def transaction_error_exec_handler(
|
||||||
|
request: Request, exc: TransactionContextManagerError
|
||||||
|
) -> JSONResponse:
|
||||||
return JSONResponse(status_code=400, content={"detail": exc.message})
|
return JSONResponse(status_code=400, content={"detail": exc.message})
|
||||||
|
|
||||||
|
|
||||||
async def user_authentication_error_exc_handler(request: Request, exc: UserIsNotAuthorizedError) -> JSONResponse:
|
async def validation_error_exc_handler(
|
||||||
|
request: Request, exc: DomainValidationError
|
||||||
|
) -> JSONResponse:
|
||||||
|
return JSONResponse(status_code=400, content={"detail": exc.message})
|
||||||
|
|
||||||
|
|
||||||
|
async def user_authentication_error_exc_handler(
|
||||||
|
request: Request, exc: UserIsNotAuthorizedError
|
||||||
|
) -> JSONResponse:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=401,
|
status_code=401,
|
||||||
content={"detail": exc.message},
|
content={"detail": exc.message},
|
||||||
|
@ -21,7 +30,9 @@ async def user_authentication_error_exc_handler(request: Request, exc: UserIsNot
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def user_already_exist_error_exc_handler(request: Request, exc: UserAlreadyExistsError) -> JSONResponse:
|
async def user_already_exist_error_exc_handler(
|
||||||
|
request: Request, exc: UserAlreadyExistsError
|
||||||
|
) -> JSONResponse:
|
||||||
return JSONResponse(status_code=409, content={"detail": exc.message})
|
return JSONResponse(status_code=409, content={"detail": exc.message})
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +47,16 @@ def init_exc_handlers(app: FastAPI) -> None:
|
||||||
DomainValidationError,
|
DomainValidationError,
|
||||||
validation_error_exc_handler,
|
validation_error_exc_handler,
|
||||||
)
|
)
|
||||||
app.add_exception_handler(UserIsNotAuthorizedError, user_authentication_error_exc_handler)
|
app.add_exception_handler(
|
||||||
app.add_exception_handler(UserAlreadyExistsError, user_already_exist_error_exc_handler)
|
UserIsNotAuthorizedError, user_authentication_error_exc_handler
|
||||||
app.add_exception_handler(UserInvalidCredentialsError, user_invalid_credentials_error_exc_handler)
|
)
|
||||||
|
app.add_exception_handler(
|
||||||
|
UserAlreadyExistsError, user_already_exist_error_exc_handler
|
||||||
|
)
|
||||||
|
app.add_exception_handler(
|
||||||
|
UserInvalidCredentialsError, user_invalid_credentials_error_exc_handler
|
||||||
|
)
|
||||||
|
|
||||||
|
app.add_exception_handler(
|
||||||
|
TransactionContextManagerError, transaction_error_exec_handler
|
||||||
|
)
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
from .uow import UnitOfWork
|
|
||||||
|
|
||||||
__all__ = ("UnitOfWork",)
|
|
|
@ -1,9 +0,0 @@
|
||||||
from typing import Protocol
|
|
||||||
|
|
||||||
|
|
||||||
class UnitOfWork(Protocol):
|
|
||||||
async def commit(self) -> None:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
async def rollback(self) -> None:
|
|
||||||
raise NotImplementedError
|
|
|
@ -1,9 +1,6 @@
|
||||||
from sqlalchemy.exc import IntegrityError
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
|
|
||||||
from api.application.abstractions import UnitOfWork
|
|
||||||
from api.application.contracts.auth.auth_request import UserCreateRequest
|
from api.application.contracts.auth.auth_request import UserCreateRequest
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
from api.domain.user.error import UserAlreadyExistsError
|
|
||||||
from api.domain.user.model import User
|
from api.domain.user.model import User
|
||||||
from api.domain.user.repository import UserRepository
|
from api.domain.user.repository import UserRepository
|
||||||
|
|
||||||
|
@ -11,11 +8,11 @@ from api.domain.user.repository import UserRepository
|
||||||
class CreateUser:
|
class CreateUser:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
uow: UnitOfWork,
|
transaction: TransactionContextManager,
|
||||||
user_repository: UserRepository,
|
user_repository: UserRepository,
|
||||||
password_hasher: PasswordHasher,
|
password_hasher: PasswordHasher,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.uow = uow
|
self.transaction = transaction
|
||||||
self.user_repository = user_repository
|
self.user_repository = user_repository
|
||||||
self.hasher = password_hasher
|
self.hasher = password_hasher
|
||||||
|
|
||||||
|
@ -27,13 +24,6 @@ class CreateUser:
|
||||||
hashed_password=self.hasher.hash_password(request.password),
|
hashed_password=self.hasher.hash_password(request.password),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
async with self.transaction as tr:
|
||||||
await self.user_repository.create_user(user=user)
|
await self.user_repository.create_user(user=user)
|
||||||
await self.uow.commit()
|
await tr.commit()
|
||||||
|
|
||||||
except IntegrityError as e:
|
|
||||||
msg = e.args[0].split("\n")[-1]
|
|
||||||
msg = msg.split(":")[1].strip()
|
|
||||||
|
|
||||||
if "email" in msg:
|
|
||||||
raise UserAlreadyExistsError(message=msg)
|
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
from api.application.contracts.company.company_request import CreateNewCompany
|
from api.application.contracts.company.company_request import CreateNewCompany
|
||||||
from api.application.contracts.company.company_response import CompanyBaseResponse
|
from api.application.contracts.company.company_response import \
|
||||||
|
CompanyBaseResponse
|
||||||
from api.domain.company.repository import CompanyRepository
|
from api.domain.company.repository import CompanyRepository
|
||||||
|
|
||||||
|
|
||||||
class CreateCompany:
|
class CreateCompany:
|
||||||
def __init__(self, company_repository: CompanyRepository) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
transaction: TransactionContextManager,
|
||||||
|
company_repository: CompanyRepository,
|
||||||
|
) -> None:
|
||||||
self.company_repository = company_repository
|
self.company_repository = company_repository
|
||||||
|
self.transaction = transaction
|
||||||
|
|
||||||
async def execute(self, request: CreateNewCompany) -> CompanyBaseResponse:
|
async def execute(self, request: CreateNewCompany) -> CompanyBaseResponse:
|
||||||
# companies = await self.company_repository.
|
async with self.transaction as tr:
|
||||||
return CompanyBaseResponse(name=request.name, email=request.email)
|
# companies = await self.company_repository.
|
||||||
|
return CompanyBaseResponse(name=request.name, email=request.email)
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
from api.application.contracts.company.company_request import CompanyByOwnerEmail
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
from api.application.contracts.company.company_response import CompanyBaseResponse
|
from api.application.contracts.company.company_request import \
|
||||||
|
CompanyByOwnerEmail
|
||||||
|
from api.application.contracts.company.company_response import \
|
||||||
|
CompanyBaseResponse
|
||||||
from api.domain.company.repository import CompanyRepository
|
from api.domain.company.repository import CompanyRepository
|
||||||
|
|
||||||
|
|
||||||
class GetCompaniesByOwnerEmail:
|
class GetCompaniesByOwnerEmail:
|
||||||
def __init__(self, company_repository: CompanyRepository) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
transaction: TransactionContextManager,
|
||||||
|
company_repository: CompanyRepository,
|
||||||
|
) -> None:
|
||||||
self.company_repository = company_repository
|
self.company_repository = company_repository
|
||||||
|
self.transaction = transaction
|
||||||
|
|
||||||
async def execute(self, request: CompanyByOwnerEmail) -> list[CompanyBaseResponse]:
|
async def execute(self, request: CompanyByOwnerEmail) -> list[CompanyBaseResponse]:
|
||||||
companies = await self.company_repository.get_companies_by_owner_email(filter={"email": request.email})
|
async with self.transaction:
|
||||||
return [CompanyBaseResponse(name=comp.name.value, email=comp.email.value) for comp in companies]
|
companies = await self.company_repository.get_companies_by_owner_email(
|
||||||
|
filter={"email": request.email}
|
||||||
|
)
|
||||||
|
return [
|
||||||
|
CompanyBaseResponse(name=comp.name.value, email=comp.email.value)
|
||||||
|
for comp in companies
|
||||||
|
]
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
from api.application.abstractions import UnitOfWork
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
from api.application.contracts.user import GetUserByEmailRequest, UserResponse
|
from api.application.contracts.user import GetUserByEmailRequest, UserResponse
|
||||||
from api.domain.user.repository import UserRepository
|
from api.domain.user.repository import UserRepository
|
||||||
|
|
||||||
|
|
||||||
class GetUserByEmail:
|
class GetUserByEmail:
|
||||||
def __init__(self, uow: UnitOfWork, user_repository: UserRepository) -> None:
|
def __init__(
|
||||||
self.uow = uow
|
self, transaction: TransactionContextManager, user_repository: UserRepository
|
||||||
|
) -> None:
|
||||||
|
self.transaction = transaction
|
||||||
self.user_repository = user_repository
|
self.user_repository = user_repository
|
||||||
|
|
||||||
async def execute(self, request: GetUserByEmailRequest) -> UserResponse | None:
|
async def execute(self, request: GetUserByEmailRequest) -> UserResponse | None:
|
||||||
user = await self.user_repository.get_user(filter={"email": request.email})
|
async with self.transaction:
|
||||||
if user:
|
user = await self.user_repository.get_user(filter={"email": request.email})
|
||||||
|
if user:
|
||||||
|
return None
|
||||||
return None
|
return None
|
||||||
return None
|
|
||||||
|
|
|
@ -2,23 +2,20 @@ from collections.abc import AsyncIterable
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from sqlalchemy.ext.asyncio import (
|
from sqlalchemy.ext.asyncio import (AsyncEngine, AsyncSession,
|
||||||
AsyncEngine,
|
async_sessionmaker, create_async_engine)
|
||||||
AsyncSession,
|
|
||||||
async_sessionmaker,
|
|
||||||
create_async_engine,
|
|
||||||
)
|
|
||||||
|
|
||||||
from api.application.abstractions import UnitOfWork
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
from api.infrastructure.dependencies.stub import Stub
|
from api.infrastructure.dependencies.stub import Stub
|
||||||
from api.infrastructure.persistence.uow import SqlAlchemyUnitOfWork
|
from api.infrastructure.persistence.transaction import \
|
||||||
|
SqlalchemyTransactionContextManager
|
||||||
from api.infrastructure.settings import Settings
|
from api.infrastructure.settings import Settings
|
||||||
|
|
||||||
|
|
||||||
def new_unit_of_work(
|
def get_transaction_context(
|
||||||
session: Annotated[AsyncSession, Depends(Stub(AsyncSession))],
|
session: Annotated[AsyncSession, Depends(Stub(AsyncSession))]
|
||||||
) -> UnitOfWork:
|
) -> TransactionContextManager:
|
||||||
return SqlAlchemyUnitOfWork(session)
|
return SqlalchemyTransactionContextManager(session)
|
||||||
|
|
||||||
|
|
||||||
def create_engine(
|
def create_engine(
|
||||||
|
|
|
@ -2,7 +2,7 @@ from typing import Annotated
|
||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
|
|
||||||
from api.application.abstractions.uow import UnitOfWork
|
from api.application.abstractions.transaction import TransactionContextManager
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
from api.application.usecase.auth.create_user import CreateUser
|
from api.application.usecase.auth.create_user import CreateUser
|
||||||
from api.application.usecase.company.create_company import CreateCompany
|
from api.application.usecase.company.create_company import CreateCompany
|
||||||
|
@ -15,21 +15,33 @@ from api.infrastructure.dependencies.stub import Stub
|
||||||
|
|
||||||
def provide_create_user(
|
def provide_create_user(
|
||||||
user_repository: Annotated[UserRepository, Depends(Stub(UserRepository))],
|
user_repository: Annotated[UserRepository, Depends(Stub(UserRepository))],
|
||||||
uow: Annotated[UnitOfWork, Depends(Stub(UnitOfWork))],
|
transaction: Annotated[
|
||||||
|
TransactionContextManager, Depends(Stub(TransactionContextManager))
|
||||||
|
],
|
||||||
password_hasher: Annotated[PasswordHasher, Depends(Stub(PasswordHasher))],
|
password_hasher: Annotated[PasswordHasher, Depends(Stub(PasswordHasher))],
|
||||||
) -> CreateUser:
|
) -> CreateUser:
|
||||||
return CreateUser(
|
return CreateUser(
|
||||||
uow=uow, user_repository=user_repository, password_hasher=password_hasher
|
transaction=transaction,
|
||||||
|
user_repository=user_repository,
|
||||||
|
password_hasher=password_hasher,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def provide_get_companies_by_email(
|
def provide_get_companies_by_email(
|
||||||
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))],
|
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))],
|
||||||
|
transaction: Annotated[
|
||||||
|
TransactionContextManager, Depends(Stub(TransactionContextManager))
|
||||||
|
],
|
||||||
) -> GetCompaniesByOwnerEmail:
|
) -> GetCompaniesByOwnerEmail:
|
||||||
return GetCompaniesByOwnerEmail(company_repository=company_repository)
|
return GetCompaniesByOwnerEmail(
|
||||||
|
transaction=transaction, company_repository=company_repository
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def provide_create_company(
|
def provide_create_company(
|
||||||
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))]
|
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))],
|
||||||
|
transaction: Annotated[
|
||||||
|
TransactionContextManager, Depends(Stub(TransactionContextManager))
|
||||||
|
],
|
||||||
) -> CreateCompany:
|
) -> CreateCompany:
|
||||||
return CreateCompany(company_repository=company_repository)
|
return CreateCompany(transaction=transaction, company_repository=company_repository)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
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()
|
|
Loading…
Reference in New Issue