firestore_db_and_auth/
firebase_rest_to_rust.rs
1use bytes::Bytes;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::HashMap;
10
11use super::dto;
12use super::errors::{FirebaseError, Result};
13
14#[derive(Debug, Serialize, Deserialize)]
15struct Wrapper {
16 #[serde(flatten)]
17 extra: HashMap<String, Value>,
18}
19
20use serde_json::{map::Map, Number};
21
22pub(crate) fn firebase_value_to_serde_value(v: &dto::Value) -> serde_json::Value {
29 if let Some(timestamp_value) = v.timestamp_value.as_ref() {
30 return Value::String(timestamp_value.clone());
31 } else if let Some(integer_value) = v.integer_value.as_ref() {
32 if let Ok(four) = integer_value.parse::<i64>() {
33 return Value::Number(four.into());
34 }
35 } else if let Some(double_value) = v.double_value {
36 if let Some(dd) = Number::from_f64(double_value) {
37 return Value::Number(dd);
38 }
39 } else if let Some(map_value) = v.map_value.as_ref() {
40 let mut map: Map<String, serde_json::value::Value> = Map::new();
41 if let Some(map_fields) = &map_value.fields {
42 for (map_key, map_v) in map_fields {
43 map.insert(map_key.clone(), firebase_value_to_serde_value(&map_v));
44 }
45 }
46 return Value::Object(map);
47 } else if let Some(string_value) = v.string_value.as_ref() {
48 return Value::String(string_value.clone());
49 } else if let Some(boolean_value) = v.boolean_value {
50 return Value::Bool(boolean_value);
51 } else if let Some(array_value) = v.array_value.as_ref() {
52 let mut vec: Vec<Value> = Vec::new();
53 if let Some(values) = &array_value.values {
54 for k in values {
55 vec.push(firebase_value_to_serde_value(&k));
56 }
57 }
58 return Value::Array(vec);
59 }
60 Value::Null
61}
62
63pub(crate) fn serde_value_to_firebase_value(v: &serde_json::Value) -> dto::Value {
70 if v.is_f64() {
71 return dto::Value {
72 double_value: Some(v.as_f64().unwrap()),
73 ..Default::default()
74 };
75 } else if let Some(integer_value) = v.as_i64() {
76 return dto::Value {
77 integer_value: Some(integer_value.to_string()),
78 ..Default::default()
79 };
80 } else if let Some(map_value) = v.as_object() {
81 let mut map: HashMap<String, dto::Value> = HashMap::new();
82 for (map_key, map_v) in map_value {
83 map.insert(map_key.to_owned(), serde_value_to_firebase_value(&map_v));
84 }
85 return dto::Value {
86 map_value: Some(dto::MapValue { fields: Some(map) }),
87 ..Default::default()
88 };
89 } else if let Some(string_value) = v.as_str() {
90 return dto::Value {
91 string_value: Some(string_value.to_owned()),
92 ..Default::default()
93 };
94 } else if let Some(boolean_value) = v.as_bool() {
95 return dto::Value {
96 boolean_value: Some(boolean_value),
97 ..Default::default()
98 };
99 } else if let Some(array_value) = v.as_array() {
100 let mut vec: Vec<dto::Value> = Vec::new();
101 for k in array_value {
102 vec.push(serde_value_to_firebase_value(&k));
103 }
104 return dto::Value {
105 array_value: Some(dto::ArrayValue { values: Some(vec) }),
106 ..Default::default()
107 };
108 }
109 Default::default()
110}
111
112pub fn document_to_pod<T>(document: &dto::Document, input_doc: Option<&Bytes>) -> Result<T>
125where
126 for<'de> T: Deserialize<'de>,
127{
128 let r = Wrapper {
133 extra: document
134 .fields
135 .as_ref()
136 .unwrap()
137 .iter()
138 .map(|(k, v)| {
139 return (k.to_owned(), firebase_value_to_serde_value(&v));
140 })
141 .collect(),
142 };
143
144 let v = serde_json::to_value(r)?;
145 let r: T = serde_json::from_value(v).map_err(|e| FirebaseError::SerdeVerbose {
146 doc: Some(document.name.clone()),
147 input_doc: String::from_utf8_lossy(input_doc.unwrap_or(&Bytes::new()))
148 .replace("\n", " ")
149 .to_string(),
150 ser: e,
151 })?;
152 Ok(r)
153}
154
155pub fn pod_to_document<T>(pod: &T) -> Result<dto::Document>
164where
165 T: Serialize,
166{
167 let v = serde_json::to_value(pod)?;
168 Ok(dto::Document {
169 fields: serde_value_to_firebase_value(&v).map_value.unwrap().fields,
170 ..Default::default()
171 })
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 use super::Result;
179 use serde::{Deserialize, Serialize};
180 use std::collections::HashMap;
181
182 #[derive(Serialize, Deserialize)]
183 struct DemoPod {
184 integer_test: u32,
185 boolean_test: bool,
186 string_test: String,
187 }
188
189 #[test]
190 fn test_document_to_pod() -> Result<()> {
191 let mut map: HashMap<String, dto::Value> = HashMap::new();
192 map.insert(
193 "integer_test".to_owned(),
194 dto::Value {
195 integer_value: Some("12".to_owned()),
196 ..Default::default()
197 },
198 );
199 map.insert(
200 "boolean_test".to_owned(),
201 dto::Value {
202 boolean_value: Some(true),
203 ..Default::default()
204 },
205 );
206 map.insert(
207 "string_test".to_owned(),
208 dto::Value {
209 string_value: Some("abc".to_owned()),
210 ..Default::default()
211 },
212 );
213 let t = dto::Document {
214 fields: Some(map),
215 ..Default::default()
216 };
217 let firebase_doc: DemoPod = document_to_pod(&t, None)?;
218 assert_eq!(firebase_doc.string_test, "abc");
219 assert_eq!(firebase_doc.integer_test, 12);
220 assert_eq!(firebase_doc.boolean_test, true);
221
222 Ok(())
223 }
224
225 #[test]
226 fn test_pod_to_document() -> Result<()> {
227 let t = DemoPod {
228 integer_test: 12,
229 boolean_test: true,
230 string_test: "abc".to_owned(),
231 };
232 let firebase_doc = pod_to_document(&t)?;
233 let map = firebase_doc.fields;
234 assert_eq!(
235 map.unwrap()
236 .get("integer_test")
237 .expect("a value in the map for integer_test")
238 .integer_value
239 .as_ref()
240 .expect("an integer value"),
241 "12"
242 );
243
244 Ok(())
245 }
246}