use serde::{Deserialize, Serialize};
#[derive(
Debug,
Clone,
PartialEq,
Serialize,
Deserialize,
zerompk::ToMessagePack,
zerompk::FromMessagePack,
)]
pub(crate) enum CrdtListOpWalRecord {
Insert {
collection: String,
document_id: String,
list_path: String,
index: u64,
fields_json: String,
},
Delete {
collection: String,
document_id: String,
list_path: String,
index: u64,
},
Move {
collection: String,
document_id: String,
list_path: String,
from_index: u64,
to_index: u64,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_insert() {
let rec = CrdtListOpWalRecord::Insert {
collection: "notes".to_string(),
document_id: "doc1".to_string(),
list_path: "blocks".to_string(),
index: 2,
fields_json: r#"{"type":"text"}"#.to_string(),
};
let bytes = zerompk::to_msgpack_vec(&rec).expect("encode");
let decoded: CrdtListOpWalRecord = zerompk::from_msgpack(&bytes).expect("decode");
assert_eq!(decoded, rec);
}
#[test]
fn round_trips_delete() {
let rec = CrdtListOpWalRecord::Delete {
collection: "notes".to_string(),
document_id: "doc1".to_string(),
list_path: "blocks".to_string(),
index: 5,
};
let bytes = zerompk::to_msgpack_vec(&rec).expect("encode");
let decoded: CrdtListOpWalRecord = zerompk::from_msgpack(&bytes).expect("decode");
assert_eq!(decoded, rec);
}
#[test]
fn round_trips_move() {
let rec = CrdtListOpWalRecord::Move {
collection: "notes".to_string(),
document_id: "doc1".to_string(),
list_path: "blocks".to_string(),
from_index: 0,
to_index: 3,
};
let bytes = zerompk::to_msgpack_vec(&rec).expect("encode");
let decoded: CrdtListOpWalRecord = zerompk::from_msgpack(&bytes).expect("decode");
assert_eq!(decoded, rec);
}
#[test]
fn move_round_trips_distinct_indices_without_collapsing_to_zero() {
let rec = CrdtListOpWalRecord::Move {
collection: "notes".to_string(),
document_id: "doc1".to_string(),
list_path: "blocks".to_string(),
from_index: 3,
to_index: 1,
};
let bytes = zerompk::to_msgpack_vec(&rec).expect("encode");
let decoded: CrdtListOpWalRecord = zerompk::from_msgpack(&bytes).expect("decode");
match decoded {
CrdtListOpWalRecord::Move {
from_index,
to_index,
..
} => {
assert_eq!(from_index, 3, "from_index must survive the round trip");
assert_eq!(to_index, 1, "to_index must survive the round trip");
assert_ne!(
from_index, to_index,
"distinct indices must never collapse to the same value"
);
assert_ne!(from_index, 0, "from_index must not collapse to 0");
assert_ne!(to_index, 0, "to_index must not collapse to 0");
}
other => panic!("expected Move variant, got {other:?}"),
}
}
}