gremlin_client/structure/
value.rs

1use crate::conversion::{BorrowFromGValue, FromGValue};
2use crate::process::traversal::{Bytecode, Order, Scope};
3use crate::structure::traverser::Traverser;
4use crate::structure::{
5    label::LabelType, Cardinality, Edge, GKey, IntermediateRepr, List, Map, Metric, Path, Property,
6    Set, Token, TraversalExplanation, TraversalMetrics, Vertex, VertexProperty,
7};
8use crate::structure::{Pop, TextP, P, T};
9use crate::{GremlinError, GremlinResult};
10use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
11pub type Date = chrono::DateTime<chrono::offset::Utc>;
12use std::convert::TryInto;
13use std::hash::Hash;
14/// Represent possible values coming from the [Gremlin Server](http://tinkerpop.apache.org/docs/3.4.0/dev/io/)
15#[allow(clippy::large_enum_variant)]
16#[derive(Debug, PartialEq, Clone)]
17pub enum GValue {
18    Null,
19    Vertex(Vertex),
20    Edge(Edge),
21    VertexProperty(VertexProperty),
22    Property(Property),
23    Uuid(uuid::Uuid),
24    Int32(i32),
25    Int64(i64),
26    Float(f32),
27    Double(f64),
28    Date(Date),
29    List(List),
30    Set(Set),
31    Map(Map),
32    Token(Token),
33    String(String),
34    Path(Path),
35    TraversalMetrics(TraversalMetrics),
36    Metric(Metric),
37    TraversalExplanation(TraversalExplanation),
38    IntermediateRepr(IntermediateRepr),
39    P(P),
40    T(T),
41    Bytecode(Bytecode),
42    Traverser(Traverser),
43    Scope(Scope),
44    Order(Order),
45    Bool(bool),
46    TextP(TextP),
47    Pop(Pop),
48    Cardinality(Cardinality),
49}
50
51impl GValue {
52    pub fn take<T>(self) -> GremlinResult<T>
53    where
54        T: FromGValue,
55    {
56        T::from_gvalue(self)
57    }
58
59    pub fn get<'a, T>(&'a self) -> GremlinResult<&'a T>
60    where
61        T: BorrowFromGValue,
62    {
63        T::from_gvalue(self)
64    }
65}
66
67impl From<Date> for GValue {
68    fn from(val: Date) -> Self {
69        GValue::Date(val)
70    }
71}
72
73impl From<String> for GValue {
74    fn from(val: String) -> Self {
75        GValue::String(val)
76    }
77}
78
79impl From<&String> for GValue {
80    fn from(val: &String) -> Self {
81        GValue::String(val.clone())
82    }
83}
84
85impl From<i32> for GValue {
86    fn from(val: i32) -> Self {
87        GValue::Int32(val)
88    }
89}
90
91impl From<i64> for GValue {
92    fn from(val: i64) -> Self {
93        GValue::Int64(val)
94    }
95}
96
97impl From<f32> for GValue {
98    fn from(val: f32) -> Self {
99        GValue::Float(val)
100    }
101}
102impl From<f64> for GValue {
103    fn from(val: f64) -> Self {
104        GValue::Double(val)
105    }
106}
107
108impl<'a> From<&'a str> for GValue {
109    fn from(val: &'a str) -> Self {
110        GValue::String(String::from(val))
111    }
112}
113
114impl From<Vertex> for GValue {
115    fn from(val: Vertex) -> Self {
116        GValue::Vertex(val)
117    }
118}
119
120impl From<&Vertex> for GValue {
121    fn from(val: &Vertex) -> Self {
122        GValue::Vertex(val.clone())
123    }
124}
125
126impl From<Path> for GValue {
127    fn from(val: Path) -> Self {
128        GValue::Path(val)
129    }
130}
131impl From<Edge> for GValue {
132    fn from(val: Edge) -> Self {
133        GValue::Edge(val)
134    }
135}
136
137impl From<VertexProperty> for GValue {
138    fn from(val: VertexProperty) -> Self {
139        GValue::VertexProperty(val)
140    }
141}
142
143impl From<Traverser> for GValue {
144    fn from(val: Traverser) -> Self {
145        GValue::Traverser(val)
146    }
147}
148impl From<TraversalMetrics> for GValue {
149    fn from(val: TraversalMetrics) -> Self {
150        GValue::TraversalMetrics(val)
151    }
152}
153
154impl From<TraversalExplanation> for GValue {
155    fn from(val: TraversalExplanation) -> Self {
156        GValue::TraversalExplanation(val)
157    }
158}
159
160impl From<Metric> for GValue {
161    fn from(val: Metric) -> Self {
162        GValue::Metric(val)
163    }
164}
165
166impl From<Property> for GValue {
167    fn from(val: Property) -> Self {
168        GValue::Property(val)
169    }
170}
171
172impl From<Scope> for GValue {
173    fn from(val: Scope) -> Self {
174        GValue::Scope(val)
175    }
176}
177
178impl From<Order> for GValue {
179    fn from(val: Order) -> Self {
180        GValue::Order(val)
181    }
182}
183impl From<Token> for GValue {
184    fn from(val: Token) -> Self {
185        GValue::Token(val)
186    }
187}
188
189impl From<HashMap<String, GValue>> for GValue {
190    fn from(val: HashMap<String, GValue>) -> Self {
191        GValue::Map(Map::from(val))
192    }
193}
194
195impl From<HashMap<GKey, GValue>> for GValue {
196    fn from(val: HashMap<GKey, GValue>) -> Self {
197        GValue::Map(Map::from(val))
198    }
199}
200
201impl From<BTreeMap<String, GValue>> for GValue {
202    fn from(val: BTreeMap<String, GValue>) -> Self {
203        GValue::Map(Map::from(val))
204    }
205}
206
207impl From<Vec<GValue>> for GValue {
208    fn from(val: Vec<GValue>) -> Self {
209        GValue::List(List::new(val))
210    }
211}
212
213impl From<GValue> for Vec<GValue> {
214    fn from(val: GValue) -> Self {
215        vec![val]
216    }
217}
218
219impl From<GValue> for VecDeque<GValue> {
220    fn from(val: GValue) -> Self {
221        match val {
222            GValue::List(l) => VecDeque::from(l.take()),
223            GValue::Set(l) => VecDeque::from(l.take()),
224            _ => VecDeque::from(vec![val]),
225        }
226    }
227}
228
229impl From<GKey> for GValue {
230    fn from(val: GKey) -> Self {
231        match val {
232            GKey::String(s) => GValue::String(s),
233            GKey::Token(s) => GValue::String(s.value().clone()),
234            GKey::Vertex(v) => GValue::Vertex(v),
235            GKey::Edge(v) => GValue::Edge(v),
236        }
237    }
238}
239
240impl From<P> for GValue {
241    fn from(val: P) -> GValue {
242        GValue::P(val)
243    }
244}
245
246impl From<TextP> for GValue {
247    fn from(val: TextP) -> GValue {
248        GValue::TextP(val)
249    }
250}
251
252impl From<T> for GValue {
253    fn from(val: T) -> GValue {
254        GValue::T(val)
255    }
256}
257
258impl From<Bytecode> for GValue {
259    fn from(val: Bytecode) -> GValue {
260        GValue::Bytecode(val)
261    }
262}
263
264impl From<bool> for GValue {
265    fn from(val: bool) -> GValue {
266        GValue::Bool(val)
267    }
268}
269
270impl From<LabelType> for GValue {
271    fn from(val: LabelType) -> GValue {
272        match val {
273            LabelType::Str(val) => val.into(),
274            LabelType::Bool(val) => val.into(),
275            LabelType::T(val) => val.into(),
276        }
277    }
278}
279
280impl From<Cardinality> for GValue {
281    fn from(val: Cardinality) -> GValue {
282        GValue::Cardinality(val)
283    }
284}
285
286impl From<uuid::Uuid> for GValue {
287    fn from(val: uuid::Uuid) -> GValue {
288        GValue::Uuid(val)
289    }
290}
291
292impl std::convert::TryFrom<GValue> for String {
293    type Error = crate::GremlinError;
294
295    fn try_from(value: GValue) -> GremlinResult<Self> {
296        match value {
297            GValue::String(s) => Ok(s),
298            GValue::List(s) => from_list(s),
299            GValue::VertexProperty(vp) => vp.take(),
300            GValue::Property(p) => p.take(),
301            _ => Err(GremlinError::Cast(format!(
302                "Cannot cast {:?} to String",
303                value
304            ))),
305        }
306    }
307}
308
309impl std::convert::TryFrom<GValue> for i32 {
310    type Error = crate::GremlinError;
311
312    fn try_from(value: GValue) -> GremlinResult<Self> {
313        match value {
314            GValue::Int32(s) => Ok(s),
315            GValue::List(s) => from_list(s),
316            GValue::VertexProperty(vp) => vp.take(),
317            GValue::Property(p) => p.take(),
318            _ => Err(GremlinError::Cast(format!(
319                "Cannot cast {:?} to i32",
320                value
321            ))),
322        }
323    }
324}
325
326impl std::convert::TryFrom<GValue> for i64 {
327    type Error = crate::GremlinError;
328
329    fn try_from(value: GValue) -> GremlinResult<Self> {
330        match value {
331            GValue::Int64(s) => Ok(s),
332            GValue::List(s) => from_list(s),
333            GValue::VertexProperty(vp) => vp.take(),
334            GValue::Property(p) => p.take(),
335            _ => Err(GremlinError::Cast(format!(
336                "Cannot cast {:?} to i64",
337                value
338            ))),
339        }
340    }
341}
342
343impl std::convert::TryFrom<GValue> for uuid::Uuid {
344    type Error = crate::GremlinError;
345
346    fn try_from(value: GValue) -> GremlinResult<Self> {
347        match value {
348            GValue::Uuid(uid) => Ok(uid),
349            GValue::List(s) => from_list(s),
350            GValue::VertexProperty(vp) => vp.take(),
351            GValue::Property(p) => p.take(),
352            _ => Err(GremlinError::Cast(format!(
353                "Cannot cast {:?} to Uuid",
354                value
355            ))),
356        }
357    }
358}
359
360impl std::convert::TryFrom<GValue> for Date {
361    type Error = crate::GremlinError;
362
363    fn try_from(value: GValue) -> GremlinResult<Self> {
364        match value {
365            GValue::Date(date) => Ok(date),
366            GValue::List(s) => from_list(s),
367            GValue::VertexProperty(vp) => vp.take(),
368            GValue::Property(p) => p.take(),
369            _ => Err(GremlinError::Cast(format!(
370                "Cannot cast {:?} to DateTime<Utc>",
371                value
372            ))),
373        }
374    }
375}
376
377impl std::convert::TryFrom<GValue> for bool {
378    type Error = crate::GremlinError;
379
380    fn try_from(value: GValue) -> GremlinResult<Self> {
381        match value {
382            GValue::Bool(val) => Ok(val),
383            GValue::List(s) => from_list(s),
384            GValue::VertexProperty(vp) => vp.take(),
385            GValue::Property(p) => p.take(),
386            _ => Err(GremlinError::Cast(format!(
387                "Cannot cast {:?} to bool",
388                value
389            ))),
390        }
391    }
392}
393
394impl std::convert::TryFrom<GValue> for f32 {
395    type Error = crate::GremlinError;
396
397    fn try_from(value: GValue) -> GremlinResult<Self> {
398        match value {
399            GValue::Float(x) => Ok(x),
400            GValue::List(s) => from_list(s),
401            GValue::VertexProperty(vp) => vp.take(),
402            GValue::Property(p) => p.take(),
403            _ => Err(GremlinError::Cast(format!(
404                "Cannot cast {:?} to f32",
405                value
406            ))),
407        }
408    }
409}
410
411impl std::convert::TryFrom<GValue> for f64 {
412    type Error = crate::GremlinError;
413
414    fn try_from(value: GValue) -> GremlinResult<Self> {
415        match value {
416            GValue::Double(x) => Ok(x),
417            GValue::List(s) => from_list(s),
418            GValue::VertexProperty(vp) => vp.take(),
419            GValue::Property(p) => p.take(),
420            _ => Err(GremlinError::Cast(format!(
421                "Cannot cast {:?} to f64",
422                value
423            ))),
424        }
425    }
426}
427
428impl std::convert::TryFrom<GValue> for BTreeMap<String, GValue> {
429    type Error = crate::GremlinError;
430
431    fn try_from(value: GValue) -> GremlinResult<Self> {
432        if let GValue::Map(m) = value {
433            m.try_into()
434        } else {
435            Err(GremlinError::Cast(format!(
436                "Cannot cast {:?} to BTreeMap<String, GValue>",
437                value
438            )))
439        }
440    }
441}
442
443impl std::convert::TryFrom<GValue> for HashMap<GKey, GValue> {
444    type Error = crate::GremlinError;
445
446    fn try_from(value: GValue) -> GremlinResult<Self> {
447        if let GValue::Map(m) = value {
448            Ok(m.into())
449        } else {
450            Err(GremlinError::Cast(format!(
451                "Cannot cast {:?} to HashMap<GKey, GValue>",
452                value
453            )))
454        }
455    }
456}
457
458impl std::convert::TryFrom<GValue> for HashMap<String, GValue> {
459    type Error = crate::GremlinError;
460
461    fn try_from(value: GValue) -> GremlinResult<Self> {
462        if let GValue::Map(m) = value {
463            m.try_into()
464        } else {
465            Err(GremlinError::Cast(format!(
466                "Cannot cast {:?} to HashMap<String, GValue>",
467                value
468            )))
469        }
470    }
471}
472
473fn from_list<T>(glist: List) -> GremlinResult<T>
474where
475    T: std::convert::TryFrom<GValue, Error = GremlinError>,
476{
477    let mut vec = glist.take();
478
479    match vec.len() {
480        1 => vec.pop().unwrap().try_into(),
481        _ => Err(GremlinError::Cast(format!(
482            "Cannot cast a List to {}",
483            std::any::type_name::<T>(),
484        ))),
485    }
486}
487
488// Optional
489
490macro_rules! impl_try_from_option {
491    ($t:ty) => {
492        impl std::convert::TryFrom<GValue> for Option<$t> {
493            type Error = crate::GremlinError;
494
495            fn try_from(value: GValue) -> GremlinResult<Self> {
496                if let GValue::Null = value {
497                    return Ok(None);
498                }
499                let res: $t = value.try_into()?;
500                Ok(Some(res))
501            }
502        }
503    };
504}
505
506impl_try_from_option!(String);
507impl_try_from_option!(i32);
508impl_try_from_option!(i64);
509impl_try_from_option!(f32);
510impl_try_from_option!(f64);
511impl_try_from_option!(Date);
512impl_try_from_option!(uuid::Uuid);
513impl_try_from_option!(bool);
514
515fn for_list<T>(glist: &List) -> GremlinResult<Vec<T>>
516where
517    T: std::convert::TryFrom<GValue, Error = GremlinError>,
518{
519    glist
520        .iter()
521        .map(|x| x.clone().try_into())
522        .collect::<GremlinResult<Vec<T>>>()
523}
524
525fn for_list_to_set<T>(glist: &List) -> GremlinResult<HashSet<T>>
526where
527    T: std::convert::TryFrom<GValue, Error = GremlinError> + Hash + Eq,
528{
529    glist
530        .iter()
531        .map(|x| x.clone().try_into())
532        .collect::<GremlinResult<HashSet<T>>>()
533}
534
535fn for_set<T>(gset: &Set) -> GremlinResult<HashSet<T>>
536where
537    T: std::convert::TryFrom<GValue, Error = GremlinError> + Hash + Eq,
538{
539    gset.iter()
540        .map(|x| x.clone().try_into())
541        .collect::<GremlinResult<HashSet<T>>>()
542}
543
544macro_rules! impl_try_from_set {
545    ($t:ty) => {
546        //Ideally this would be handled in conversion.rs but because the GValue::Set holds a Vec
547        //we handle converting it here
548        impl FromGValue for HashSet<$t> {
549            fn from_gvalue(value: GValue) -> GremlinResult<Self> {
550                match value {
551                    GValue::List(s) => for_list_to_set(&s),
552                    GValue::Set(s) => for_set(&s),
553                    GValue::Null => Ok(HashSet::new()),
554                    _ => Err(GremlinError::Cast(format!(
555                        "Cannot cast {:?} to HashSet",
556                        value
557                    ))),
558                }
559            }
560        }
561
562        impl std::convert::TryFrom<GValue> for HashSet<$t> {
563            type Error = crate::GremlinError;
564
565            fn try_from(value: GValue) -> GremlinResult<Self> {
566                match value {
567                    GValue::List(s) => for_list_to_set(&s),
568                    GValue::Set(s) => for_set(&s),
569                    GValue::Null => Ok(HashSet::new()),
570                    _ => Err(GremlinError::Cast(format!(
571                        "Cannot cast {:?} to HashSet",
572                        value
573                    ))),
574                }
575            }
576        }
577
578        impl std::convert::TryFrom<&GValue> for HashSet<$t> {
579            type Error = crate::GremlinError;
580
581            fn try_from(value: &GValue) -> GremlinResult<Self> {
582                match value {
583                    GValue::List(s) => for_list_to_set(s),
584                    GValue::Set(s) => for_set(s),
585                    GValue::Null => Ok(HashSet::new()),
586                    _ => Err(GremlinError::Cast(format!(
587                        "Cannot cast {:?} to HashSet",
588                        value
589                    ))),
590                }
591            }
592        }
593    };
594}
595
596impl_try_from_set!(String);
597impl_try_from_set!(i32);
598impl_try_from_set!(i64);
599impl_try_from_set!(Date);
600impl_try_from_set!(uuid::Uuid);
601impl_try_from_set!(bool);
602//floats do not conform to the Eq or Hash traits
603// impl_try_from_set!(f32);
604// impl_try_from_set!(f64);
605
606macro_rules! impl_try_from_list {
607    ($t:ty) => {
608        impl std::convert::TryFrom<GValue> for Vec<$t> {
609            type Error = crate::GremlinError;
610
611            fn try_from(value: GValue) -> GremlinResult<Self> {
612                match value {
613                    GValue::List(s) => for_list(&s),
614                    GValue::Null => Ok(Vec::new()),
615                    _ => Err(GremlinError::Cast(format!(
616                        "Cannot cast {:?} to Vec",
617                        value
618                    ))),
619                }
620            }
621        }
622
623        impl std::convert::TryFrom<&GValue> for Vec<$t> {
624            type Error = crate::GremlinError;
625
626            fn try_from(value: &GValue) -> GremlinResult<Self> {
627                match value {
628                    GValue::List(s) => for_list(s),
629                    GValue::Null => Ok(Vec::new()),
630                    _ => Err(GremlinError::Cast(format!(
631                        "Cannot cast {:?} to Vec",
632                        value
633                    ))),
634                }
635            }
636        }
637    };
638}
639
640impl_try_from_list!(String);
641impl_try_from_list!(i32);
642impl_try_from_list!(i64);
643impl_try_from_list!(f32);
644impl_try_from_list!(f64);
645impl_try_from_list!(Date);
646impl_try_from_list!(uuid::Uuid);
647impl_try_from_list!(bool);