waves_rust/model/transaction/
data_transaction.rs1use crate::error::{Error, Result};
2use crate::model::data_entry::DataEntry;
3use crate::util::{Base64, JsonDeserializer};
4use crate::waves_proto::data_transaction_data::data_entry::Value::{
5 BinaryValue, BoolValue, IntValue, StringValue,
6};
7use crate::waves_proto::data_transaction_data::DataEntry as ProtoDataEntry;
8use crate::waves_proto::DataTransactionData;
9use serde_json::{Map, Number, Value};
10
11const TYPE: u8 = 12;
12
13#[derive(Clone, Eq, PartialEq, Debug)]
14pub struct DataTransactionInfo {
15 data: Vec<DataEntry>,
16}
17
18impl DataTransactionInfo {
19 pub fn new(data: Vec<DataEntry>) -> Self {
20 DataTransactionInfo { data }
21 }
22
23 pub fn tx_type() -> u8 {
24 TYPE
25 }
26
27 pub fn data(&self) -> Vec<DataEntry> {
28 self.data.clone()
29 }
30}
31
32impl TryFrom<&Value> for DataTransactionInfo {
33 type Error = Error;
34
35 fn try_from(value: &Value) -> Result<Self> {
36 let data_transaction: DataTransaction = value.try_into()?;
37 Ok(DataTransactionInfo {
38 data: data_transaction.data(),
39 })
40 }
41}
42
43#[derive(Clone, Eq, PartialEq, Debug)]
44pub struct DataTransaction {
45 data: Vec<DataEntry>,
46}
47
48impl DataTransaction {
49 pub fn new(data: Vec<DataEntry>) -> Self {
50 DataTransaction { data }
51 }
52
53 pub fn tx_type() -> u8 {
54 TYPE
55 }
56
57 pub fn data(&self) -> Vec<DataEntry> {
58 self.data.clone()
59 }
60}
61
62impl TryFrom<&Value> for DataTransaction {
63 type Error = Error;
64
65 fn try_from(value: &Value) -> Result<Self> {
66 let data_array = JsonDeserializer::safe_to_array_from_field(value, "data")?;
67 let data = data_array
68 .iter()
69 .map(|entry| entry.try_into())
70 .collect::<Result<Vec<DataEntry>>>()?;
71
72 Ok(DataTransaction { data })
73 }
74}
75
76impl TryFrom<&DataTransaction> for DataTransactionData {
77 type Error = Error;
78
79 fn try_from(value: &DataTransaction) -> Result<Self> {
80 let mut proto_data_entries: Vec<ProtoDataEntry> = vec![];
81 let data_entries = value.data();
82 for data_entry in data_entries {
83 let key = data_entry.key();
84 match data_entry {
85 DataEntry::IntegerEntry { key: _, value } => {
86 proto_data_entries.push(ProtoDataEntry {
87 key,
88 value: Some(IntValue(value)),
89 });
90 }
91 DataEntry::BooleanEntry { key: _, value } => {
92 proto_data_entries.push(ProtoDataEntry {
93 key,
94 value: Some(BoolValue(value)),
95 });
96 }
97 DataEntry::BinaryEntry { key: _, value } => {
98 proto_data_entries.push(ProtoDataEntry {
99 key,
100 value: Some(BinaryValue(value)),
101 })
102 }
103 DataEntry::StringEntry { key: _, value } => {
104 proto_data_entries.push(ProtoDataEntry {
105 key,
106 value: Some(StringValue(value)),
107 })
108 }
109 DataEntry::DeleteEntry { key: _ } => {
110 proto_data_entries.push(ProtoDataEntry { key, value: None });
111 }
112 };
113 }
114 Ok(DataTransactionData {
115 data: proto_data_entries,
116 })
117 }
118}
119
120impl TryFrom<&DataTransaction> for Map<String, Value> {
121 type Error = Error;
122
123 fn try_from(value: &DataTransaction) -> Result<Self> {
124 let mut map: Map<String, Value> = Map::new();
125 let entries = value
126 .data()
127 .iter()
128 .map(|entry| entry.into())
129 .collect::<Vec<Value>>();
130 map.insert("data".to_string(), Value::Array(entries));
131 Ok(map)
132 }
133}
134
135impl From<&DataEntry> for Value {
136 fn from(data_entry: &DataEntry) -> Self {
137 let mut map: Map<String, Value> = Map::new();
138 map.insert("key".to_string(), data_entry.key().into());
139 match data_entry {
140 DataEntry::IntegerEntry { key: _, value } => {
141 map.insert("type".to_string(), "integer".into());
142 map.insert("value".to_string(), Value::Number(Number::from(*value)));
143 }
144 DataEntry::BooleanEntry { key: _, value } => {
145 map.insert("type".to_string(), "boolean".into());
146 map.insert("value".to_string(), Value::Bool(*value));
147 }
148 DataEntry::BinaryEntry { key: _, value } => {
149 map.insert("type".to_string(), "binary".into());
150 map.insert("value".to_string(), Base64::encode(value, true).into());
151 }
152 DataEntry::StringEntry { key: _, value } => {
153 map.insert("type".to_string(), "string".into());
154 map.insert("value".to_string(), Value::String(value.clone()));
155 }
156 DataEntry::DeleteEntry { key: _ } => {
157 map.insert("value".to_string(), Value::Null);
158 }
159 };
160 map.into()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use crate::error::Result;
167 use crate::model::data_entry::DataEntry;
168 use crate::model::DataTransaction;
169 use crate::waves_proto::data_transaction_data::data_entry::Value::{
170 BinaryValue, BoolValue, IntValue, StringValue,
171 };
172 use crate::waves_proto::DataTransactionData;
173 use serde_json::{json, Map, Value};
174
175 use std::borrow::Borrow;
176 use std::fs;
177
178 #[test]
179 fn test_json_to_data_transaction() -> Result<()> {
180 let data = fs::read_to_string("./tests/resources/data_transaction_rs.json")
181 .expect("Unable to read file");
182 let json: Value = serde_json::from_str(&data).expect("failed to generate json from str");
183
184 let data_tx_from_json: DataTransaction = json.borrow().try_into()?;
185 let data_entries = data_tx_from_json.data();
186
187 for data_entry in data_entries {
188 match data_entry {
189 DataEntry::IntegerEntry { key, value } => {
190 assert_eq!("int", key);
191 assert_eq!(12, value);
192 }
193 DataEntry::BooleanEntry { key, value } => {
194 assert_eq!("bool", key);
195 assert_eq!(false, value);
196 }
197 DataEntry::BinaryEntry { key, value } => {
198 assert_eq!("binary", key);
199 assert_eq!([0_u8; 12].to_vec(), value);
200 }
201 DataEntry::StringEntry { key, value } => {
202 assert_eq!("str", key);
203 assert_eq!("value", value);
204 }
205 DataEntry::DeleteEntry { key } => {
206 assert_eq!("del_str", key)
207 }
208 }
209 }
210
211 Ok(())
212 }
213
214 #[test]
215 fn test_data_transaction_to_proto() -> Result<()> {
216 let expected_vec_data = vec![
217 DataEntry::IntegerEntry {
218 key: "int".to_string(),
219 value: 12,
220 },
221 DataEntry::BooleanEntry {
222 key: "bool".to_string(),
223 value: false,
224 },
225 DataEntry::BinaryEntry {
226 key: "binary".to_string(),
227 value: [0; 12].to_vec(),
228 },
229 DataEntry::StringEntry {
230 key: "str".to_string(),
231 value: "value".to_string(),
232 },
233 DataEntry::DeleteEntry {
234 key: "del_str".to_string(),
235 },
236 ];
237 let data_transaction = &DataTransaction::new(expected_vec_data.clone());
238 let proto: DataTransactionData = data_transaction.try_into()?;
239 assert_eq!(expected_vec_data.len(), proto.data.len());
240
241 for data_entry in expected_vec_data {
242 match data_entry {
243 DataEntry::IntegerEntry { key, value } => {
244 let int_entry = &proto.data[0];
245 assert_eq!(int_entry.key, key);
246 int_entry.value.clone().map(|it| match it {
247 IntValue(int_value) => {
248 assert_eq!(int_value, value)
249 }
250 _ => panic!("expected integer"),
251 });
252 }
253 DataEntry::BooleanEntry { key, value } => {
254 let bool_entry = &proto.data[1];
255 assert_eq!(bool_entry.key, key);
256 bool_entry.value.clone().map(|it| match it {
257 BoolValue(bool_value) => {
258 assert_eq!(bool_value, value)
259 }
260 _ => panic!("expected integer"),
261 });
262 }
263 DataEntry::BinaryEntry { key, value } => {
264 let binary_entry = &proto.data[2];
265 assert_eq!(binary_entry.key, key);
266 binary_entry.value.clone().map(|it| match it {
267 BinaryValue(binary_value) => {
268 assert_eq!(binary_value, value)
269 }
270 _ => panic!("expected integer"),
271 });
272 }
273 DataEntry::StringEntry { key, value } => {
274 let string_entry = &proto.data[3];
275 assert_eq!(string_entry.key, key);
276 string_entry.value.clone().map(|it| match it {
277 StringValue(string_value) => {
278 assert_eq!(string_value, value)
279 }
280 _ => panic!("expected integer"),
281 });
282 }
283 DataEntry::DeleteEntry { key } => {
284 let delete_entry = &proto.data[4];
285 assert_eq!(delete_entry.key, key);
286 }
287 }
288 }
289
290 Ok(())
291 }
292
293 #[test]
294 fn test_data_transaction_to_json() -> Result<()> {
295 let data_transaction = &DataTransaction::new(vec![
296 DataEntry::IntegerEntry {
297 key: "int".to_string(),
298 value: 12,
299 },
300 DataEntry::BooleanEntry {
301 key: "bool".to_string(),
302 value: false,
303 },
304 DataEntry::BinaryEntry {
305 key: "binary".to_string(),
306 value: [0; 12].to_vec(),
307 },
308 DataEntry::StringEntry {
309 key: "str".to_string(),
310 value: "value".to_string(),
311 },
312 DataEntry::DeleteEntry {
313 key: "del_str".to_string(),
314 },
315 ]);
316
317 let map: Map<String, Value> = data_transaction.try_into()?;
318 let json: Value = map.into();
319 let expected_json = json!({"data": [
320 {
321 "key": "int",
322 "type": "integer",
323 "value": 12
324 },
325 {
326 "key": "bool",
327 "type": "boolean",
328 "value": false
329 },
330 {
331 "key": "binary",
332 "type": "binary",
333 "value": "base64:AAAAAAAAAAAAAAAA"
334 },
335 {
336 "key": "str",
337 "type": "string",
338 "value": "value"
339 },
340 {
341 "key": "del_str",
342 "value": null
343 }
344 ]});
345 assert_eq!(expected_json, json);
346 Ok(())
347 }
348}