1use indexmap::IndexMap;
4
5use crate::convert::ToTeaLeaf;
6use crate::{Schema, Union, TeaLeaf, Value};
7
8pub struct TeaLeafBuilder {
21 schemas: IndexMap<String, Schema>,
22 unions: IndexMap<String, Union>,
23 data: IndexMap<String, Value>,
24 is_root_array: bool,
25}
26
27impl TeaLeafBuilder {
28 pub fn new() -> Self {
30 Self {
31 schemas: IndexMap::new(),
32 unions: IndexMap::new(),
33 data: IndexMap::new(),
34 is_root_array: false,
35 }
36 }
37
38 pub fn add<T: ToTeaLeaf>(mut self, key: &str, dto: &T) -> Self {
40 self.schemas.extend(T::collect_schemas());
41 self.unions.extend(T::collect_unions());
42 self.data
43 .insert(key.to_string(), dto.to_tealeaf_value());
44 self
45 }
46
47 pub fn add_value(mut self, key: &str, value: Value) -> Self {
49 self.data.insert(key.to_string(), value);
50 self
51 }
52
53 pub fn add_schema(mut self, schema: Schema) -> Self {
55 self.schemas.insert(schema.name.clone(), schema);
56 self
57 }
58
59 pub fn add_union(mut self, union: Union) -> Self {
61 self.unions.insert(union.name.clone(), union);
62 self
63 }
64
65 pub fn add_vec<T: ToTeaLeaf>(mut self, key: &str, items: &[T]) -> Self {
67 self.schemas.extend(T::collect_schemas());
68 self.unions.extend(T::collect_unions());
69 let arr = Value::Array(items.iter().map(|i| i.to_tealeaf_value()).collect());
70 self.data.insert(key.to_string(), arr);
71 self
72 }
73
74 pub fn root_array(mut self) -> Self {
76 self.is_root_array = true;
77 self
78 }
79
80 pub fn build(self) -> TeaLeaf {
82 let mut doc = TeaLeaf::new(self.schemas, self.data);
83 doc.unions = self.unions;
84 doc.set_root_array(self.is_root_array);
85 doc
86 }
87}
88
89impl Default for TeaLeafBuilder {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::FieldType;
99 #[allow(unused_imports)]
100 use crate::types::ObjectMap;
101
102 #[test]
103 fn test_builder_basic() {
104 let doc = TeaLeafBuilder::new()
105 .add_value("name", Value::String("test".into()))
106 .add_value("count", Value::Int(42))
107 .build();
108
109 assert_eq!(
110 doc.get("name"),
111 Some(&Value::String("test".into()))
112 );
113 assert_eq!(doc.get("count"), Some(&Value::Int(42)));
114 }
115
116 #[test]
117 fn test_builder_with_schema() {
118 let schema = crate::Schema::new("point")
119 .field("x", FieldType::new("float"))
120 .field("y", FieldType::new("float"));
121
122 let doc = TeaLeafBuilder::new()
123 .add_schema(schema)
124 .add_value("origin", Value::Object({
125 let mut m = ObjectMap::new();
126 m.insert("x".to_string(), Value::Float(0.0));
127 m.insert("y".to_string(), Value::Float(0.0));
128 m
129 }))
130 .build();
131
132 assert!(doc.schema("point").is_some());
133 assert!(doc.get("origin").is_some());
134 }
135
136 #[test]
137 fn test_builder_with_union() {
138 use crate::Variant;
139
140 let union = Union::new("Shape")
141 .variant(Variant::new("circle").field("radius", FieldType::new("float")))
142 .variant(Variant::new("rect").field("w", FieldType::new("float")).field("h", FieldType::new("float")));
143
144 let doc = TeaLeafBuilder::new()
145 .add_union(union)
146 .add_value("shape", Value::Tagged("circle".into(), Box::new(Value::Float(5.0))))
147 .build();
148
149 assert!(doc.union("Shape").is_some());
150 assert_eq!(doc.union("Shape").unwrap().variants.len(), 2);
151 }
152
153 #[test]
154 fn test_builder_default() {
155 let doc = TeaLeafBuilder::default().build();
156 assert!(doc.get("anything").is_none());
157 }
158}