Skip to content

Commit d5c6694

Browse files
committed
add autocommit to fix not saved data
1 parent 011267c commit d5c6694

File tree

6 files changed

+18
-21
lines changed

6 files changed

+18
-21
lines changed

Justfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ sh:
1212
test *args: down && down
1313
docker compose run application sh -c "sleep 1 && uv run alembic downgrade base && uv run alembic upgrade head && uv run pytest {{ args }}"
1414

15+
# run api
16+
run:
17+
docker compose run --service-ports application sh -c "sleep 1 && uv run alembic upgrade head && uv run python -m app"
18+
1519
# create alembic migration with arguments
1620
migration *args: && down
1721
docker compose run application sh -c "sleep 1 && uv run alembic upgrade head && uv run alembic revision --autogenerate {{ args }}"

app/application.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import fastapi
55
import modern_di_fastapi
6-
from advanced_alchemy.exceptions import DuplicateKeyError, ForeignKeyError
6+
from advanced_alchemy.exceptions import DuplicateKeyError
77

88
from app import exceptions, ioc
99
from app.api.decks import ROUTER
@@ -23,13 +23,9 @@ def __init__(self) -> None:
2323
)
2424
self.di_container = modern_di_fastapi.setup_di(self.app)
2525
include_routers(self.app)
26-
self.app.add_exception_handler(
27-
ForeignKeyError,
28-
exceptions.foreign_key_error_handler, # type: ignore[arg-type]
29-
)
3026
self.app.add_exception_handler(
3127
DuplicateKeyError,
32-
exceptions.foreign_key_error_handler, # type: ignore[arg-type]
28+
exceptions.duplicate_key_error_handler, # type: ignore[arg-type]
3329
)
3430

3531
@contextlib.asynccontextmanager

app/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
from advanced_alchemy.exceptions import DuplicateKeyError, ForeignKeyError
1+
from advanced_alchemy.exceptions import DuplicateKeyError
22
from fastapi.responses import JSONResponse
33
from starlette import status
44
from starlette.requests import Request
55

66

7-
async def foreign_key_error_handler(_: Request, exc: ForeignKeyError | DuplicateKeyError) -> JSONResponse:
7+
async def duplicate_key_error_handler(_: Request, exc: DuplicateKeyError) -> JSONResponse:
88
return JSONResponse(
99
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
1010
content={"detail": exc.detail},

app/ioc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ class Dependencies(BaseGraph):
88
database_engine = providers.Resource(Scope.APP, create_sa_engine)
99
session = providers.Resource(Scope.REQUEST, create_session, engine=database_engine.cast)
1010

11-
decks_service = providers.Factory(Scope.REQUEST, repositories.DecksService, session=session.cast)
12-
cards_service = providers.Factory(Scope.REQUEST, repositories.CardsService, session=session.cast)
11+
decks_service = providers.Factory(Scope.REQUEST, repositories.DecksService, session=session.cast, auto_commit=True)
12+
cards_service = providers.Factory(Scope.REQUEST, repositories.CardsService, session=session.cast, auto_commit=True)

app/resources/db.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
async def create_sa_engine() -> typing.AsyncIterator[sa.AsyncEngine]:
13-
logger.debug("Initializing SQLAlchemy engine")
13+
logger.info("Initializing SQLAlchemy engine")
1414
engine = sa.create_async_engine(
1515
url=settings.db_dsn,
1616
echo=settings.debug,
@@ -19,12 +19,12 @@ async def create_sa_engine() -> typing.AsyncIterator[sa.AsyncEngine]:
1919
pool_pre_ping=settings.db_pool_pre_ping,
2020
max_overflow=settings.db_max_overflow,
2121
)
22-
logger.debug("SQLAlchemy engine has been initialized")
22+
logger.info("SQLAlchemy engine has been initialized")
2323
try:
2424
yield engine
2525
finally:
2626
await engine.dispose()
27-
logger.debug("SQLAlchemy engine has been cleaned up")
27+
logger.info("SQLAlchemy engine has been cleaned up")
2828

2929

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

3838
async def create_session(engine: sa.AsyncEngine) -> typing.AsyncIterator[sa.AsyncSession]:
3939
async with CustomAsyncSession(engine, expire_on_commit=False, autoflush=False) as session:
40+
logger.info("session created")
4041
yield session
42+
logger.info("session closed")

tests/conftest.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import typing
22

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

2120

2221
@pytest.fixture(autouse=True)
23-
async def di_container() -> modern_di.Container:
24-
return modern_di_fastapi.fetch_di_container(application)
25-
26-
27-
@pytest.fixture(autouse=True)
28-
async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[AsyncSession]:
29-
async with di_container:
22+
async def db_session() -> typing.AsyncIterator[AsyncSession]:
23+
async with modern_di_fastapi.fetch_di_container(application) as di_container:
3024
engine = await ioc.Dependencies.database_engine.async_resolve(di_container)
3125
connection = await engine.connect()
3226
transaction = await connection.begin()
@@ -39,3 +33,4 @@ async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[
3933
if connection.in_transaction():
4034
await transaction.rollback()
4135
await connection.close()
36+
await engine.dispose()

0 commit comments

Comments
 (0)