#[cfg(feature = "serde-support")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-support", serde(rename_all = "lowercase"))]
pub enum Lifecycle {
Spec,
Data,
Ownership,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-support", serde(untagged))]
pub enum Version {
Counter(u64),
Cid(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct BaseChange<T> {
pub structure: String,
pub version: Version,
pub t_ns: u64,
#[cfg_attr(
feature = "serde-support",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub seq: Option<u64>,
pub lifecycle: Lifecycle,
pub change: T,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde-support",
serde(tag = "kind", rename_all = "camelCase")
)]
pub enum LogChange<T> {
Append { value: T },
AppendMany { values: Vec<T> },
Clear { count: usize },
TrimHead { n: usize },
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde-support",
serde(tag = "kind", rename_all = "camelCase")
)]
pub enum ListChange<T> {
Append { value: T },
AppendMany { values: Vec<T> },
Insert { index: usize, value: T },
InsertMany { index: usize, values: Vec<T> },
Pop { index: i64, value: T },
Clear { count: usize },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-support", serde(rename_all = "camelCase"))]
pub enum DeleteReason {
Explicit,
Expired,
LruEvict,
Archived,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde-support",
serde(tag = "kind", rename_all = "camelCase")
)]
pub enum MapChange<K, V> {
Set {
key: K,
value: V,
},
Delete {
key: K,
previous: V,
reason: DeleteReason,
},
Clear {
count: usize,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde-support",
serde(tag = "kind", rename_all = "camelCase")
)]
pub enum IndexChange<K, V> {
Upsert {
primary: K,
secondary: String,
value: V,
},
Delete {
primary: K,
},
DeleteMany {
primaries: Vec<K>,
},
Clear {
count: usize,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "serde-support")]
#[test]
fn lifecycle_serde_lowercase() {
assert_eq!(serde_json::to_string(&Lifecycle::Spec).unwrap(), "\"spec\"");
assert_eq!(serde_json::to_string(&Lifecycle::Data).unwrap(), "\"data\"");
assert_eq!(
serde_json::to_string(&Lifecycle::Ownership).unwrap(),
"\"ownership\""
);
let parsed: Lifecycle = serde_json::from_str("\"data\"").unwrap();
assert_eq!(parsed, Lifecycle::Data);
}
#[cfg(feature = "serde-support")]
#[test]
fn version_serde_untagged_matches_ts_number_or_string() {
assert_eq!(serde_json::to_string(&Version::Counter(42)).unwrap(), "42");
assert_eq!(
serde_json::to_string(&Version::Cid("bafy123".into())).unwrap(),
"\"bafy123\""
);
let parsed_num: Version = serde_json::from_str("7").unwrap();
assert_eq!(parsed_num, Version::Counter(7));
let parsed_str: Version = serde_json::from_str("\"bafyabc\"").unwrap();
assert_eq!(parsed_str, Version::Cid("bafyabc".into()));
}
#[cfg(feature = "serde-support")]
#[test]
fn base_change_skips_optional_seq() {
let c: BaseChange<u64> = BaseChange {
structure: "test".into(),
version: Version::Counter(1),
t_ns: 100,
seq: None,
lifecycle: Lifecycle::Data,
change: 99,
};
let s = serde_json::to_string(&c).unwrap();
assert!(
!s.contains("seq"),
"Option::None should not emit seq field: {s}"
);
}
}