|
| 1 | +import datetime as dt |
1 | 2 | import typing |
2 | 3 | from collections.abc import Sequence |
3 | 4 |
|
|
11 | 12 | from app.database import tables |
12 | 13 |
|
13 | 14 |
|
| 15 | +_WITH_MEMBERS: typing.Final[dict[str, typing.Any]] = { |
| 16 | + "load": [orm.joinedload(tables.ChatsTable.members)], |
| 17 | + "uniquify": True, |
| 18 | + # A chat already in the identity map keeps its noload members without this. |
| 19 | + "execution_options": {"populate_existing": True}, |
| 20 | +} |
| 21 | + |
| 22 | + |
14 | 23 | class ChatsRepository(SQLAlchemyAsyncRepositoryService[tables.ChatsTable]): |
15 | 24 | class BaseRepository(SQLAlchemyAsyncRepository[tables.ChatsTable]): |
16 | 25 | model_type = tables.ChatsTable |
17 | 26 |
|
18 | 27 | repository_type = BaseRepository |
19 | 28 |
|
20 | 29 | async def fetch_with_members(self, chat_id: int) -> tables.ChatsTable: |
21 | | - return await self.get_one( |
22 | | - tables.ChatsTable.id == chat_id, |
23 | | - load=[orm.selectinload(tables.ChatsTable.members)], |
24 | | - # A chat already in the identity map keeps its noload members without this. |
25 | | - execution_options={"populate_existing": True}, |
| 30 | + return await self.get_one(tables.ChatsTable.id == chat_id, **_WITH_MEMBERS) |
| 31 | + |
| 32 | + async def find_with_members(self, chat_id: int) -> tables.ChatsTable | None: |
| 33 | + return await self.get_one_or_none(tables.ChatsTable.id == chat_id, **_WITH_MEMBERS) |
| 34 | + |
| 35 | + async def set_last_message(self, chat_id: int, message_id: int) -> None: |
| 36 | + await self.repository.session.execute( |
| 37 | + sa.update(tables.ChatsTable) |
| 38 | + .where(tables.ChatsTable.id == chat_id) |
| 39 | + .values(last_message_id=message_id, updated_at=dt.datetime.now(tz=dt.UTC)) |
| 40 | + ) |
| 41 | + |
| 42 | + async def repoint_last_message(self, chat_id: int, deleted_message_id: int) -> None: |
| 43 | + newest_active: typing.Final = ( |
| 44 | + sa.select(tables.MessagesTable.id) |
| 45 | + .where(tables.MessagesTable.chat_id == chat_id, tables.MessagesTable.deleted_at.is_(None)) |
| 46 | + .order_by(tables.MessagesTable.id.desc()) |
| 47 | + .limit(1) |
| 48 | + .scalar_subquery() |
| 49 | + ) |
| 50 | + await self.repository.session.execute( |
| 51 | + sa.update(tables.ChatsTable) |
| 52 | + .where(tables.ChatsTable.id == chat_id, tables.ChatsTable.last_message_id == deleted_message_id) |
| 53 | + .values(last_message_id=newest_active, updated_at=dt.datetime.now(tz=dt.UTC)) |
26 | 54 | ) |
27 | 55 |
|
28 | 56 | async def get_or_create_direct(self, *, direct_key: str, created_by_id: int) -> tuple[tables.ChatsTable, bool]: |
@@ -59,7 +87,7 @@ async def list_for_user(self, user_id: int) -> Sequence[tables.ChatsTable]: |
59 | 87 | sa.select(tables.ChatsTable) |
60 | 88 | .options( |
61 | 89 | orm.with_expression(tables.ChatsTable.unread_count, unread_count), |
62 | | - orm.selectinload(tables.ChatsTable.last_message), |
| 90 | + orm.joinedload(tables.ChatsTable.last_message), |
63 | 91 | ) |
64 | 92 | .join(tables.ChatMembersTable, tables.ChatMembersTable.chat_id == tables.ChatsTable.id) |
65 | 93 | .where(tables.ChatMembersTable.user_id == user_id) |
|
0 commit comments