-- Phase 10: relations (threads, edits, reactions, references) and -- full-text search. -- content.m.relates_to of each event, written out so that "the children of -- this event" is an index lookup. Both are '' for an event that relates to -- nothing, and are cleared when the event is redacted: the redaction -- algorithm strips the content they came from. ALTER TABLE roomserver_events ADD COLUMN relates_to_id TEXT NOT NULL DEFAULT ''; ALTER TABLE roomserver_events ADD COLUMN rel_type TEXT NOT NULL DEFAULT ''; -- The events already stored. Only a relation with both fields a string -- counts, which is the rule the roomserver applies to new events. UPDATE roomserver_events SET relates_to_id = json_extract(event_json, '$.content."m.relates_to".event_id'), rel_type = json_extract(event_json, '$.content."m.relates_to".rel_type') WHERE redacted_by = '' AND json_type(event_json, '$.content."m.relates_to".event_id') = 'text' AND json_type(event_json, '$.content."m.relates_to".rel_type') = 'text'; -- /relations, the bundled summaries and /threads all start from a parent -- and read its children in stream order. CREATE INDEX IF NOT EXISTS roomserver_events_relations_idx ON roomserver_events (room_id, relates_to_id, rel_type, stream_ordering); -- The full-text index /search reads: one row per searchable event, keyed by -- the event's stream ordering as its rowid, which is unique across the -- server and is what a redaction finds the row by. Outliers are not here: -- an event joins the index when it joins a timeline. -- -- unicode61 with diacritics removed matches "cafe" against "café", which is -- what a user searching a chat history expects. CREATE VIRTUAL TABLE IF NOT EXISTS roomserver_event_search USING fts5( body, room_id UNINDEXED, event_id UNINDEXED, search_key UNINDEXED, sender UNINDEXED, event_type UNINDEXED, tokenize = 'unicode61 remove_diacritics 2' ); INSERT INTO roomserver_event_search (rowid, body, room_id, event_id, search_key, sender, event_type) SELECT stream_ordering, json_extract(event_json, '$.content.body'), room_id, event_id, 'content.body', sender, event_type FROM roomserver_events WHERE event_type = 'm.room.message' AND NOT outlier AND redacted_by = '' AND json_type(event_json, '$.content.body') = 'text'; INSERT INTO roomserver_event_search (rowid, body, room_id, event_id, search_key, sender, event_type) SELECT stream_ordering, json_extract(event_json, '$.content.name'), room_id, event_id, 'content.name', sender, event_type FROM roomserver_events WHERE event_type = 'm.room.name' AND NOT outlier AND redacted_by = '' AND json_type(event_json, '$.content.name') = 'text'; INSERT INTO roomserver_event_search (rowid, body, room_id, event_id, search_key, sender, event_type) SELECT stream_ordering, json_extract(event_json, '$.content.topic'), room_id, event_id, 'content.topic', sender, event_type FROM roomserver_events WHERE event_type = 'm.room.topic' AND NOT outlier AND redacted_by = '' AND json_type(event_json, '$.content.topic') = 'text';