p2panda_rs/document/
document_view_fields.rs1use std::collections::btree_map::Iter;
4use std::collections::BTreeMap;
5
6use crate::operation::traits::AsOperation;
7use crate::operation::{OperationFields, OperationId, OperationValue};
8use crate::WithId;
9
10#[derive(Clone, Debug, PartialEq)]
12pub struct DocumentViewValue {
13 operation_id: OperationId,
14 value: OperationValue,
15}
16
17impl DocumentViewValue {
18 pub fn new(operation_id: &OperationId, value: &OperationValue) -> Self {
20 Self {
21 operation_id: operation_id.clone(),
22 value: value.clone(),
23 }
24 }
25
26 pub fn id(&self) -> &OperationId {
28 &self.operation_id
29 }
30
31 pub fn value(&self) -> &OperationValue {
33 &self.value
34 }
35}
36
37#[derive(Clone, Debug, PartialEq)]
39pub struct DocumentViewFields(BTreeMap<String, DocumentViewValue>);
40
41impl DocumentViewFields {
42 pub fn new() -> Self {
44 Self(BTreeMap::new())
45 }
46
47 pub fn new_from_operation_fields(id: &OperationId, fields: &OperationFields) -> Self {
49 let mut document_view_fields = DocumentViewFields::new();
50
51 for (name, value) in fields.iter() {
52 document_view_fields.insert(name, DocumentViewValue::new(id, value));
53 }
54
55 document_view_fields
56 }
57
58 pub fn insert(&mut self, name: &str, value: DocumentViewValue) -> Option<DocumentViewValue> {
60 self.0.insert(name.to_owned(), value)
61 }
62
63 pub fn len(&self) -> usize {
65 self.0.len()
66 }
67
68 pub fn is_empty(&self) -> bool {
70 self.0.is_empty()
71 }
72
73 pub fn get(&self, name: &str) -> Option<&DocumentViewValue> {
75 if !self.0.contains_key(name) {
76 return None;
77 }
78
79 self.0.get(name)
80 }
81
82 pub fn keys(&self) -> Vec<String> {
84 self.0.keys().cloned().collect()
85 }
86
87 pub fn iter(&self) -> Iter<String, DocumentViewValue> {
89 self.0.iter()
90 }
91}
92
93impl Default for DocumentViewFields {
94 fn default() -> Self {
95 Self::new()
96 }
97}
98
99impl<T: AsOperation + WithId<OperationId>> From<T> for DocumentViewFields {
100 fn from(operation: T) -> Self {
101 let mut document_view_fields = DocumentViewFields::new();
102
103 if let Some(fields) = operation.fields() {
104 for (name, value) in fields.iter() {
105 document_view_fields.insert(name, DocumentViewValue::new(operation.id(), value));
106 }
107 }
108
109 document_view_fields
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use rstest::rstest;
116
117 use crate::document::{DocumentViewFields, DocumentViewValue};
118 use crate::operation::traits::AsOperation;
119 use crate::operation::{OperationId, OperationValue};
120 use crate::test_utils::fixtures::{published_operation, random_operation_id};
121 use crate::test_utils::memory_store::PublishedOperation;
122 use crate::WithId;
123
124 #[rstest]
125 fn construct_fields(#[from(random_operation_id)] value_id: OperationId) {
126 let mut fields = DocumentViewFields::new();
127
128 fields.insert(
129 "name",
130 DocumentViewValue::new(&value_id, &OperationValue::String("ʕ •ᴥ•ʔ Cafe!".into())),
131 );
132 fields.insert(
133 "owner",
134 DocumentViewValue::new(&value_id, &OperationValue::String("しろくま".into())),
135 );
136 fields.insert(
137 "house-number",
138 DocumentViewValue::new(&value_id, &OperationValue::Integer(12)),
139 );
140
141 assert_eq!(fields.len(), 3);
142 assert!(!fields.is_empty());
143 assert_eq!(
144 fields.get("name").unwrap(),
145 &DocumentViewValue::new(&value_id, &OperationValue::String("ʕ •ᴥ•ʔ Cafe!".into()))
146 );
147 assert_eq!(
148 fields.get("owner").unwrap(),
149 &DocumentViewValue::new(&value_id, &OperationValue::String("しろくま".into()))
150 );
151 assert_eq!(
152 fields.get("house-number").unwrap(),
153 &DocumentViewValue::new(&value_id, &OperationValue::Integer(12))
154 );
155 }
156
157 #[rstest]
158 fn from_published_operation(#[from(published_operation)] operation: PublishedOperation) {
159 let document_view_fields = DocumentViewFields::from(operation.clone());
160 let operation_fields = operation.fields().unwrap();
161 assert_eq!(document_view_fields.len(), operation_fields.len());
162 }
163
164 #[rstest]
165 fn new_from_operation_fields(#[from(published_operation)] operation: PublishedOperation) {
166 let document_view_fields = DocumentViewFields::new_from_operation_fields(
167 operation.id(),
168 &operation.fields().unwrap(),
169 );
170 let operation_fields = operation.fields().unwrap();
171 assert_eq!(document_view_fields.len(), operation_fields.len());
172 }
173}