Skip to content

Commit

Permalink
add autocommit to fix not saved data
Browse files Browse the repository at this point in the history
  • Loading branch information
lesnik512 committed Nov 9, 2024
1 parent 011267c commit d5c6694
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 21 deletions.
4 changes: 4 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ sh:
test *args: down && down
docker compose run application sh -c "sleep 1 && uv run alembic downgrade base && uv run alembic upgrade head && uv run pytest {{ args }}"

# run api
run:
docker compose run --service-ports application sh -c "sleep 1 && uv run alembic upgrade head && uv run python -m app"

# create alembic migration with arguments
migration *args: && down
docker compose run application sh -c "sleep 1 && uv run alembic upgrade head && uv run alembic revision --autogenerate {{ args }}"
Expand Down
8 changes: 2 additions & 6 deletions app/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import fastapi
import modern_di_fastapi
from advanced_alchemy.exceptions import DuplicateKeyError, ForeignKeyError
from advanced_alchemy.exceptions import DuplicateKeyError

from app import exceptions, ioc
from app.api.decks import ROUTER
Expand All @@ -23,13 +23,9 @@ def __init__(self) -> None:
)
self.di_container = modern_di_fastapi.setup_di(self.app)
include_routers(self.app)
self.app.add_exception_handler(
ForeignKeyError,
exceptions.foreign_key_error_handler, # type: ignore[arg-type]
)
self.app.add_exception_handler(
DuplicateKeyError,
exceptions.foreign_key_error_handler, # type: ignore[arg-type]
exceptions.duplicate_key_error_handler, # type: ignore[arg-type]
)

@contextlib.asynccontextmanager
Expand Down
4 changes: 2 additions & 2 deletions app/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from advanced_alchemy.exceptions import DuplicateKeyError, ForeignKeyError
from advanced_alchemy.exceptions import DuplicateKeyError
from fastapi.responses import JSONResponse
from starlette import status
from starlette.requests import Request


async def foreign_key_error_handler(_: Request, exc: ForeignKeyError | DuplicateKeyError) -> JSONResponse:
async def duplicate_key_error_handler(_: Request, exc: DuplicateKeyError) -> JSONResponse:
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={"detail": exc.detail},
Expand Down
4 changes: 2 additions & 2 deletions app/ioc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ class Dependencies(BaseGraph):
database_engine = providers.Resource(Scope.APP, create_sa_engine)
session = providers.Resource(Scope.REQUEST, create_session, engine=database_engine.cast)

decks_service = providers.Factory(Scope.REQUEST, repositories.DecksService, session=session.cast)
cards_service = providers.Factory(Scope.REQUEST, repositories.CardsService, session=session.cast)
decks_service = providers.Factory(Scope.REQUEST, repositories.DecksService, session=session.cast, auto_commit=True)
cards_service = providers.Factory(Scope.REQUEST, repositories.CardsService, session=session.cast, auto_commit=True)
8 changes: 5 additions & 3 deletions app/resources/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


async def create_sa_engine() -> typing.AsyncIterator[sa.AsyncEngine]:
logger.debug("Initializing SQLAlchemy engine")
logger.info("Initializing SQLAlchemy engine")
engine = sa.create_async_engine(
url=settings.db_dsn,
echo=settings.debug,
Expand All @@ -19,12 +19,12 @@ async def create_sa_engine() -> typing.AsyncIterator[sa.AsyncEngine]:
pool_pre_ping=settings.db_pool_pre_ping,
max_overflow=settings.db_max_overflow,
)
logger.debug("SQLAlchemy engine has been initialized")
logger.info("SQLAlchemy engine has been initialized")
try:
yield engine
finally:
await engine.dispose()
logger.debug("SQLAlchemy engine has been cleaned up")
logger.info("SQLAlchemy engine has been cleaned up")


class CustomAsyncSession(sa.AsyncSession):
Expand All @@ -37,4 +37,6 @@ async def close(self) -> None:

async def create_session(engine: sa.AsyncEngine) -> typing.AsyncIterator[sa.AsyncSession]:
async with CustomAsyncSession(engine, expire_on_commit=False, autoflush=False) as session:
logger.info("session created")
yield session
logger.info("session closed")
11 changes: 3 additions & 8 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import typing

import modern_di
import modern_di_fastapi
import pytest
from httpx import ASGITransport, AsyncClient
Expand All @@ -20,13 +19,8 @@ async def client() -> typing.AsyncIterator[AsyncClient]:


@pytest.fixture(autouse=True)
async def di_container() -> modern_di.Container:
return modern_di_fastapi.fetch_di_container(application)


@pytest.fixture(autouse=True)
async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[AsyncSession]:
async with di_container:
async def db_session() -> typing.AsyncIterator[AsyncSession]:
async with modern_di_fastapi.fetch_di_container(application) as di_container:
engine = await ioc.Dependencies.database_engine.async_resolve(di_container)
connection = await engine.connect()
transaction = await connection.begin()
Expand All @@ -39,3 +33,4 @@ async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[
if connection.in_transaction():
await transaction.rollback()
await connection.close()
await engine.dispose()

0 comments on commit d5c6694

Please sign in to comment.