use crate::provider::DbValue;
#[derive(Debug, Clone)]
pub struct EntitySnapshot {
entries: Box<[(&'static str, DbValue)]>,
}
impl EntitySnapshot {
pub fn new(entries: Vec<(&'static str, DbValue)>) -> Self {
Self {
entries: entries.into_boxed_slice(),
}
}
pub fn empty() -> Self {
Self {
entries: Box::new([]),
}
}
pub fn get(&self, field: &str) -> Option<&DbValue> {
self.entries
.iter()
.find(|(k, _)| *k == field)
.map(|(_, v)| v)
}
pub fn iter(&self) -> impl Iterator<Item = (&'static str, &DbValue)> {
self.entries.iter().map(|(k, v)| (*k, v))
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl PartialEq for EntitySnapshot {
fn eq(&self, other: &Self) -> bool {
self.entries.len() == other.entries.len()
&& self.entries.iter().all(|(k, v)| other.get(k) == Some(v))
}
}
impl From<Vec<(&'static str, DbValue)>> for EntitySnapshot {
fn from(entries: Vec<(&'static str, DbValue)>) -> Self {
Self::new(entries)
}
}
impl Default for EntitySnapshot {
fn default() -> Self {
Self::empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn construct_and_get() {
let snap = EntitySnapshot::new(vec![
("id", DbValue::I32(42)),
("name", DbValue::String("hello".into())),
]);
assert_eq!(snap.get("id"), Some(&DbValue::I32(42)));
assert_eq!(snap.get("name"), Some(&DbValue::String("hello".into())));
assert_eq!(snap.get("missing"), None);
}
#[test]
fn empty_snapshot() {
let snap = EntitySnapshot::empty();
assert!(snap.is_empty());
assert_eq!(snap.len(), 0);
assert_eq!(snap.get("anything"), None);
}
#[test]
fn iter_all_fields() {
let snap = EntitySnapshot::new(vec![("a", DbValue::I32(1)), ("b", DbValue::I32(2))]);
let mut fields: Vec<&str> = snap.iter().map(|(k, _)| k).collect();
fields.sort();
assert_eq!(fields, vec!["a", "b"]);
}
#[test]
fn eq_order_independent() {
let a = EntitySnapshot::new(vec![
("id", DbValue::I32(1)),
("name", DbValue::String("x".into())),
]);
let b = EntitySnapshot::new(vec![
("name", DbValue::String("x".into())),
("id", DbValue::I32(1)),
]);
assert_eq!(a, b);
}
#[test]
fn ne_different_values() {
let a = EntitySnapshot::new(vec![("id", DbValue::I32(1))]);
let b = EntitySnapshot::new(vec![("id", DbValue::I32(2))]);
assert_ne!(a, b);
}
#[test]
fn ne_different_lengths() {
let a = EntitySnapshot::new(vec![("id", DbValue::I32(1))]);
let b = EntitySnapshot::new(vec![
("id", DbValue::I32(1)),
("name", DbValue::String("x".into())),
]);
assert_ne!(a, b);
}
#[test]
fn clone_preserves_data() {
let snap = EntitySnapshot::new(vec![
("id", DbValue::I64(99)),
("active", DbValue::Bool(true)),
]);
let cloned = snap.clone();
assert_eq!(snap, cloned);
}
#[test]
fn default_is_empty() {
let snap = EntitySnapshot::default();
assert!(snap.is_empty());
}
}