Coverage for app/backend/src/couchers/helpers/group_chats.py: 100%
10 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-08 23:56 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-08 23:56 +0000
1"""
2Rules for scoping a user's group chat messages, shared by the conversations API and the Ping badge.
3"""
5from datetime import datetime
7from sqlalchemy import ColumnElement, SQLColumnExpression, and_, func, or_, select
9from couchers.models import GroupChatSubscription, Message
12def was_subscribed_at(
13 subscription: type[GroupChatSubscription], instant: SQLColumnExpression[datetime] | datetime
14) -> ColumnElement[bool]:
15 """
16 In the chat at the given instant: joined before it and hadn't left yet, or left after it.
17 """
18 return and_(
19 subscription.joined <= instant,
20 or_(subscription.left == None, subscription.left >= instant),
21 )
24def is_unseen(message: type[Message], subscription: type[GroupChatSubscription]) -> ColumnElement[bool]:
25 """
26 Unseen by the subscriber and still within their reach: a message they can never open, because it
27 was sent while they were out of the chat, is not unread.
28 """
29 return and_(
30 was_subscribed_at(subscription, message.time),
31 message.id > subscription.last_seen_message_id,
32 )
35def is_newest_subscription(user_id: SQLColumnExpression[int] | int) -> ColumnElement[bool]:
36 """
37 Only the user's newest subscription to each chat they've been in. Rejoining a chat leaves the
38 earlier subscription behind, and it's the newest one that carries the archived and last-seen state.
39 """
40 newest_per_chat = (
41 select(func.max(GroupChatSubscription.id))
42 .where(GroupChatSubscription.user_id == user_id)
43 .group_by(GroupChatSubscription.group_chat_id)
44 # not aliased(): rebuilding the ORM proxy index per call is a hotspot, and Ping runs this on
45 # every poll. correlate_except keeps this table local to the subquery so it doesn't bind to
46 # the enclosing query's GroupChatSubscription
47 .correlate_except(GroupChatSubscription)
48 )
49 return GroupChatSubscription.id.in_(newest_per_chat)