@@ -393,4 +393,184 @@ impl<'a> IndexeddbEventCacheStoreTransaction<'a> {
393
393
{
394
394
self . transaction . object_store ( T :: OBJECT_STORE ) ?. clear ( ) ?. await . map_err ( Into :: into)
395
395
}
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
+ }
396
576
}
0 commit comments