use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SnapshotTableProgress {
pub name: String,
pub last_pk: Option<serde_json::Value>,
pub done: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct InterleavedSnapshotCheckpoint {
#[serde(alias = "stream_pos")]
pub reconciliation_pos: serde_json::Value,
pub tables: Vec<SnapshotTableProgress>,
}
impl InterleavedSnapshotCheckpoint {
pub fn new(reconciliation_pos: serde_json::Value, tables: Vec<SnapshotTableProgress>) -> Self {
Self {
reconciliation_pos,
tables,
}
}
pub fn all_done(&self) -> bool {
self.tables.iter().all(|t| t.done)
}
}
impl crate::checkpoint::Checkpoint for InterleavedSnapshotCheckpoint {
const DATABASE_TYPE: &'static str = "interleaved_snapshot";
fn to_cli_string(&self) -> String {
serde_json::to_string(self).unwrap_or_default()
}
fn from_cli_string(s: &str) -> anyhow::Result<Self> {
Ok(serde_json::from_str(s)?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::checkpoint::{Checkpoint, CheckpointFile, SyncPhase};
fn sample() -> InterleavedSnapshotCheckpoint {
InterleavedSnapshotCheckpoint::new(
serde_json::json!("0/16B3748"),
vec![
SnapshotTableProgress {
name: "users".to_string(),
last_pk: Some(serde_json::json!([{ "type": "Int64", "value": 42 }])),
done: false,
},
SnapshotTableProgress {
name: "orders".to_string(),
last_pk: None,
done: true,
},
],
)
}
#[test]
fn cli_string_roundtrip() {
let original = sample();
let s = original.to_cli_string();
let decoded = InterleavedSnapshotCheckpoint::from_cli_string(&s).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn checkpoint_file_roundtrip() {
let original = sample();
let file = CheckpointFile::new(&original, SyncPhase::SnapshotProgress).unwrap();
assert_eq!(
file.database_type(),
InterleavedSnapshotCheckpoint::DATABASE_TYPE
);
let decoded: InterleavedSnapshotCheckpoint = file.parse().unwrap();
assert_eq!(original, decoded);
}
#[test]
fn all_done_reflects_table_state() {
let mut cp = sample();
assert!(!cp.all_done());
for t in &mut cp.tables {
t.done = true;
}
assert!(cp.all_done());
}
}