1
0

Only return rooms where user is currently joined

This commit is contained in:
Devon Hudson
2025-10-07 12:49:32 -06:00
parent 4dd82e581a
commit 4c51247cb3
2 changed files with 16 additions and 52 deletions
+14 -50
View File
@@ -1134,25 +1134,10 @@ class RelationsWorkerStore(EventsWorkerStore, SQLBaseStore):
) -> Tuple[Sequence[Tuple[str, str, Optional[EventBase]]], Optional[int]]:
"""Get a list of updated threads, ordered by stream ordering of their
latest reply, filtered to only include threads in rooms where the user
was joined at the time of the thread's latest update.
Note: This function has a known limitation due to the threads table only
storing the latest update per thread. If a thread had multiple updates
within the token range and the user left the room between updates, earlier
updates that occurred while the user was joined will NOT be returned.
Example edge case:
t1: User joins room, thread updated (user should see this)
t2: User leaves room
t3: Thread updated again (user should NOT see this)
Result: Neither update is returned (because membership check at t3 fails)
This is an acceptable trade-off to avoid expensive queries through the
event_relations table.
is currently joined.
Args:
user_id: Only fetch threads for rooms where the user was joined at
the time of the thread's latest update.
user_id: Only fetch threads for rooms that the user is currently joined to.
from_token: Fetch rows from a previous next_batch, or from the start if None.
to_token: Fetch rows from a previous prev_batch, or from the stream end if None.
limit: Only fetch the most recent `limit` threads.
@@ -1183,41 +1168,20 @@ class RelationsWorkerStore(EventsWorkerStore, SQLBaseStore):
pagination_clause += " AND stream_ordering <= ?"
pagination_args.append(str(to_bound))
# Filter threads to only those in rooms where the user was joined at the
# time of the thread's latest update.
#
# We use room_memberships.event_stream_ordering to perform a point-in-time
# membership check. This finds the most recent membership event for the user
# in each room that occurred at or before the thread's latest update
# (threads.stream_ordering), and verifies it was a 'join' membership.
#
# Note: Due to the threads table only storing the latest update per thread,
# this approach has a known limitation: if a thread had multiple updates and
# the user left the room between updates, earlier updates that occurred while
# they were joined will not be returned. This is an acceptable trade-off to
# avoid expensive queries through event_relations.
# Filter threads to only those in rooms that the user is currently joined to.
sql = f"""
SELECT thread_id, room_id, latest_event_id, stream_ordering
FROM threads
WHERE EXISTS (
SELECT 1
FROM room_memberships AS rm
WHERE rm.room_id = threads.room_id
AND rm.user_id = ?
AND rm.event_stream_ordering <= threads.stream_ordering
AND rm.membership = ?
AND NOT EXISTS (
SELECT 1
FROM room_memberships AS rm2
WHERE rm2.room_id = rm.room_id
AND rm2.user_id = rm.user_id
AND rm2.event_stream_ordering > rm.event_stream_ordering
AND rm2.event_stream_ordering <= threads.stream_ordering
)
)
{pagination_clause}
ORDER BY stream_ordering DESC
LIMIT ?
FROM threads
WHERE EXISTS (
SELECT 1
FROM local_current_membership AS lcm
WHERE lcm.room_id = threads.room_id
AND lcm.user_id = ?
AND lcm.membership = ?
)
{pagination_clause}
ORDER BY stream_ordering DESC
LIMIT ?
"""
def _get_thread_updates_for_user_txn(
@@ -350,8 +350,8 @@ class SlidingSyncThreadsExtensionTestCase(SlidingSyncBase):
response_body, _ = self.do_sync(sync_body, tok=user2_tok, since=sync_pos)
# Assert: User2 should NOT see the thread update (they left before latest update)
# Note: This demonstrates the known limitation - user2 won't see the thread
# even though there was an update while they were joined (Reply 1)
# Note: This also demonstrates that only currently joined rooms are returned - user2
# won't see the thread even though there was an update while they were joined (Reply 1)
self.assertNotIn(
EXT_NAME,
response_body["extensions"],