1use std::ops::Deref;
16
17use indexed_db_futures::transaction as inner;
18use matrix_sdk_base::{
19 event_cache::{Event as RawEvent, Gap as RawGap},
20 linked_chunk::{ChunkContent, ChunkIdentifier, LinkedChunkId, RawChunk},
21};
22use ruma::{EventId, RoomId, events::relation::RelationType};
23use serde::{Serialize, de::DeserializeOwned};
24
25use crate::{
26 error::AsyncErrorDeps,
27 event_cache_store::{
28 serializer::indexed_types::{
29 IndexedChunk, IndexedChunkIdKey, IndexedEvent, IndexedEventIdKey,
30 IndexedEventPositionKey, IndexedEventRelationKey, IndexedEventRoomKey, IndexedGapIdKey,
31 IndexedLease, IndexedLeaseIdKey, IndexedNextChunkIdKey,
32 },
33 types::{Chunk, ChunkType, Event, Gap, Lease, Position},
34 },
35 serializer::indexed_type::{
36 IndexedTypeSerializer,
37 range::IndexedKeyRange,
38 traits::{Indexed, IndexedPrefixKeyBounds, IndexedPrefixKeyComponentBounds},
39 },
40 transaction::{Transaction, TransactionError},
41};
42
43pub struct IndexeddbEventCacheStoreTransaction<'a> {
47 transaction: Transaction<'a>,
48}
49
50impl<'a> Deref for IndexeddbEventCacheStoreTransaction<'a> {
51 type Target = Transaction<'a>;
52
53 fn deref(&self) -> &Self::Target {
54 &self.transaction
55 }
56}
57
58impl<'a> IndexeddbEventCacheStoreTransaction<'a> {
59 pub fn new(transaction: inner::Transaction<'a>, serializer: &'a IndexedTypeSerializer) -> Self {
60 Self { transaction: Transaction::new(transaction, serializer) }
61 }
62
63 pub async fn commit(self) -> Result<(), TransactionError> {
65 self.transaction.commit().await
66 }
67
68 pub async fn get_items_by_linked_chunk_id<'b, T, K>(
71 &self,
72 linked_chunk_id: LinkedChunkId<'b>,
73 ) -> Result<Vec<T>, TransactionError>
74 where
75 T: Indexed,
76 T::IndexedType: DeserializeOwned,
77 T::Error: AsyncErrorDeps,
78 K: IndexedPrefixKeyBounds<T, LinkedChunkId<'b>> + Serialize,
79 {
80 self.get_items_by_key::<T, K>(IndexedKeyRange::all_with_prefix(
81 linked_chunk_id,
82 self.serializer().inner(),
83 ))
84 .await
85 }
86
87 pub async fn get_items_in_room<'b, T, K>(
89 &self,
90 room_id: &'b RoomId,
91 ) -> Result<Vec<T>, TransactionError>
92 where
93 T: Indexed,
94 T::IndexedType: DeserializeOwned,
95 T::Error: AsyncErrorDeps,
96 K: IndexedPrefixKeyBounds<T, &'b RoomId> + Serialize,
97 {
98 self.get_items_by_key::<T, K>(IndexedKeyRange::all_with_prefix(
99 room_id,
100 self.serializer().inner(),
101 ))
102 .await
103 }
104
105 pub async fn get_items_count_by_linked_chunk_id<'b, T, K>(
108 &self,
109 linked_chunk_id: LinkedChunkId<'b>,
110 ) -> Result<usize, TransactionError>
111 where
112 T: Indexed,
113 T::IndexedType: DeserializeOwned,
114 T::Error: AsyncErrorDeps,
115 K: IndexedPrefixKeyBounds<T, LinkedChunkId<'b>> + Serialize,
116 {
117 self.get_items_count_by_key::<T, K>(IndexedKeyRange::all_with_prefix(
118 linked_chunk_id,
119 self.serializer().inner(),
120 ))
121 .await
122 }
123
124 pub async fn delete_items_by_linked_chunk_id<'b, T, K>(
127 &self,
128 linked_chunk_id: LinkedChunkId<'b>,
129 ) -> Result<(), TransactionError>
130 where
131 T: Indexed,
132 K: IndexedPrefixKeyBounds<T, LinkedChunkId<'b>> + Serialize,
133 {
134 self.delete_items_by_key::<T, K>(IndexedKeyRange::all_with_prefix(
135 linked_chunk_id,
136 self.serializer().inner(),
137 ))
138 .await
139 }
140
141 pub async fn get_lease_by_id(&self, id: &str) -> Result<Option<Lease>, TransactionError> {
144 self.get_item_by_key_components::<Lease, IndexedLeaseIdKey>(id).await
145 }
146
147 pub async fn put_lease(&self, lease: &Lease) -> Result<IndexedLease, TransactionError> {
152 self.put_item(lease).await
153 }
154
155 pub async fn get_chunk_by_id(
159 &self,
160 linked_chunk_id: LinkedChunkId<'_>,
161 chunk_id: ChunkIdentifier,
162 ) -> Result<Option<Chunk>, TransactionError> {
163 self.get_item_by_key_components::<Chunk, IndexedChunkIdKey>((linked_chunk_id, chunk_id))
164 .await
165 }
166
167 pub async fn get_chunk_by_next_chunk_id(
171 &self,
172 linked_chunk_id: LinkedChunkId<'_>,
173 next_chunk_id: Option<ChunkIdentifier>,
174 ) -> Result<Option<Chunk>, TransactionError> {
175 self.get_item_by_key_components::<Chunk, IndexedNextChunkIdKey>((
176 linked_chunk_id,
177 next_chunk_id,
178 ))
179 .await
180 }
181
182 pub async fn get_chunks_by_linked_chunk_id(
184 &self,
185 linked_chunk_id: LinkedChunkId<'_>,
186 ) -> Result<Vec<Chunk>, TransactionError> {
187 self.get_items_by_linked_chunk_id::<Chunk, IndexedChunkIdKey>(linked_chunk_id).await
188 }
189
190 pub async fn get_chunks_count_by_linked_chunk_id(
193 &self,
194 linked_chunk_id: LinkedChunkId<'_>,
195 ) -> Result<usize, TransactionError> {
196 self.get_items_count_by_linked_chunk_id::<Chunk, IndexedChunkIdKey>(linked_chunk_id).await
197 }
198
199 pub async fn get_max_chunk_by_id(
202 &self,
203 linked_chunk_id: LinkedChunkId<'_>,
204 ) -> Result<Option<Chunk>, TransactionError> {
205 let range = IndexedKeyRange::all_with_prefix::<Chunk, _>(
206 linked_chunk_id,
207 self.serializer().inner(),
208 );
209 self.get_max_item_by_key::<Chunk, IndexedChunkIdKey>(range).await
210 }
211
212 pub async fn load_chunk_by_id(
216 &self,
217 linked_chunk_id: LinkedChunkId<'_>,
218 chunk_id: ChunkIdentifier,
219 ) -> Result<Option<RawChunk<RawEvent, RawGap>>, TransactionError> {
220 if let Some(chunk) = self.get_chunk_by_id(linked_chunk_id, chunk_id).await? {
221 let content = match chunk.chunk_type {
222 ChunkType::Event => {
223 let events = self
224 .get_events_by_chunk(
225 linked_chunk_id,
226 ChunkIdentifier::new(chunk.identifier),
227 )
228 .await?
229 .into_iter()
230 .map(RawEvent::from)
231 .collect();
232 ChunkContent::Items(events)
233 }
234 ChunkType::Gap => {
235 let gap = self
236 .get_gap_by_id(linked_chunk_id, ChunkIdentifier::new(chunk.identifier))
237 .await?
238 .ok_or(TransactionError::ItemNotFound)?;
239 ChunkContent::Gap(RawGap { token: gap.token })
240 }
241 };
242 return Ok(Some(RawChunk {
243 identifier: ChunkIdentifier::new(chunk.identifier),
244 content,
245 previous: chunk.previous.map(ChunkIdentifier::new),
246 next: chunk.next.map(ChunkIdentifier::new),
247 }));
248 }
249 Ok(None)
250 }
251
252 pub async fn add_chunk(&self, chunk: &Chunk) -> Result<IndexedChunk, TransactionError> {
259 let indexed = self.add_item(chunk).await?;
260 if let Some(previous) = chunk.previous {
261 let previous_identifier = ChunkIdentifier::new(previous);
262 let mut previous_chunk = self
263 .get_chunk_by_id(chunk.linked_chunk_id.as_ref(), previous_identifier)
264 .await?
265 .ok_or(TransactionError::ItemNotFound)?;
266 previous_chunk.next = Some(chunk.identifier);
267 self.put_item(&previous_chunk).await?;
268 }
269 if let Some(next) = chunk.next {
270 let next_identifier = ChunkIdentifier::new(next);
271 let mut next_chunk = self
272 .get_chunk_by_id(chunk.linked_chunk_id.as_ref(), next_identifier)
273 .await?
274 .ok_or(TransactionError::ItemNotFound)?;
275 next_chunk.previous = Some(chunk.identifier);
276 self.put_item(&next_chunk).await?;
277 }
278 Ok(indexed)
279 }
280
281 pub async fn delete_chunk_by_id(
286 &self,
287 linked_chunk_id: LinkedChunkId<'_>,
288 chunk_id: ChunkIdentifier,
289 ) -> Result<(), TransactionError> {
290 if let Some(chunk) = self.get_chunk_by_id(linked_chunk_id, chunk_id).await? {
291 if let Some(previous) = chunk.previous {
292 let previous_identifier = ChunkIdentifier::new(previous);
293 if let Some(mut previous_chunk) =
294 self.get_chunk_by_id(linked_chunk_id, previous_identifier).await?
295 {
296 previous_chunk.next = chunk.next;
297 self.put_item(&previous_chunk).await?;
298 }
299 }
300 if let Some(next) = chunk.next {
301 let next_identifier = ChunkIdentifier::new(next);
302 if let Some(mut next_chunk) =
303 self.get_chunk_by_id(linked_chunk_id, next_identifier).await?
304 {
305 next_chunk.previous = chunk.previous;
306 self.put_item(&next_chunk).await?;
307 }
308 }
309 self.delete_item_by_key::<Chunk, IndexedChunkIdKey>((linked_chunk_id, chunk_id))
310 .await?;
311 match chunk.chunk_type {
312 ChunkType::Event => {
313 self.delete_events_by_chunk(linked_chunk_id, chunk_id).await?;
314 }
315 ChunkType::Gap => {
316 self.delete_gap_by_id(linked_chunk_id, chunk_id).await?;
317 }
318 }
319 }
320 Ok(())
321 }
322
323 pub async fn delete_chunks_by_linked_chunk_id(
325 &self,
326 linked_chunk_id: LinkedChunkId<'_>,
327 ) -> Result<(), TransactionError> {
328 self.delete_items_by_linked_chunk_id::<Chunk, IndexedChunkIdKey>(linked_chunk_id).await
329 }
330
331 pub async fn get_event_by_id(
334 &self,
335 linked_chunk_id: LinkedChunkId<'_>,
336 event_id: &EventId,
337 ) -> Result<Option<Event>, TransactionError> {
338 let key = self.serializer().encode_key((linked_chunk_id, event_id));
339 self.get_item_by_key::<Event, IndexedEventIdKey>(key).await
340 }
341
342 pub async fn get_event_by_room(
345 &self,
346 room_id: &RoomId,
347 event_id: &EventId,
348 ) -> Result<Option<Event>, TransactionError> {
349 let key = self.serializer().encode_key((room_id, event_id));
350 self.get_item_by_key::<Event, IndexedEventRoomKey>(key).await
351 }
352
353 pub async fn get_events_by_room(
356 &self,
357 room_id: &RoomId,
358 event_id: &EventId,
359 ) -> Result<Vec<Event>, TransactionError> {
360 let key: IndexedEventRoomKey = self.serializer().encode_key((room_id, event_id));
361 self.get_items_by_key::<Event, IndexedEventRoomKey>(key).await
362 }
363
364 pub async fn get_room_events(&self, room_id: &RoomId) -> Result<Vec<Event>, TransactionError> {
367 self.get_items_in_room::<Event, IndexedEventRoomKey>(room_id).await
368 }
369
370 pub async fn get_events_by_chunk(
373 &self,
374 linked_chunk_id: LinkedChunkId<'_>,
375 chunk_id: ChunkIdentifier,
376 ) -> Result<Vec<Event>, TransactionError> {
377 let range = IndexedKeyRange::all_with_prefix(
378 (linked_chunk_id, chunk_id),
379 self.serializer().inner(),
380 );
381 self.get_items_by_key::<Event, IndexedEventPositionKey>(range).await
382 }
383
384 pub async fn get_events_count_by_chunk(
387 &self,
388 linked_chunk_id: LinkedChunkId<'_>,
389 chunk_id: ChunkIdentifier,
390 ) -> Result<usize, TransactionError> {
391 let range = IndexedKeyRange::all_with_prefix(
392 (linked_chunk_id, chunk_id),
393 self.serializer().inner(),
394 );
395 self.get_items_count_by_key::<Event, IndexedEventPositionKey>(range).await
396 }
397
398 pub async fn get_events_by_relation(
401 &self,
402 room_id: &RoomId,
403 range: impl Into<IndexedKeyRange<(&EventId, &RelationType)>>,
404 ) -> Result<Vec<Event>, TransactionError> {
405 let range = range
406 .into()
407 .map(|(event_id, relation_type)| (room_id, event_id, relation_type))
408 .encoded(self.serializer().inner());
409 self.get_items_by_key::<Event, IndexedEventRelationKey>(range).await
410 }
411
412 pub async fn get_events_by_related_event(
415 &self,
416 room_id: &RoomId,
417 related_event_id: &EventId,
418 ) -> Result<Vec<Event>, TransactionError> {
419 let range = IndexedKeyRange::all_with_prefix(
420 (room_id, related_event_id),
421 self.serializer().inner(),
422 );
423 self.get_items_by_key::<Event, IndexedEventRelationKey>(range).await
424 }
425
426 pub async fn put_event(&self, event: &Event) -> Result<IndexedEvent, TransactionError> {
431 if let Some(position) = event.position() {
432 self.delete_event_by_position(event.linked_chunk_id(), position).await?;
442 }
443 self.put_item(event).await
444 }
445
446 pub async fn delete_events_by_position(
449 &self,
450 linked_chunk_id: LinkedChunkId<'_>,
451 range: impl Into<IndexedKeyRange<Position>>,
452 ) -> Result<(), TransactionError> {
453 self.delete_items_by_key_components::<Event, IndexedEventPositionKey>(
454 range.into().map(|position| (linked_chunk_id, position)),
455 )
456 .await
457 }
458
459 pub async fn delete_event_by_position(
461 &self,
462 linked_chunk_id: LinkedChunkId<'_>,
463 position: Position,
464 ) -> Result<(), TransactionError> {
465 self.delete_item_by_key::<Event, IndexedEventPositionKey>((linked_chunk_id, position)).await
466 }
467
468 pub async fn delete_events_by_chunk(
470 &self,
471 linked_chunk_id: LinkedChunkId<'_>,
472 chunk_id: ChunkIdentifier,
473 ) -> Result<(), TransactionError> {
474 let range = IndexedKeyRange::all_with_prefix(
475 (linked_chunk_id, chunk_id),
476 self.serializer().inner(),
477 );
478 self.delete_items_by_key::<Event, IndexedEventPositionKey>(range).await
479 }
480
481 pub async fn delete_events_by_chunk_from_index(
484 &self,
485 linked_chunk_id: LinkedChunkId<'_>,
486 position: Position,
487 ) -> Result<(), TransactionError> {
488 let lower = (linked_chunk_id, position);
489 let upper = IndexedEventPositionKey::upper_key_components_with_prefix((
490 linked_chunk_id,
491 ChunkIdentifier::new(position.chunk_identifier),
492 ));
493 let range = IndexedKeyRange::Bound(lower, upper).map(|(_, position)| position);
494 self.delete_events_by_position(linked_chunk_id, range).await
495 }
496
497 pub async fn delete_events_by_linked_chunk_id(
499 &self,
500 linked_chunk_id: LinkedChunkId<'_>,
501 ) -> Result<(), TransactionError> {
502 self.delete_items_by_linked_chunk_id::<Event, IndexedEventIdKey>(linked_chunk_id).await
503 }
504
505 pub async fn get_gap_by_id(
508 &self,
509 linked_chunk_id: LinkedChunkId<'_>,
510 chunk_id: ChunkIdentifier,
511 ) -> Result<Option<Gap>, TransactionError> {
512 self.get_item_by_key_components::<Gap, IndexedGapIdKey>((linked_chunk_id, chunk_id)).await
513 }
514
515 pub async fn delete_gap_by_id(
518 &self,
519 linked_chunk_id: LinkedChunkId<'_>,
520 chunk_id: ChunkIdentifier,
521 ) -> Result<(), TransactionError> {
522 self.delete_item_by_key::<Gap, IndexedGapIdKey>((linked_chunk_id, chunk_id)).await
523 }
524
525 pub async fn delete_gaps_by_linked_chunk_id(
527 &self,
528 linked_chunk_id: LinkedChunkId<'_>,
529 ) -> Result<(), TransactionError> {
530 self.delete_items_by_linked_chunk_id::<Gap, IndexedGapIdKey>(linked_chunk_id).await
531 }
532}