Skip to content

Commit ba925ef

Browse files
authored
fix: translate integrity errors from the message upsert (#60)
get_or_create called session.execute directly, so a constraint violation surfaced as SQLAlchemy's IntegrityError instead of advanced-alchemy's ForeignKeyError or DuplicateKeyError, which the API maps to 400 and 409.
1 parent b4041af commit ba925ef

2 files changed

Lines changed: 15 additions & 4 deletions

File tree

‎app/repositories/messages_repository.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
from collections.abc import Sequence
44

55
import sqlalchemy as sa
6+
from advanced_alchemy.exceptions import wrap_sqlalchemy_exception
67
from advanced_alchemy.filters import LimitOffset
7-
from advanced_alchemy.repository import SQLAlchemyAsyncRepository
8+
from advanced_alchemy.repository import DEFAULT_ERROR_MESSAGE_TEMPLATES, SQLAlchemyAsyncRepository
89
from advanced_alchemy.service import SQLAlchemyAsyncRepositoryService
910
from sqlalchemy.dialects import postgresql
1011

@@ -29,9 +30,11 @@ async def get_or_create(
2930
)
3031
# xmax is 0 only on a row version this statement inserted.
3132
created: typing.Final = sa.literal_column("xmax = 0", sa.Boolean)
32-
message, was_created = (
33-
await self.repository.session.execute(statement.returning(tables.MessagesTable, created))
34-
).one()
33+
with wrap_sqlalchemy_exception(error_messages=DEFAULT_ERROR_MESSAGE_TEMPLATES, dialect_name="postgresql"):
34+
result: typing.Final = await self.repository.session.execute(
35+
statement.returning(tables.MessagesTable, created)
36+
)
37+
message, was_created = result.one()
3538
return message, was_created
3639

3740
async def fetch_latest_active(self, chat_id: int) -> tables.MessagesTable | None:

‎tests/use_cases/test_create_message.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77
import sqlalchemy as sa
8+
from advanced_alchemy.exceptions import ForeignKeyError
89
from db_retry import Transaction
910
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
1011

@@ -99,6 +100,13 @@ async def test_same_idempotency_key_in_two_different_chats_creates_two_messages(
99100
assert second.chat_id == other_chat.id
100101

101102

103+
async def test_get_or_create_raises_foreign_key_error_for_an_unknown_chat(
104+
messages_repository: MessagesRepository, alice: Actor
105+
) -> None:
106+
with pytest.raises(ForeignKeyError):
107+
await messages_repository.get_or_create(chat_id=-1, user_id=alice.id, idempotency_key=uuid.uuid4(), text="hi")
108+
109+
102110
async def test_send_writes_the_message_with_a_single_statement(
103111
create_message_use_case: CreateMessageUseCase,
104112
direct_chat: tables.ChatsTable,

0 commit comments

Comments
 (0)