Skip to content

Commit 1a32aa5

Browse files
mgoldenbergHywan
authored andcommitted
refactor(indexeddb): add indexing trait impls for event
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
1 parent a99df7e commit 1a32aa5

File tree

3 files changed

+198
-3
lines changed

3 files changed

+198
-3
lines changed

crates/matrix-sdk-indexeddb/src/event_cache_store/migrations.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ pub mod v1 {
120120
pub const EVENTS_POSITION_KEY_PATH: &str = "position";
121121
pub const EVENTS_RELATION: &str = "events_relation";
122122
pub const EVENTS_RELATION_KEY_PATH: &str = "relation";
123+
pub const EVENTS_RELATION_RELATED_EVENTS: &str = "events_relation_related_event";
124+
pub const EVENTS_RELATION_RELATION_TYPES: &str = "events_relation_relation_type";
123125
pub const GAPS: &str = "gaps";
124126
pub const GAPS_KEY_PATH: &str = "id";
125127
}

crates/matrix-sdk-indexeddb/src/event_cache_store/serializer/types.rs

Lines changed: 148 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,37 @@
2929
3030
use matrix_sdk_base::linked_chunk::ChunkIdentifier;
3131
use matrix_sdk_crypto::CryptoStoreError;
32-
use ruma::RoomId;
32+
use ruma::{events::relation::RelationType, EventId, OwnedEventId, RoomId};
3333
use serde::{Deserialize, Serialize};
34+
use thiserror::Error;
3435

3536
use crate::{
3637
event_cache_store::{
3738
migrations::current::keys,
3839
serializer::traits::{Indexed, IndexedKey, IndexedKeyBounds},
39-
types::Chunk,
40+
types::{Chunk, Event, Position},
4041
},
4142
serializer::{IndexeddbSerializer, MaybeEncrypted},
4243
};
4344

45+
/// The first unicode character, and hence the lower bound for IndexedDB keys
46+
/// (or key components) which are represented as strings.
47+
///
48+
/// This value is useful for constructing a key range over all strings when used
49+
/// in conjunction with [`INDEXED_KEY_UPPER_CHARACTER`].
50+
const INDEXED_KEY_LOWER_CHARACTER: char = '\u{0000}';
51+
52+
/// The last unicode character in the [Basic Multilingual Plane][1]. This seems
53+
/// like a reasonable place to set the upper bound for IndexedDB keys (or key
54+
/// components) which are represented as strings, though one could
55+
/// theoretically set it to `\u{10FFFF}`.
56+
///
57+
/// This value is useful for constructing a key range over all strings when used
58+
/// in conjunction with [`INDEXED_KEY_LOWER_CHARACTER`].
59+
///
60+
/// [1]: https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
61+
const INDEXED_KEY_UPPER_CHARACTER: char = '\u{FFFF}';
62+
4463
/// Represents the [`LINKED_CHUNKS`][1] object store.
4564
///
4665
/// [1]: crate::event_cache_store::migrations::v1::create_linked_chunks_object_store
@@ -206,6 +225,46 @@ pub struct IndexedEvent {
206225
pub content: IndexedEventContent,
207226
}
208227

228+
#[derive(Debug, Error)]
229+
pub enum IndexedEventError {
230+
#[error("no event id")]
231+
NoEventId,
232+
#[error("crypto store: {0}")]
233+
CryptoStore(#[from] CryptoStoreError),
234+
}
235+
236+
impl Indexed for Event {
237+
type IndexedType = IndexedEvent;
238+
type Error = IndexedEventError;
239+
240+
fn to_indexed(
241+
&self,
242+
room_id: &RoomId,
243+
serializer: &IndexeddbSerializer,
244+
) -> Result<Self::IndexedType, Self::Error> {
245+
let event_id = self.event_id().ok_or(Self::Error::NoEventId)?;
246+
let id = IndexedEventIdKey::encode(room_id, &event_id, serializer);
247+
let position = self
248+
.position()
249+
.map(|position| IndexedEventPositionKey::encode(room_id, &position, serializer));
250+
let relation = self.relation().map(|(related_event, relation_type)| {
251+
IndexedEventRelationKey::encode(
252+
room_id,
253+
&(related_event, RelationType::from(relation_type)),
254+
serializer,
255+
)
256+
});
257+
Ok(IndexedEvent { id, position, relation, content: serializer.maybe_encrypt_value(self)? })
258+
}
259+
260+
fn from_indexed(
261+
indexed: Self::IndexedType,
262+
serializer: &IndexeddbSerializer,
263+
) -> Result<Self, Self::Error> {
264+
serializer.maybe_decrypt_value(indexed.content).map_err(Into::into)
265+
}
266+
}
267+
209268
/// The value associated with the [primary key](IndexedEvent::id) of the
210269
/// [`EVENTS`][1] object store, which is constructed from:
211270
///
@@ -216,6 +275,30 @@ pub struct IndexedEvent {
216275
#[derive(Debug, Serialize, Deserialize)]
217276
pub struct IndexedEventIdKey(IndexedRoomId, IndexedEventId);
218277

278+
impl IndexedKey<Event> for IndexedEventIdKey {
279+
type KeyComponents = OwnedEventId;
280+
281+
fn encode(room_id: &RoomId, event_id: &OwnedEventId, serializer: &IndexeddbSerializer) -> Self {
282+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
283+
let event_id = serializer.encode_key_as_string(keys::EVENTS, event_id);
284+
Self(room_id, event_id)
285+
}
286+
}
287+
288+
impl IndexedKeyBounds<Event> for IndexedEventIdKey {
289+
fn encode_lower(room_id: &RoomId, serializer: &IndexeddbSerializer) -> Self {
290+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
291+
let event_id = String::from(INDEXED_KEY_LOWER_CHARACTER);
292+
Self(room_id, event_id)
293+
}
294+
295+
fn encode_upper(room_id: &RoomId, serializer: &IndexeddbSerializer) -> Self {
296+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
297+
let event_id = String::from(INDEXED_KEY_UPPER_CHARACTER);
298+
Self(room_id, event_id)
299+
}
300+
}
301+
219302
pub type IndexedEventId = String;
220303

221304
/// The value associated with the [`position`](IndexedEvent::position) index of
@@ -229,6 +312,36 @@ pub type IndexedEventId = String;
229312
#[derive(Debug, Serialize, Deserialize)]
230313
pub struct IndexedEventPositionKey(IndexedRoomId, IndexedChunkId, IndexedEventPositionIndex);
231314

315+
impl IndexedKey<Event> for IndexedEventPositionKey {
316+
type KeyComponents = Position;
317+
318+
fn encode(room_id: &RoomId, position: &Position, serializer: &IndexeddbSerializer) -> Self {
319+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
320+
Self(room_id, position.chunk_identifier, position.index)
321+
}
322+
}
323+
324+
impl IndexedKeyBounds<Event> for IndexedEventPositionKey {
325+
fn encode_lower(room_id: &RoomId, serializer: &IndexeddbSerializer) -> Self {
326+
<Self as IndexedKey<Event>>::encode(
327+
room_id,
328+
&Position { chunk_identifier: 0, index: 0 },
329+
serializer,
330+
)
331+
}
332+
333+
fn encode_upper(room_id: &RoomId, serializer: &IndexeddbSerializer) -> Self {
334+
<Self as IndexedKey<Event>>::encode(
335+
room_id,
336+
&Position {
337+
chunk_identifier: js_sys::Number::MAX_SAFE_INTEGER as u64,
338+
index: js_sys::Number::MAX_SAFE_INTEGER as usize,
339+
},
340+
serializer,
341+
)
342+
}
343+
}
344+
232345
pub type IndexedEventPositionIndex = usize;
233346

234347
/// The value associated with the [`relation`](IndexedEvent::relation) index of
@@ -242,6 +355,39 @@ pub type IndexedEventPositionIndex = usize;
242355
#[derive(Debug, Serialize, Deserialize)]
243356
pub struct IndexedEventRelationKey(IndexedRoomId, IndexedEventId, IndexedRelationType);
244357

358+
impl IndexedKey<Event> for IndexedEventRelationKey {
359+
type KeyComponents = (OwnedEventId, RelationType);
360+
361+
fn encode(
362+
room_id: &RoomId,
363+
(related_event_id, relation_type): &(OwnedEventId, RelationType),
364+
serializer: &IndexeddbSerializer,
365+
) -> Self {
366+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
367+
let related_event_id =
368+
serializer.encode_key_as_string(keys::EVENTS_RELATION_RELATED_EVENTS, related_event_id);
369+
let relation_type = serializer
370+
.encode_key_as_string(keys::EVENTS_RELATION_RELATION_TYPES, relation_type.to_string());
371+
Self(room_id, related_event_id, relation_type)
372+
}
373+
}
374+
375+
impl IndexedKeyBounds<Event> for IndexedEventRelationKey {
376+
fn encode_lower(room_id: &RoomId, serializer: &IndexeddbSerializer) -> Self {
377+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
378+
let related_event_id = String::from(INDEXED_KEY_LOWER_CHARACTER);
379+
let relation_type = String::from(INDEXED_KEY_LOWER_CHARACTER);
380+
Self(room_id, related_event_id, relation_type)
381+
}
382+
383+
fn encode_upper(room_id: &RoomId, serializer: &IndexeddbSerializer) -> Self {
384+
let room_id = serializer.encode_key_as_string(keys::ROOMS, room_id);
385+
let related_event_id = String::from(INDEXED_KEY_UPPER_CHARACTER);
386+
let relation_type = String::from(INDEXED_KEY_UPPER_CHARACTER);
387+
Self(room_id, related_event_id, relation_type)
388+
}
389+
}
390+
245391
/// A representation of the relationship between two events (see
246392
/// [`RelationType`](ruma::events::relation::RelationType))
247393
pub type IndexedRelationType = String;

crates/matrix-sdk-indexeddb/src/event_cache_store/types.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use matrix_sdk_base::{deserialized_responses::TimelineEvent, linked_chunk::ChunkIdentifier};
1+
use matrix_sdk_base::{
2+
deserialized_responses::TimelineEvent, event_cache::store::extract_event_relation,
3+
linked_chunk::ChunkIdentifier,
4+
};
5+
use ruma::OwnedEventId;
26
use serde::{Deserialize, Serialize};
37

48
/// Representation of a [`Chunk`](matrix_sdk_base::linked_chunk::Chunk)
@@ -50,6 +54,34 @@ impl From<Event> for TimelineEvent {
5054
}
5155
}
5256

57+
impl Event {
58+
/// The [`OwnedEventId`] of the underlying event.
59+
pub fn event_id(&self) -> Option<OwnedEventId> {
60+
match self {
61+
Event::InBand(e) => e.event_id(),
62+
Event::OutOfBand(e) => e.event_id(),
63+
}
64+
}
65+
66+
/// The [`Position`] of the underlying event, if it is in a chunk.
67+
pub fn position(&self) -> Option<Position> {
68+
match self {
69+
Event::InBand(e) => Some(e.position),
70+
Event::OutOfBand(_) => None,
71+
}
72+
}
73+
74+
/// The [`OwnedEventId`] and
75+
/// [`RelationType`](ruma::events::relation::RelationType) of the underlying
76+
/// event as a [`String`].
77+
pub fn relation(&self) -> Option<(OwnedEventId, String)> {
78+
match self {
79+
Event::InBand(e) => e.relation(),
80+
Event::OutOfBand(e) => e.relation(),
81+
}
82+
}
83+
}
84+
5385
/// A generic representation of an
5486
/// [`Event`](matrix_sdk_base::event_cache::Event) which can be stored in
5587
/// IndexedDB.
@@ -64,6 +96,21 @@ pub struct GenericEvent<P> {
6496
pub position: P,
6597
}
6698

99+
impl<P> GenericEvent<P> {
100+
/// The [`OwnedEventId`] of the underlying event.
101+
pub fn event_id(&self) -> Option<OwnedEventId> {
102+
self.content.event_id()
103+
}
104+
105+
/// The event that the underlying event relates to, if any.
106+
///
107+
/// Returns the related [`OwnedEventId`] and the
108+
/// [`RelationType`](ruma::events::relation::RelationType) as a [`String`].
109+
pub fn relation(&self) -> Option<(OwnedEventId, String)> {
110+
extract_event_relation(self.content.raw())
111+
}
112+
}
113+
67114
/// A concrete instance of [`GenericEvent`] for in-band events, i.e.,
68115
/// events which are part of a chunk and therefore have a position.
69116
pub type InBandEvent = GenericEvent<Position>;

0 commit comments

Comments
 (0)