1use indexmap::IndexMap;
2use redis::{from_redis_value, FromRedisValue, RedisResult, Value};
3use std::{
4 collections::HashMap,
5};
6
7use crate::{
8 from_graph_value,
9 helpers::{create_rediserror, apply_macro}
10};
11
12mod types {
14 pub const VALUE_UNKNOWN: i64 = 0;
15 pub const VALUE_NULL: i64 = 1;
16 pub const VALUE_STRING: i64 = 2;
17 pub const VALUE_INTEGER: i64 = 3;
18 pub const VALUE_BOOLEAN: i64 = 4;
19 pub const VALUE_DOUBLE: i64 = 5;
20 pub const VALUE_ARRAY: i64 = 6;
21 pub const VALUE_EDGE: i64 = 7;
22 pub const VALUE_NODE: i64 = 8;
23 pub const VALUE_PATH: i64 = 9;
24 pub const VALUE_MAP: i64 = 10;
25 pub const VALUE_POINT: i64 = 11;
26}
27
28#[derive(Clone, Debug, PartialEq)]
30pub enum GraphValue {
31 Unknown(Value),
33 Map(GraphMap),
38 Point(GeoPoint),
43 Path(GraphPath),
48 Node(Node),
53 Relation(Relationship),
58 Array(Vec<GraphValue>),
63 Integer(i64),
68 Double(f64),
73 String(String),
78 Boolean(bool),
83 Null,
86}
87
88#[derive(Debug, Clone, PartialEq)]
90pub struct GeoPoint {
91 pub latitude: f32,
93 pub longitude: f32,
95}
96
97#[derive(Debug, Clone, PartialEq)]
99pub struct GraphMap(pub HashMap<String, GraphValue>);
100
101impl GraphMap {
102 pub fn into_inner(self) -> HashMap<String, GraphValue> {
104 self.0
105 }
106
107 pub fn get<T: FromGraphValue>(&self, key: &str) -> RedisResult<Option<T>> {
109 match self.0.get(key) {
110 Some(val) => from_graph_value(val.clone()),
111 None => Ok(None),
112 }
113 }
114}
115
116#[derive(Debug, Clone, PartialEq)]
118pub struct Node {
119 pub id: i64,
121 pub label_ids: Vec<i64>,
123 pub properties: IndexMap<i64, GraphValue>,
125}
126
127impl Node {
128 pub fn new(id: i64, label_ids: Vec<i64>, properties: IndexMap<i64, GraphValue>) -> Self {
130 Self {
131 id,
132 label_ids,
133 properties,
134 }
135 }
136}
137
138#[derive(Debug, Clone, PartialEq)]
140pub struct Relationship {
141 pub id: i64,
143 pub label_id: i64,
145 pub src: i64,
147 pub dest: i64,
149 pub properties: IndexMap<i64, GraphValue>,
151}
152
153impl Relationship {
154 pub fn new(
156 id: i64,
157 label_id: i64,
158 src: i64,
159 dest: i64,
160 properties: IndexMap<i64, GraphValue>,
161 ) -> Self {
162 Self {
163 id,
164 label_id,
165 src,
166 dest,
167 properties,
168 }
169 }
170}
171
172pub trait PropertyAccess {
174 fn properties(&self) -> &IndexMap<i64, GraphValue>;
176
177 fn get_property_by_label_id<T: FromGraphValue>(&self, label_id: i64) -> RedisResult<Option<T>> {
179 match self.properties().get(&label_id) {
180 Some(val) => from_graph_value(val.clone()),
181 None => Ok(None),
182 }
183 }
184
185 fn get_property_by_index<T: FromGraphValue>(&self, idx: usize) -> RedisResult<T> {
188 from_graph_value(self.properties()[idx].clone())
189 }
190
191 fn property_values<T: FromGraphValue>(&self) -> RedisResult<T> {
193 from_graph_value(GraphValue::Array(
194 self.properties().values().cloned().collect(),
195 ))
196 }
197
198 fn into_property_values<T: FromGraphValue>(self) -> RedisResult<T>;
200}
201
202impl PropertyAccess for Node {
203 #[inline(always)]
204 fn properties(&self) -> &IndexMap<i64, GraphValue> {
205 &self.properties
206 }
207
208 fn into_property_values<T: FromGraphValue>(self) -> RedisResult<T> {
209 FromGraphValue::from_graph_value(GraphValue::Array(
210 self.properties.into_values().collect(),
211 ))
212 }
213}
214
215impl PropertyAccess for Relationship {
216 #[inline(always)]
217 fn properties(&self) -> &IndexMap<i64, GraphValue> {
218 &self.properties
219 }
220
221 fn into_property_values<T: FromGraphValue>(self) -> RedisResult<T> {
222 FromGraphValue::from_graph_value(GraphValue::Array(
223 self.properties.into_values().collect(),
224 ))
225 }
226}
227
228#[derive(Debug, PartialEq, Clone)]
230pub struct GraphPath {
231 pub nodes: Vec<Node>,
233 pub relationships: Vec<Relationship>,
235}
236
237pub trait FromGraphValue: Sized {
262 fn from_graph_value(value: GraphValue) -> RedisResult<Self>;
264}
265
266
267macro_rules! from_graph_value_for_int {
269 ( $t:ty ) => {
270 impl FromGraphValue for $t {
271 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
272 match value {
273 GraphValue::Integer(val) => <$t>::try_from(val).map_err(|_| create_rediserror(concat!("Could not convert to ", stringify!($t)))),
274 _ => Err(create_rediserror(&format!(
275 concat!("Cant convert {:?} to ", stringify!($t)),
276 value
277 ))),
278 }
279 }
280 }
281 };
282}
283
284impl FromGraphValue for f64 {
286 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
287 match value {
288 GraphValue::Double(val) => Ok(val),
289 _ => Err(create_rediserror(&format!(
290 concat!("Cant convert {:?} to ", stringify!($t)),
291 value
292 ))),
293 }
294 }
295}
296apply_macro!(
297 from_graph_value_for_int,
298 i8,
299 i16,
300 i32,
301 i64,
302 u8,
303 u16,
304 u32,
305 u64
306);
307
308impl FromGraphValue for bool {
309 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
310 match value {
311 GraphValue::Boolean(val) => Ok(val),
312 _ => Err(create_rediserror(&format!(
313 "Cant convert {:?} to bool",
314 value
315 ))),
316 }
317 }
318}
319
320impl FromGraphValue for () {
321 fn from_graph_value(_: GraphValue) -> RedisResult<Self> {
322 Ok(())
323 }
324}
325
326impl<T: FromGraphValue> FromGraphValue for Vec<T> {
327 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
328 match value {
329 GraphValue::Array(val) => Ok(val
330 .into_iter()
331 .map(FromGraphValue::from_graph_value)
332 .collect::<RedisResult<Self>>()?),
333 _ => Err(create_rediserror(&format!(
334 "Cant convert {:?} to Vec",
335 value
336 ))),
337 }
338 }
339}
340
341impl FromGraphValue for GraphMap {
342 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
343 match value {
344 GraphValue::Map(map) => Ok(map),
345 _ => Err(create_rediserror(&format!(
346 "Cant convert {:?} to GraphMap",
347 value
348 ))),
349 }
350 }
351}
352
353impl FromGraphValue for GraphPath {
354 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
355 match value {
356 GraphValue::Path(path) => Ok(path),
357 _ => Err(create_rediserror(&format!(
358 "Cant convert {:?} to GraphPath",
359 value
360 ))),
361 }
362 }
363}
364
365impl FromGraphValue for GeoPoint {
366 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
367 match value {
368 GraphValue::Point(point) => Ok(point),
369 _ => Err(create_rediserror(&format!(
370 "Cant convert {:?} to GeoPoint",
371 value
372 ))),
373 }
374 }
375}
376
377impl FromGraphValue for Node {
378 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
379 match value {
380 GraphValue::Node(node) => Ok(node),
381 _ => Err(create_rediserror(&format!(
382 "Cant convert {:?} to Node",
383 value
384 ))),
385 }
386 }
387}
388
389impl FromGraphValue for Relationship {
390 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
391 match value {
392 GraphValue::Relation(rel) => Ok(rel),
393 _ => Err(create_rediserror(&format!(
394 "Cant convert {:?} to Relationship",
395 value
396 ))),
397 }
398 }
399}
400
401impl<T: FromGraphValue> FromGraphValue for Option<T> {
402 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
403 match value {
404 GraphValue::Null => Ok(None),
405 val => Ok(Some(from_graph_value(val)?)),
406 }
407 }
408}
409
410impl FromGraphValue for GraphValue {
411 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
412 Ok(value)
413 }
414}
415
416impl FromGraphValue for String {
417 fn from_graph_value(value: GraphValue) -> RedisResult<Self> {
418 match value {
419 GraphValue::String(s) => Ok(s.to_string()),
420 _ => Err(create_rediserror(&format!(
421 "Cant convert {:?} to String",
422 value
423 ))),
424 }
425 }
426}
427
428macro_rules! from_graph_value_for_tuple {
430 () => ();
431 ($($name:ident,)+) => (
432 #[doc(hidden)]
433 impl<$($name: FromGraphValue),+> FromGraphValue for ($($name,)*) {
434 #[allow(non_snake_case, unused_variables)]
437 fn from_graph_value(v: GraphValue) -> RedisResult<($($name,)*)> {
438 match v {
439 GraphValue::Array(mut items) => {
440 let mut n = 0;
442 $(let $name = (); n += 1;)*
443 if items.len() != n {
444 return Err(create_rediserror(&format!("Wrong length to create Tuple {} from {:?}", std::any::type_name::<Self>(), &items)))
445 }
446
447 Ok(($({
448 let $name = ();
449 FromGraphValue::from_graph_value(items.remove(0))?
450 },)*))
451 }
452 _ => Err(create_rediserror(&format!("Can not create Tuple from {:?}", v)))
453 }
454 }
455 }
456 from_graph_value_for_tuple_peel!($($name,)*);
457 )
458}
459
460macro_rules! from_graph_value_for_tuple_peel {
464 ($name:ident, $($other:ident,)*) => (from_graph_value_for_tuple!($($other,)*);)
465}
466
467from_graph_value_for_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
468
469impl FromRedisValue for GraphValue {
470 fn from_redis_value(v: &Value) -> RedisResult<Self> {
471 match v {
472 Value::Bulk(data) if data.len() == 2 => match &data[0] {
473 Value::Int(type_) => convert_to_graphvalue(*type_, &data[1]),
474 value => Err(create_rediserror(&format!(
475 "Couldnt convert {:?} to GraphValue",
476 value
477 ))),
478 },
479 value => Err(create_rediserror(&format!(
480 "Couldnt convert {:?} to GraphValue",
481 value
482 ))),
483 }
484 }
485}
486
487impl FromRedisValue for GraphPath {
488 fn from_redis_value(v: &Value) -> RedisResult<Self> {
489 let (nodes, relationships): (GraphValue, GraphValue) = from_redis_value(v)?;
490 Ok(GraphPath {
491 nodes: from_graph_value(nodes)?,
492 relationships: from_graph_value(relationships)?,
493 })
494 }
495}
496
497impl FromRedisValue for GeoPoint {
498 fn from_redis_value(v: &Value) -> RedisResult<Self> {
499 let (latitude, longitude): (f32, f32) = from_redis_value(v)?;
500 Ok(GeoPoint {
501 latitude,
502 longitude,
503 })
504 }
505}
506
507impl FromRedisValue for GraphMap {
508 fn from_redis_value(v: &Value) -> RedisResult<Self> {
509 match v {
510 Value::Bulk(values) => {
511 let temp: Vec<(String, GraphValue)> = FromRedisValue::from_redis_values(values)?;
512 Ok(GraphMap(temp.into_iter().collect()))
513 }
514 value => Err(create_rediserror(&format!(
515 "Couldnt convert {:?} to GraphMap",
516 value
517 ))),
518 }
519 }
520}
521
522impl FromRedisValue for Node {
523 fn from_redis_value(v: &Value) -> RedisResult<Self> {
524 match v {
525 Value::Bulk(ref values) if values.len() == 3 => Ok(Node::new(
526 from_redis_value(&values[0])?,
527 from_redis_value(&values[1])?,
528 parse_properties(&values[2])?,
529 )),
530 val => Err(create_rediserror(&format!(
531 "Couldnt convert {:?} to Node",
532 val
533 ))),
534 }
535 }
536}
537
538
539impl FromRedisValue for Relationship {
540 fn from_redis_value(v: &Value) -> RedisResult<Self> {
541 match v {
542 Value::Bulk(ref values) if values.len() == 5 => Ok(Relationship::new(
543 from_redis_value(&values[0])?,
544 from_redis_value(&values[1])?,
545 from_redis_value(&values[2])?,
546 from_redis_value(&values[3])?,
547 parse_properties(&values[4])?,
548 )),
549 val => Err(create_rediserror(&format!(
550 "Couldnt convert {:?} to Relationship",
551 val
552 ))),
553 }
554 }
555}
556
557fn parse_properties(value: &Value) -> RedisResult<IndexMap<i64, GraphValue>> {
558 let temp: Vec<Value> = from_redis_value(value)?;
560 let properties: Vec<(i64, i64, Value)> = temp
561 .into_iter()
562 .map(|v| from_redis_value::<(i64, i64, Value)>(&v))
563 .collect::<RedisResult<_>>()?;
564 properties
565 .into_iter()
566 .map(
567 |(property_id, type_, value)| match convert_to_graphvalue(type_, &value) {
568 Ok(gvalue) => Ok((property_id, gvalue)),
569 Err(err) => Err(err),
570 },
571 )
572 .collect()
573}
574
575fn convert_to_graphvalue(type_: i64, val: &Value) -> RedisResult<GraphValue> {
576 use types::*;
577 match type_ {
578 VALUE_NODE => Ok(GraphValue::Node(from_redis_value(val)?)),
579 VALUE_EDGE => Ok(GraphValue::Relation(from_redis_value(val)?)),
580 VALUE_PATH => Ok(GraphValue::Path(from_redis_value(val)?)),
581 VALUE_MAP => Ok(GraphValue::Map(from_redis_value(val)?)),
582 VALUE_POINT => Ok(GraphValue::Point(from_redis_value(val)?)),
583 VALUE_NULL => Ok(GraphValue::Null),
584 VALUE_DOUBLE => Ok(GraphValue::Double(from_redis_value(val)?)),
585 VALUE_INTEGER => Ok(GraphValue::Integer(from_redis_value(val)?)),
586 VALUE_ARRAY => Ok(GraphValue::Array(from_redis_value(val)?)),
587 VALUE_STRING => Ok(GraphValue::String(from_redis_value(val)?)),
588 VALUE_BOOLEAN => Ok(GraphValue::Boolean({
589 match from_redis_value::<String>(val)?.as_str() {
591 "true" => true,
592 "false" => false,
593 _ => {
594 return Err(create_rediserror(&format!(
595 "Cant convert {:?} to bool",
596 val
597 )))
598 }
599 }
600 })),
601 VALUE_UNKNOWN | _ => Ok(GraphValue::Unknown(val.to_owned())),
602 }
603}