1use redis::{from_redis_value, FromRedisValue, RedisError, RedisResult, Value};
2use std::collections::HashMap;
3
4#[derive(Default, Clone, Debug)]
8pub struct GraphResultSet {
9 pub header: Vec<String>,
11
12 pub data: Vec<GraphResult>,
14
15 pub metadata: Vec<String>,
17}
18
19#[derive(Default, Clone, Debug)]
37pub struct GraphResult {
38 pub data: HashMap<String, GraphValue>,
40}
41
42#[derive(Clone, Debug)]
47pub enum GraphValue {
48 Scalar(Value),
49 Node(NodeValue),
50 Relation(RelationValue),
51}
52
53#[derive(Default, Clone, Debug)]
56pub struct NodeValue {
57 pub id: u64,
58 pub labels: Vec<String>,
59 pub properties: HashMap<String, Value>,
60}
61
62#[derive(Default, Clone, Debug)]
65pub struct RelationValue {
66 pub id: u64,
67 pub rel_type: String,
68 pub src_node: u64,
69 pub dest_node: u64,
70 pub properties: HashMap<String, Value>,
71}
72
73#[derive(Default, Clone, Debug)]
75pub struct SlowLogEntry {
76 pub timestamp: u64,
78 pub command: String,
80 pub query: String,
82 pub time: f64,
84}
85
86#[derive(Default, Clone, Debug)]
89pub struct GraphConfig {
90 pub values: HashMap<String, Value>,
91}
92
93impl GraphConfig {
94 pub fn get_value<T: FromRedisValue>(&self, key: &str) -> RedisResult<Option<T>> {
98 match self.values.get(key) {
99 Some(value) => from_redis_value(value),
100 _ => Ok(None),
101 }
102 }
103}
104
105impl GraphResultSet {
106 fn from_metadata(metadata: Vec<String>) -> Self {
107 GraphResultSet {
108 header: Vec::default(),
109 data: Vec::default(),
110 metadata,
111 }
112 }
113}
114
115impl GraphResult {
118 pub fn get_value(&self, key: &str) -> Option<&GraphValue> {
120 self.data.get(key)
121 }
122
123 pub fn get_scalar<T: FromRedisValue>(&self, key: &str) -> Option<T> {
127 match self.get_value(key) {
128 Some(GraphValue::Scalar(value)) => from_redis_value(value).unwrap_or(None),
129 _ => None,
130 }
131 }
132
133 pub fn get_node(&self, key: &str) -> Option<&NodeValue> {
137 match self.get_value(key) {
138 Some(GraphValue::Node(value)) => Some(value),
139 _ => None,
140 }
141 }
142
143 pub fn get_relation(&self, key: &str) -> Option<&RelationValue> {
147 match self.get_value(key) {
148 Some(GraphValue::Relation(value)) => Some(value),
149 _ => None,
150 }
151 }
152}
153
154pub trait WithProperties {
158 fn get_property_value(&self, key: &str) -> Option<&Value>;
160
161 fn get_property<T: FromRedisValue>(&self, key: &str) -> RedisResult<Option<T>> {
165 match self.get_property_value(key) {
166 Some(value) => from_redis_value(value),
167 _ => Ok(None),
168 }
169 }
170
171 fn get_property_option<T: FromRedisValue>(&self, key: &str) -> Option<T> {
175 self.get_property(key).unwrap_or(None)
176 }
177}
178
179impl WithProperties for NodeValue {
181 fn get_property_value(&self, key: &str) -> Option<&Value> {
182 self.properties.get(key)
183 }
184}
185
186impl WithProperties for RelationValue {
188 fn get_property_value(&self, key: &str) -> Option<&Value> {
189 self.properties.get(key)
190 }
191}
192
193impl FromRedisValue for GraphResultSet {
194 fn from_redis_value(v: &Value) -> RedisResult<Self> {
195 match *v {
196 Value::Bulk(ref values) if values.is_empty() => Ok(GraphResultSet::default()),
197 Value::Bulk(ref values) if values.len() == 1 => match values.get(0) {
198 Some(v) => {
199 let data: Vec<String> = from_redis_value(v)?;
200 Ok(GraphResultSet::from_metadata(data))
201 }
202 _ => Ok(GraphResultSet::default()),
203 },
204 Value::Bulk(ref values) => {
205 let header: Vec<String> = match values.get(0) {
206 Some(v) => from_redis_value(v)?,
207 _ => Vec::default(),
208 };
209
210 let data: Vec<GraphResult> = match values.get(1) {
211 Some(Value::Bulk(v)) => v
212 .iter()
213 .map(|bulk| {
214 let items: Vec<GraphValue> = from_redis_value(bulk)?;
215 let mut data: HashMap<String, GraphValue> = HashMap::new();
216 for (idx, name) in header.iter().enumerate() {
217 if let Some(value) = items.get(idx) {
218 data.insert(name.to_string(), value.to_owned());
219 }
220 }
221 Ok(GraphResult { data })
222 })
223 .collect::<RedisResult<Vec<GraphResult>>>()?,
224 _ => Vec::default(),
225 };
226
227 let metadata: Vec<String> = match values.get(2) {
228 Some(v) => from_redis_value(v)?,
229 _ => Vec::default(),
230 };
231
232 Ok(GraphResultSet {
233 header,
234 data,
235 metadata,
236 })
237 }
238 _ => Err(create_error("Could not parse graph result")),
239 }
240 }
241}
242
243impl FromRedisValue for GraphValue {
244 fn from_redis_value(v: &Value) -> RedisResult<Self> {
245 match v {
246 Value::Bulk(ref values) if values.len() == 3 => {
247 let res: NodeValue = from_redis_value(v)?;
248 Ok(GraphValue::Node(res))
249 }
250 Value::Bulk(_) => {
251 let res: RelationValue = from_redis_value(v)?;
252 Ok(GraphValue::Relation(res))
253 }
254 value => Ok(GraphValue::Scalar(value.clone())),
255 }
256 }
257}
258
259impl FromRedisValue for NodeValue {
260 fn from_redis_value(v: &Value) -> RedisResult<Self> {
261 let values = to_property_map(v)?;
262 let id: u64 = values
263 .get("id")
264 .map_or(Ok(Some(0)), from_redis_value)?
265 .unwrap();
266 let labels: Vec<String> = if values.get("labels").is_some() {
267 from_redis_value(values.get("labels").unwrap())?
268 } else {
269 Vec::default()
270 };
271 let properties: HashMap<String, Value> = if values.get("properties").is_some() {
272 to_property_map(values.get("properties").unwrap())?
273 } else {
274 HashMap::default()
275 };
276
277 Ok(NodeValue {
278 id,
279 labels,
280 properties,
281 })
282 }
283}
284
285impl FromRedisValue for RelationValue {
286 fn from_redis_value(v: &Value) -> RedisResult<Self> {
287 let values = to_property_map(v)?;
288 let id: u64 = values
289 .get("id")
290 .map_or(Ok(Some(0)), from_redis_value)?
291 .unwrap();
292 let rel_type: String = values
293 .get("type")
294 .map_or(Ok(Some("".to_string())), from_redis_value)?
295 .unwrap();
296 let src_node: u64 = values
297 .get("src_node")
298 .map_or(Ok(Some(0)), from_redis_value)?
299 .unwrap();
300 let dest_node: u64 = values
301 .get("dest_node")
302 .map_or(Ok(Some(0)), from_redis_value)?
303 .unwrap();
304 let properties: HashMap<String, Value> = if values.get("properties").is_some() {
305 to_property_map(values.get("properties").unwrap())?
306 } else {
307 HashMap::new()
308 };
309
310 Ok(RelationValue {
311 id,
312 rel_type,
313 src_node,
314 dest_node,
315 properties,
316 })
317 }
318}
319
320impl FromRedisValue for SlowLogEntry {
321 fn from_redis_value(v: &Value) -> RedisResult<Self> {
322 match v {
323 Value::Bulk(ref values) if values.len() == 4 => Ok(SlowLogEntry {
324 timestamp: from_redis_value(values.get(0).unwrap())?,
325 command: from_redis_value(values.get(1).unwrap())?,
326 query: from_redis_value(values.get(2).unwrap())?,
327 time: from_redis_value(values.get(3).unwrap())?,
328 }),
329 _ => Err(create_error("invalid_slow_log_entry")),
330 }
331 }
332}
333
334impl FromRedisValue for GraphConfig {
335 fn from_redis_value(v: &Value) -> RedisResult<Self> {
336 match v {
337 Value::Bulk(_) => Ok(GraphConfig {
338 values: to_property_map(v)?,
339 }),
340 _ => Ok(GraphConfig {
341 values: HashMap::default(),
342 }),
343 }
344 }
345}
346
347pub fn create_error(msg: &str) -> RedisError {
349 RedisError::from(std::io::Error::new(
350 std::io::ErrorKind::Other,
351 msg.to_string(),
352 ))
353}
354
355pub fn to_property_map(v: &Value) -> RedisResult<HashMap<String, Value>> {
357 let t: Vec<Vec<Value>> = match from_redis_value(v) {
358 Ok(v) => v,
359 _ => vec![],
360 };
361 let mut values: HashMap<String, Value> = HashMap::default();
362 for pair in t {
363 if pair.len() == 2 {
364 let key: String = from_redis_value(&pair[0])?;
365 values.insert(key, pair[1].clone());
366 }
367 }
368 Ok(values)
369}
370
371pub fn value_from_pair<T: FromRedisValue>(v: &Value) -> RedisResult<T> {
372 let r: (String, T) = from_redis_value(v)?;
373 Ok(r.1)
374}