Skip to content

Commit b1ef15c

Browse files
mgoldenbergHywan
authored andcommitted
refactor(indexeddb): add helper fns for EventCacheStore::handle_linked_chunk_updates
Signed-off-by: Michael Goldenberg <[email protected]>
1 parent 829b6a7 commit b1ef15c

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

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

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,4 +393,184 @@ impl<'a> IndexeddbEventCacheStoreTransaction<'a> {
393393
{
394394
self.transaction.object_store(T::OBJECT_STORE)?.clear()?.await.map_err(Into::into)
395395
}
396+
397+
/// Query IndexedDB for chunks that match the given chunk identifier in the
398+
/// given room. If more than one item is found, an error is returned.
399+
pub async fn get_chunk_by_id(
400+
&self,
401+
room_id: &RoomId,
402+
chunk_id: &ChunkIdentifier,
403+
) -> Result<Option<Chunk>, IndexeddbEventCacheStoreTransactionError> {
404+
self.get_item_by_key_components::<Chunk, IndexedChunkIdKey>(room_id, chunk_id).await
405+
}
406+
407+
/// Add a chunk to the given room and ensure that the next and previous
408+
/// chunks are properly linked to the chunk being added. If a chunk with
409+
/// the same identifier already exists, the given chunk will be
410+
/// rejected.
411+
pub async fn add_chunk(
412+
&self,
413+
room_id: &RoomId,
414+
chunk: &Chunk,
415+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
416+
self.add_item(room_id, chunk).await?;
417+
if let Some(previous) = chunk.previous {
418+
let previous_identifier = ChunkIdentifier::new(previous);
419+
if let Some(mut previous_chunk) =
420+
self.get_chunk_by_id(room_id, &previous_identifier).await?
421+
{
422+
previous_chunk.next = Some(chunk.identifier);
423+
self.put_item(room_id, &previous_chunk).await?;
424+
}
425+
}
426+
if let Some(next) = chunk.next {
427+
let next_identifier = ChunkIdentifier::new(next);
428+
if let Some(mut next_chunk) = self.get_chunk_by_id(room_id, &next_identifier).await? {
429+
next_chunk.previous = Some(chunk.identifier);
430+
self.put_item(room_id, &next_chunk).await?;
431+
}
432+
}
433+
Ok(())
434+
}
435+
436+
/// Delete chunk that matches the given id in the given room and ensure that
437+
/// the next and previous chunk are updated to link to one another.
438+
/// Additionally, ensure that events and gaps in the given chunk are
439+
/// also deleted.
440+
pub async fn delete_chunk_by_id(
441+
&self,
442+
room_id: &RoomId,
443+
chunk_id: &ChunkIdentifier,
444+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
445+
if let Some(chunk) = self.get_chunk_by_id(room_id, chunk_id).await? {
446+
if let Some(previous) = chunk.previous {
447+
let previous_identifier = ChunkIdentifier::new(previous);
448+
if let Some(mut previous_chunk) =
449+
self.get_chunk_by_id(room_id, &previous_identifier).await?
450+
{
451+
previous_chunk.next = chunk.next;
452+
self.put_item(room_id, &previous_chunk).await?;
453+
}
454+
}
455+
if let Some(next) = chunk.next {
456+
let next_identifier = ChunkIdentifier::new(next);
457+
if let Some(mut next_chunk) =
458+
self.get_chunk_by_id(room_id, &next_identifier).await?
459+
{
460+
next_chunk.previous = chunk.previous;
461+
self.put_item(room_id, &next_chunk).await?;
462+
}
463+
}
464+
self.delete_item_by_key::<Chunk, IndexedChunkIdKey>(room_id, chunk_id).await?;
465+
match chunk.chunk_type {
466+
ChunkType::Event => {
467+
self.delete_events_by_chunk(room_id, chunk_id).await?;
468+
}
469+
ChunkType::Gap => {
470+
self.delete_gap_by_id(room_id, chunk_id).await?;
471+
}
472+
}
473+
}
474+
Ok(())
475+
}
476+
477+
/// Delete all chunks in the given room
478+
pub async fn delete_chunks_in_room(
479+
&self,
480+
room_id: &RoomId,
481+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
482+
self.delete_items_in_room::<Chunk, IndexedChunkIdKey>(room_id).await
483+
}
484+
485+
/// Puts an event in the given room. If an event with the same key already
486+
/// exists, it will be overwritten.
487+
pub async fn put_event(
488+
&self,
489+
room_id: &RoomId,
490+
event: &Event,
491+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
492+
if let Some(position) = event.position() {
493+
// For some reason, we can't simply replace an event with `put_item`
494+
// because we can get an error stating that the data violates a uniqueness
495+
// constraint on the `events_position` index. This is NOT expected, but
496+
// it is not clear if this improperly implemented in the browser or the
497+
// library we are using.
498+
//
499+
// As a workaround, if the event has a position, we delete it first and
500+
// then call `put_item`. This should be fine as it all happens within the
501+
// context of a single transaction.
502+
self.delete_event_by_position(room_id, &position).await?;
503+
}
504+
self.put_item(room_id, event).await
505+
}
506+
507+
/// Delete events in the given position range in the given room
508+
pub async fn delete_events_by_position(
509+
&self,
510+
room_id: &RoomId,
511+
range: impl Into<IndexedKeyRange<&Position>>,
512+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
513+
self.delete_items_by_key_components::<Event, IndexedEventPositionKey>(room_id, range).await
514+
}
515+
516+
/// Delete event in the given position in the given room
517+
pub async fn delete_event_by_position(
518+
&self,
519+
room_id: &RoomId,
520+
position: &Position,
521+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
522+
self.delete_item_by_key::<Event, IndexedEventPositionKey>(room_id, position).await
523+
}
524+
525+
/// Delete events in the given chunk in the given room
526+
pub async fn delete_events_by_chunk(
527+
&self,
528+
room_id: &RoomId,
529+
chunk_id: &ChunkIdentifier,
530+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
531+
let mut lower = IndexedEventPositionKey::lower_key_components();
532+
lower.chunk_identifier = chunk_id.index();
533+
let mut upper = IndexedEventPositionKey::upper_key_components();
534+
upper.chunk_identifier = chunk_id.index();
535+
let range = IndexedKeyRange::Bound(&lower, &upper);
536+
self.delete_events_by_position(room_id, range).await
537+
}
538+
539+
/// Delete events starting from the given position in the given room
540+
/// until the end of the chunk
541+
pub async fn delete_events_by_chunk_from_index(
542+
&self,
543+
room_id: &RoomId,
544+
position: &Position,
545+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
546+
let mut upper = IndexedEventPositionKey::upper_key_components();
547+
upper.chunk_identifier = position.chunk_identifier;
548+
let range = IndexedKeyRange::Bound(position, &upper);
549+
self.delete_events_by_position(room_id, range).await
550+
}
551+
552+
/// Delete all events in the given room
553+
pub async fn delete_events_in_room(
554+
&self,
555+
room_id: &RoomId,
556+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
557+
self.delete_items_in_room::<Event, IndexedEventIdKey>(room_id).await
558+
}
559+
560+
/// Delete gap that matches the given chunk identifier in the given room
561+
pub async fn delete_gap_by_id(
562+
&self,
563+
room_id: &RoomId,
564+
chunk_id: &ChunkIdentifier,
565+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
566+
self.delete_item_by_key::<Gap, IndexedGapIdKey>(room_id, chunk_id).await
567+
}
568+
569+
/// Delete all gaps in the given room
570+
pub async fn delete_gaps_in_room(
571+
&self,
572+
room_id: &RoomId,
573+
) -> Result<(), IndexeddbEventCacheStoreTransactionError> {
574+
self.delete_items_in_room::<Gap, IndexedGapIdKey>(room_id).await
575+
}
396576
}

0 commit comments

Comments
 (0)