checkpoint.rs (3373B)
1 #![allow(clippy::module_name_repetitions)] 2 #[cfg(not(feature = "std"))] 3 use alloc::{string::String, vec::Vec}; 4 5 use crate::types::RadrootsEventsIndexedShardId; 6 7 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 8 #[derive(Clone, Debug, PartialEq, Eq)] 9 pub struct RadrootsEventsIndexedShardCheckpoint { 10 pub shard_id: RadrootsEventsIndexedShardId, 11 #[cfg_attr( 12 feature = "serde", 13 serde(deserialize_with = "crate::serde_ext::epoch_seconds::de") 14 )] 15 pub last_created_at: u32, 16 pub last_event_id: Option<String>, 17 pub cursor: Option<String>, 18 } 19 20 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 21 #[derive(Clone, Debug, PartialEq, Eq)] 22 pub struct RadrootsEventsIndexedIndexCheckpoint { 23 #[cfg_attr( 24 feature = "serde", 25 serde(deserialize_with = "crate::serde_ext::epoch_seconds::de") 26 )] 27 pub generated_at: u32, 28 pub shards: Vec<RadrootsEventsIndexedShardCheckpoint>, 29 } 30 31 impl RadrootsEventsIndexedIndexCheckpoint { 32 pub fn get( 33 &self, 34 id: &RadrootsEventsIndexedShardId, 35 ) -> Option<&RadrootsEventsIndexedShardCheckpoint> { 36 self.shards.iter().find(|s| &s.shard_id == id) 37 } 38 pub fn upsert(&mut self, cp: RadrootsEventsIndexedShardCheckpoint) { 39 if let Some(slot) = self.shards.iter_mut().find(|s| s.shard_id == cp.shard_id) { 40 *slot = cp; 41 } else { 42 self.shards.push(cp); 43 } 44 } 45 } 46 47 #[cfg(test)] 48 mod tests { 49 use super::{RadrootsEventsIndexedIndexCheckpoint, RadrootsEventsIndexedShardCheckpoint}; 50 use crate::types::RadrootsEventsIndexedShardId; 51 #[cfg(not(feature = "std"))] 52 use alloc::{string::String, vec, vec::Vec}; 53 #[cfg(feature = "std")] 54 use std::{string::String, vec::Vec}; 55 56 fn checkpoint( 57 shard_id: &str, 58 last_created_at: u32, 59 last_event_id: Option<&str>, 60 ) -> RadrootsEventsIndexedShardCheckpoint { 61 RadrootsEventsIndexedShardCheckpoint { 62 shard_id: RadrootsEventsIndexedShardId(String::from(shard_id)), 63 last_created_at, 64 last_event_id: last_event_id.map(String::from), 65 cursor: None, 66 } 67 } 68 69 #[test] 70 fn get_returns_none_for_unknown_shard() { 71 let cp = RadrootsEventsIndexedIndexCheckpoint { 72 generated_at: 1, 73 shards: vec![checkpoint("us-1", 10, Some("a"))], 74 }; 75 let missing = cp.get(&RadrootsEventsIndexedShardId(String::from("us-2"))); 76 assert!(missing.is_none()); 77 } 78 79 #[test] 80 fn upsert_inserts_and_updates_shards() { 81 let mut cp = RadrootsEventsIndexedIndexCheckpoint { 82 generated_at: 2, 83 shards: Vec::new(), 84 }; 85 86 cp.upsert(checkpoint("us-1", 10, Some("a"))); 87 assert_eq!(cp.shards.len(), 1); 88 assert_eq!( 89 cp.get(&RadrootsEventsIndexedShardId(String::from("us-1"))) 90 .expect("inserted shard") 91 .last_created_at, 92 10 93 ); 94 95 cp.upsert(checkpoint("us-1", 11, Some("b"))); 96 assert_eq!(cp.shards.len(), 1); 97 let updated = cp 98 .get(&RadrootsEventsIndexedShardId(String::from("us-1"))) 99 .expect("updated shard"); 100 assert_eq!(updated.last_created_at, 11); 101 assert_eq!(updated.last_event_id.as_deref(), Some("b")); 102 } 103 }