Skip to content

Commit bab88f0

Browse files
committed
https://github.com/krylosov-aa/context-async-sqlalchemy/issues/11
1 parent 4f430bb commit bab88f0

File tree

5 files changed

+62
-1
lines changed

5 files changed

+62
-1
lines changed

context_async_sqlalchemy/session.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ async def atomic_db_session(
4141
await session.execute(...)
4242
"""
4343
session = await db_session(connect)
44+
if session.in_transaction():
45+
await session.commit()
4446
async with session.begin():
4547
yield session
4648

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from context_async_sqlalchemy import atomic_db_session, db_session
2+
from sqlalchemy import insert
3+
4+
from ..database import connection
5+
from ..models import ExampleTable
6+
7+
8+
async def handler_with_db_session_and_atomic_2() -> None:
9+
"""
10+
Let's imagine you already have a function that works with a contextual
11+
session, and its use case calls autocommit at the end of the request.
12+
You want to reuse this function, but you need to commit immediately,
13+
rather than wait for the request to complete.
14+
"""
15+
# This is a new transaction in a new connection
16+
await _insert_1()
17+
18+
# If you want to wrap an operation in a new
19+
# transaction, the current transaction will be committed automatically.
20+
async with atomic_db_session(connection):
21+
await _insert_1()
22+
23+
24+
async def _insert_1() -> None:
25+
session = await db_session(connection)
26+
stmt = insert(ExampleTable).values(
27+
text="example_with_db_session_and_atomic"
28+
)
29+
await session.execute(stmt)

examples/fastapi_example/setup_app.py

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

1111
from .database import connection
1212
from .routes.atomic_usage import handler_with_db_session_and_atomic
13+
from .routes.atomic_usage_2 import handler_with_db_session_and_atomic_2
1314
from .routes.manual_commit import handler_with_db_session_and_manual_close
1415
from .routes.manual_rollback import handler_with_db_session_and_manual_rollback
1516
from .routes.multiple_session_usage import handler_multiple_sessions
@@ -59,6 +60,11 @@ def setup_routes(app: FastAPI) -> None:
5960
handler_with_db_session_and_atomic,
6061
methods=["POST"],
6162
)
63+
app.add_api_route(
64+
"/example_with_db_session_and_atomic_2",
65+
handler_with_db_session_and_atomic_2,
66+
methods=["POST"],
67+
)
6268
app.add_api_route(
6369
"/example_with_db_session_and_manual_close",
6470
handler_with_db_session_and_manual_close,

examples/fastapi_example/tests/non_transactional/test_routes.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,30 @@ async def test_example_with_db_session_and_atomic(
5757
assert row.text == "example_with_db_session_and_atomic"
5858

5959

60+
@pytest.mark.asyncio
61+
async def test_example_with_db_session_and_atomic_2(
62+
client: AsyncClient,
63+
db_session_test: AsyncSession,
64+
) -> None:
65+
"""
66+
Since the handler involves manual session management,
67+
such a handler should only be tested in non-transactional tests.
68+
"""
69+
# Act
70+
response = await client.post(
71+
"/example_with_db_session_and_atomic_2",
72+
)
73+
74+
# Assert
75+
assert response.status_code == HTTPStatus.OK
76+
77+
result = await db_session_test.execute(select(ExampleTable))
78+
rows = result.scalars().all()
79+
assert len(rows) == 2
80+
for row in rows:
81+
assert row.text == "example_with_db_session_and_atomic"
82+
83+
6084
@pytest.mark.asyncio
6185
async def test_example_with_db_session_and_manual_close(
6286
client: AsyncClient,

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ ignore=WPS476, WPS300, WPS410, WPS412, WPS501, WPS229, WPS202, WPS110, WPS473
44
WPS217, WPS430, WPS420
55

66
per-file-ignores =
7-
examples/*: WPS110, WPS432, WPS204, WPS114, WPS226, WPS201
7+
examples/*: WPS110, WPS432, WPS204, WPS114, WPS226, WPS201, WPS213

0 commit comments

Comments
 (0)