surreal_sync_core/checkpoint/
snapshot.rs1use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct SnapshotTableProgress {
19 pub name: String,
21 pub last_pk: Option<serde_json::Value>,
26 pub done: bool,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub struct InterleavedSnapshotCheckpoint {
34 #[serde(alias = "stream_pos")]
40 pub reconciliation_pos: serde_json::Value,
41 pub tables: Vec<SnapshotTableProgress>,
43}
44
45impl InterleavedSnapshotCheckpoint {
46 pub fn new(reconciliation_pos: serde_json::Value, tables: Vec<SnapshotTableProgress>) -> Self {
48 Self {
49 reconciliation_pos,
50 tables,
51 }
52 }
53
54 pub fn all_done(&self) -> bool {
56 self.tables.iter().all(|t| t.done)
57 }
58}
59
60impl crate::checkpoint::Checkpoint for InterleavedSnapshotCheckpoint {
61 const DATABASE_TYPE: &'static str = "interleaved_snapshot";
62
63 fn to_cli_string(&self) -> String {
64 serde_json::to_string(self).unwrap_or_default()
65 }
66
67 fn from_cli_string(s: &str) -> anyhow::Result<Self> {
68 Ok(serde_json::from_str(s)?)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use crate::checkpoint::{Checkpoint, CheckpointFile, SyncPhase};
76
77 fn sample() -> InterleavedSnapshotCheckpoint {
78 InterleavedSnapshotCheckpoint::new(
79 serde_json::json!("0/16B3748"),
80 vec![
81 SnapshotTableProgress {
82 name: "users".to_string(),
83 last_pk: Some(serde_json::json!([{ "type": "Int64", "value": 42 }])),
84 done: false,
85 },
86 SnapshotTableProgress {
87 name: "orders".to_string(),
88 last_pk: None,
89 done: true,
90 },
91 ],
92 )
93 }
94
95 #[test]
96 fn cli_string_roundtrip() {
97 let original = sample();
98 let s = original.to_cli_string();
99 let decoded = InterleavedSnapshotCheckpoint::from_cli_string(&s).unwrap();
100 assert_eq!(original, decoded);
101 }
102
103 #[test]
104 fn checkpoint_file_roundtrip() {
105 let original = sample();
106 let file = CheckpointFile::new(&original, SyncPhase::SnapshotProgress).unwrap();
107 assert_eq!(
108 file.database_type(),
109 InterleavedSnapshotCheckpoint::DATABASE_TYPE
110 );
111 let decoded: InterleavedSnapshotCheckpoint = file.parse().unwrap();
112 assert_eq!(original, decoded);
113 }
114
115 #[test]
116 fn all_done_reflects_table_state() {
117 let mut cp = sample();
118 assert!(!cp.all_done());
119 for t in &mut cp.tables {
120 t.done = true;
121 }
122 assert!(cp.all_done());
123 }
124}