1use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9
10use crate::value::Value;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct Document {
18 pub id: String,
20 pub fields: HashMap<String, Value>,
23}
24
25impl Document {
26 pub fn new(id: impl Into<String>) -> Self {
28 Self {
29 id: id.into(),
30 fields: HashMap::new(),
31 }
32 }
33
34 pub fn set(&mut self, key: impl Into<String>, value: Value) -> &mut Self {
36 self.fields.insert(key.into(), value);
37 self
38 }
39
40 pub fn get(&self, key: &str) -> Option<&Value> {
42 self.fields.get(key)
43 }
44
45 pub fn get_str(&self, key: &str) -> Option<&str> {
47 match self.fields.get(key) {
48 Some(Value::String(s)) => Some(s),
49 _ => None,
50 }
51 }
52
53 pub fn get_f64(&self, key: &str) -> Option<f64> {
55 match self.fields.get(key) {
56 Some(Value::Float(f)) => Some(*f),
57 Some(Value::Integer(i)) => Some(*i as f64),
58 _ => None,
59 }
60 }
61
62 pub fn to_msgpack(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
64 rmp_serde::to_vec_named(self)
65 }
66
67 pub fn from_msgpack(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
69 rmp_serde::from_slice(bytes)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn document_builder() {
79 let mut doc = Document::new("user-1");
80 doc.set("name", Value::String("Alice".into()))
81 .set("age", Value::Integer(30))
82 .set("score", Value::Float(9.5));
83
84 assert_eq!(doc.id, "user-1");
85 assert_eq!(doc.get_str("name"), Some("Alice"));
86 assert_eq!(doc.get_f64("age"), Some(30.0));
87 assert_eq!(doc.get_f64("score"), Some(9.5));
88 assert!(doc.get("missing").is_none());
89 }
90
91 #[test]
92 fn msgpack_roundtrip() {
93 let mut doc = Document::new("d1");
94 doc.set("key", Value::String("val".into()));
95
96 let bytes = doc.to_msgpack().unwrap();
97 let decoded = Document::from_msgpack(&bytes).unwrap();
98 assert_eq!(doc, decoded);
99 }
100}