Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit d41e1f6

Browse files
committed
Initial implementation of MSC3981.
1 parent e6af49f commit d41e1f6

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

changelog.d/15315.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Experimental support to recursively provide relations per [MSC3981](https://github.com/matrix-org/matrix-spec-proposals/pull/3981).

synapse/config/experimental.py

+5
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
181181

182182
# MSC2659: Application service ping endpoint
183183
self.msc2659_enabled = experimental.get("msc2659_enabled", False)
184+
185+
# MSC3981: Recurse relations
186+
self.msc3981_recurse_relations = experimental.get(
187+
"msc3981_recurse_relations", False
188+
)

synapse/handlers/relations.py

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ async def get_relations(
8585
event_id: str,
8686
room_id: str,
8787
pagin_config: PaginationConfig,
88+
recurse: bool,
8889
include_original_event: bool,
8990
relation_type: Optional[str] = None,
9091
event_type: Optional[str] = None,
@@ -98,6 +99,7 @@ async def get_relations(
9899
event_id: Fetch events that relate to this event ID.
99100
room_id: The room the event belongs to.
100101
pagin_config: The pagination config rules to apply, if any.
102+
recurse: Whether to recursively find relations.
101103
include_original_event: Whether to include the parent event.
102104
relation_type: Only fetch events with this relation type, if given.
103105
event_type: Only fetch events with this event type, if given.
@@ -132,6 +134,7 @@ async def get_relations(
132134
direction=pagin_config.direction,
133135
from_token=pagin_config.from_token,
134136
to_token=pagin_config.to_token,
137+
recurse=recurse,
135138
)
136139

137140
events = await self._main_store.get_events_as_list(

synapse/rest/client/relations.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from synapse.api.constants import Direction
2020
from synapse.handlers.relations import ThreadsListInclude
2121
from synapse.http.server import HttpServer
22-
from synapse.http.servlet import RestServlet, parse_integer, parse_string
22+
from synapse.http.servlet import RestServlet, parse_boolean, parse_integer, parse_string
2323
from synapse.http.site import SynapseRequest
2424
from synapse.rest.client._base import client_patterns
2525
from synapse.storage.databases.main.relations import ThreadsNextBatch
@@ -49,6 +49,7 @@ def __init__(self, hs: "HomeServer"):
4949
self.auth = hs.get_auth()
5050
self._store = hs.get_datastores().main
5151
self._relations_handler = hs.get_relations_handler()
52+
self._support_recurse = hs.config.experimental.msc3981_recurse_relations
5253

5354
async def on_GET(
5455
self,
@@ -63,6 +64,12 @@ async def on_GET(
6364
pagination_config = await PaginationConfig.from_request(
6465
self._store, request, default_limit=5, default_dir=Direction.BACKWARDS
6566
)
67+
if self._support_recurse:
68+
recurse = parse_boolean(
69+
request, "org.matrix.msc3981.recurse", default=False
70+
)
71+
else:
72+
recurse = False
6673

6774
# The unstable version of this API returns an extra field for client
6875
# compatibility, see https://github.com/matrix-org/synapse/issues/12930.
@@ -75,6 +82,7 @@ async def on_GET(
7582
event_id=parent_id,
7683
room_id=room_id,
7784
pagin_config=pagination_config,
85+
recurse=recurse,
7886
include_original_event=include_original_event,
7987
relation_type=relation_type,
8088
event_type=event_type,

synapse/storage/databases/main/relations.py

+39-13
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ async def get_relations_for_event(
172172
direction: Direction = Direction.BACKWARDS,
173173
from_token: Optional[StreamToken] = None,
174174
to_token: Optional[StreamToken] = None,
175+
recurse: bool = False,
175176
) -> Tuple[Sequence[_RelatedEvent], Optional[StreamToken]]:
176177
"""Get a list of relations for an event, ordered by topological ordering.
177178
@@ -186,6 +187,7 @@ async def get_relations_for_event(
186187
oldest first (forwards).
187188
from_token: Fetch rows from the given token, or from the start if None.
188189
to_token: Fetch rows up to the given token, or up to the end if None.
190+
recurse: Whether to recursively find relations.
189191
190192
Returns:
191193
A tuple of:
@@ -200,7 +202,7 @@ async def get_relations_for_event(
200202
# Ensure bad limits aren't being passed in.
201203
assert limit >= 0
202204

203-
where_clause = ["relates_to_id = ?", "room_id = ?"]
205+
where_clause = ["room_id = ?"]
204206
where_args: List[Union[str, int]] = [event.event_id, room_id]
205207
is_redacted = event.internal_metadata.is_redacted()
206208

@@ -229,18 +231,42 @@ async def get_relations_for_event(
229231
if pagination_clause:
230232
where_clause.append(pagination_clause)
231233

232-
sql = """
233-
SELECT event_id, relation_type, sender, topological_ordering, stream_ordering
234-
FROM event_relations
235-
INNER JOIN events USING (event_id)
236-
WHERE %s
237-
ORDER BY topological_ordering %s, stream_ordering %s
238-
LIMIT ?
239-
""" % (
240-
" AND ".join(where_clause),
241-
order,
242-
order,
243-
)
234+
# TODO This needs to be a recursive query that maybe still matches some of the times above.
235+
if recurse:
236+
sql = """
237+
WITH RECURSIVE related_events AS (
238+
SELECT event_id, relation_type, relates_to_id, 0 depth
239+
FROM event_relations
240+
WHERE relates_to_id = ?
241+
UNION SELECT e.event_id, e.relation_type, e.relates_to_id, depth + 1
242+
FROM event_relations e
243+
INNER JOIN related_events r ON r.event_id = e.relates_to_id
244+
WHERE depth <= 3
245+
)
246+
SELECT event_id, relation_type, sender, topological_ordering, stream_ordering
247+
FROM related_events
248+
INNER JOIN events USING (event_id)
249+
WHERE %s
250+
ORDER BY topological_ordering %s, stream_ordering %s
251+
LIMIT ?;
252+
""" % (
253+
" AND ".join(where_clause),
254+
order,
255+
order,
256+
)
257+
else:
258+
sql = """
259+
SELECT event_id, relation_type, sender, topological_ordering, stream_ordering
260+
FROM event_relations
261+
INNER JOIN events USING (event_id)
262+
WHERE relates_to_id = ? AND %s
263+
ORDER BY topological_ordering %s, stream_ordering %s
264+
LIMIT ?
265+
""" % (
266+
" AND ".join(where_clause),
267+
order,
268+
order,
269+
)
244270

245271
def _get_recent_references_for_event_txn(
246272
txn: LoggingTransaction,

0 commit comments

Comments
 (0)