use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::value::Value;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Document {
pub id: String,
pub fields: HashMap<String, Value>,
}
impl Document {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
fields: HashMap::new(),
}
}
pub fn set(&mut self, key: impl Into<String>, value: Value) -> &mut Self {
self.fields.insert(key.into(), value);
self
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.fields.get(key)
}
pub fn get_str(&self, key: &str) -> Option<&str> {
match self.fields.get(key) {
Some(Value::String(s)) => Some(s),
_ => None,
}
}
pub fn get_f64(&self, key: &str) -> Option<f64> {
match self.fields.get(key) {
Some(Value::Float(f)) => Some(*f),
Some(Value::Integer(i)) => Some(*i as f64),
_ => None,
}
}
pub fn to_msgpack(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
rmp_serde::to_vec_named(self)
}
pub fn from_msgpack(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
rmp_serde::from_slice(bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn document_builder() {
let mut doc = Document::new("user-1");
doc.set("name", Value::String("Alice".into()))
.set("age", Value::Integer(30))
.set("score", Value::Float(9.5));
assert_eq!(doc.id, "user-1");
assert_eq!(doc.get_str("name"), Some("Alice"));
assert_eq!(doc.get_f64("age"), Some(30.0));
assert_eq!(doc.get_f64("score"), Some(9.5));
assert!(doc.get("missing").is_none());
}
#[test]
fn msgpack_roundtrip() {
let mut doc = Document::new("d1");
doc.set("key", Value::String("val".into()));
let bytes = doc.to_msgpack().unwrap();
let decoded = Document::from_msgpack(&bytes).unwrap();
assert_eq!(doc, decoded);
}
}