Skip to main content

atomr_persistence_redis/
codec.rs

1//! JSON payload shapes stored alongside the sequence number score.
2
3use atomr_persistence::{PersistentRepr, SnapshotMetadata};
4use base64::{engine::general_purpose::STANDARD as B64, Engine as _};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8pub struct StoredRepr {
9    pub persistence_id: String,
10    pub sequence_nr: u64,
11    pub payload_b64: String,
12    pub manifest: String,
13    pub writer_uuid: String,
14    pub deleted: bool,
15    pub tags: Vec<String>,
16}
17
18impl From<&PersistentRepr> for StoredRepr {
19    fn from(r: &PersistentRepr) -> Self {
20        Self {
21            persistence_id: r.persistence_id.clone(),
22            sequence_nr: r.sequence_nr,
23            payload_b64: B64.encode(&r.payload),
24            manifest: r.manifest.clone(),
25            writer_uuid: r.writer_uuid.clone(),
26            deleted: r.deleted,
27            tags: r.tags.clone(),
28        }
29    }
30}
31
32impl StoredRepr {
33    pub fn into_repr(self) -> PersistentRepr {
34        PersistentRepr {
35            persistence_id: self.persistence_id,
36            sequence_nr: self.sequence_nr,
37            payload: B64.decode(self.payload_b64).unwrap_or_default(),
38            manifest: self.manifest,
39            writer_uuid: self.writer_uuid,
40            deleted: self.deleted,
41            tags: self.tags,
42        }
43    }
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct StoredSnapshot {
48    pub persistence_id: String,
49    pub sequence_nr: u64,
50    pub timestamp: u64,
51    pub payload_b64: String,
52}
53
54impl StoredSnapshot {
55    pub fn new(meta: &SnapshotMetadata, payload: &[u8]) -> Self {
56        Self {
57            persistence_id: meta.persistence_id.clone(),
58            sequence_nr: meta.sequence_nr,
59            timestamp: meta.timestamp,
60            payload_b64: B64.encode(payload),
61        }
62    }
63
64    pub fn into_parts(self) -> (SnapshotMetadata, Vec<u8>) {
65        let payload = B64.decode(self.payload_b64).unwrap_or_default();
66        (
67            SnapshotMetadata {
68                persistence_id: self.persistence_id,
69                sequence_nr: self.sequence_nr,
70                timestamp: self.timestamp,
71            },
72            payload,
73        )
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn round_trip_repr() {
83        let original = PersistentRepr {
84            persistence_id: "p1".into(),
85            sequence_nr: 7,
86            payload: vec![0, 1, 2, 255],
87            manifest: "m".into(),
88            writer_uuid: "w".into(),
89            deleted: false,
90            tags: vec!["t1".into()],
91        };
92        let stored = StoredRepr::from(&original);
93        let back = stored.into_repr();
94        assert_eq!(back.persistence_id, original.persistence_id);
95        assert_eq!(back.sequence_nr, original.sequence_nr);
96        assert_eq!(back.payload, original.payload);
97        assert_eq!(back.tags, original.tags);
98    }
99
100    #[test]
101    fn round_trip_snapshot() {
102        let meta = SnapshotMetadata { persistence_id: "p".into(), sequence_nr: 9, timestamp: 100 };
103        let payload = b"state".to_vec();
104        let stored = StoredSnapshot::new(&meta, &payload);
105        let (m, p) = stored.into_parts();
106        assert_eq!(m.sequence_nr, 9);
107        assert_eq!(p, payload);
108    }
109}