Skip to content

Commit

Permalink
Fixed / Added Option support for: String, i32, i64, f32, f64, uuid,
Browse files Browse the repository at this point in the history
date, and bool
  • Loading branch information
criminosis committed Mar 30, 2021
1 parent c6936ad commit 1cc84c9
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 2 deletions.
44 changes: 42 additions & 2 deletions gremlin-client/src/structure/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ impl std::convert::TryFrom<GValue> for uuid::Uuid {
fn try_from(value: GValue) -> GremlinResult<Self> {
match value {
GValue::Uuid(uid) => Ok(uid),
GValue::List(s) => from_list(s),
_ => Err(GremlinError::Cast(format!(
"Cannot cast {:?} to Uuid",
value
Expand All @@ -353,6 +354,7 @@ impl std::convert::TryFrom<GValue> for Date {
fn try_from(value: GValue) -> GremlinResult<Self> {
match value {
GValue::Date(date) => Ok(date),
GValue::List(s) => from_list(s),
_ => Err(GremlinError::Cast(format!(
"Cannot cast {:?} to DateTime<Utc>",
value
Expand All @@ -367,6 +369,7 @@ impl std::convert::TryFrom<GValue> for bool {
fn try_from(value: GValue) -> GremlinResult<Self> {
match value {
GValue::Bool(val) => Ok(val),
GValue::List(s) => from_list(s),
_ => Err(GremlinError::Cast(format!(
"Cannot cast {:?} to bool",
value
Expand All @@ -375,6 +378,36 @@ impl std::convert::TryFrom<GValue> for bool {
}
}

impl std::convert::TryFrom<GValue> for f32 {
type Error = crate::GremlinError;

fn try_from(value: GValue) -> GremlinResult<Self> {
match value {
GValue::Float(x) => Ok(x),
GValue::List(s) => from_list(s),
_ => Err(GremlinError::Cast(format!(
"Cannot cast {:?} to f32",
value
))),
}
}
}

impl std::convert::TryFrom<GValue> for f64 {
type Error = crate::GremlinError;

fn try_from(value: GValue) -> GremlinResult<Self> {
match value {
GValue::Double(x) => Ok(x),
GValue::List(s) => from_list(s),
_ => Err(GremlinError::Cast(format!(
"Cannot cast {:?} to f64",
value
))),
}
}
}

fn from_list<T>(glist: List) -> GremlinResult<T>
where
T: std::convert::TryFrom<GValue, Error = GremlinError>,
Expand All @@ -400,11 +433,18 @@ macro_rules! impl_try_from_option {
if let GValue::Null = value {
return Ok(None);
}
let res = value.try_into()?;
Ok(res)
let res: $t = value.try_into()?;
Ok(Some(res))
}
}
};
}

impl_try_from_option!(String);
impl_try_from_option!(i32);
impl_try_from_option!(i64);
impl_try_from_option!(f32);
impl_try_from_option!(f64);
impl_try_from_option!(Date);
impl_try_from_option!(uuid::Uuid);
impl_try_from_option!(bool);
145 changes: 145 additions & 0 deletions gremlin-client/tests/integration_client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod common;

use chrono::offset::TimeZone;
use chrono::Utc;
use gremlin_client::{
ConnectionOptions, GremlinClient, GremlinError, List, TlsOptions, ToGValue,
TraversalExplanation, TraversalMetrics, VertexProperty,
Expand Down Expand Up @@ -163,6 +164,150 @@ fn test_vertex_creation() {
);
}

#[test]
fn test_complex_vertex_creation_with_option_none_properties() {
let graph = graph();
let properties = graph
.execute(r#"g.addV('person').valueMap()"#, &[])
.expect("it should execute addV")
.filter_map(Result::ok)
.map(|f| f.take::<Map>())
.next()
.expect("There should be 1 traversal element")
.expect("The traversal response should not have errored");

//No properties should be present
assert_eq!(0, properties.len());

//Now demonstrate retrieving Option of the various value types
//All responses should be Ok and be containing a None
assert!(properties
.try_get::<&str, Option<String>>("name")
.unwrap()
.is_none());
assert!(properties
.try_get::<&str, Option<i32>>("age")
.unwrap()
.is_none());
assert!(properties
.try_get::<&str, Option<i64>>("time")
.unwrap()
.is_none());
assert!(properties
.try_get::<&str, Option<f32>>("score")
.unwrap()
.is_none());
assert!(properties
.try_get::<&str, Option<f64>>("score2")
.unwrap()
.is_none());
assert!(properties
.try_get::<&str, Option<chrono::DateTime<chrono::offset::Utc>>>("date")
.unwrap()
.is_none());
assert!(properties
.try_get::<&str, Option<uuid::Uuid>>("uuid")
.unwrap()
.is_none());
}

#[test]
fn test_complex_vertex_creation_with_option_some_properties() {
let graph = graph();
let q = r#"
g.addV('person')
.property('name',name)
.property('age',age)
.property('time',time)
.property('score',score)
.property('score2',score2)
.property('uuid',uuid)
.property('date',date)
.property('bool',true)
.valueMap()"#;

let uuid = uuid::Uuid::new_v4();
let now = Utc.timestamp(5, 0);
let params: &[(&str, &dyn ToGValue)] = &[
("name", &"mark"),
("age", &(22 as i32)),
("time", &(23 as i64)),
("score", &(3.2 as f32)),
("score2", &(3.2 as f64)),
("uuid", &uuid),
("date", &now),
];
let properties = graph
.execute(q, params)
.expect("it should execute addV")
.filter_map(Result::ok)
.map(|f| f.take::<Map>())
.next()
.expect("There should be 1 traversal element")
.expect("The traversal response should not have errored");

assert_eq!(8, properties.len());

//Now demonstrate retrieving Option of the various value types
//All responses should be Ok contain a Some value
assert_eq!(
"mark",
properties
.try_get::<&str, Option<String>>("name")
.unwrap()
.unwrap()
);
assert_eq!(
22,
properties
.try_get::<&str, Option<i32>>("age")
.unwrap()
.unwrap()
);
assert_eq!(
23,
properties
.try_get::<&str, Option<i64>>("time")
.unwrap()
.unwrap()
);
assert_eq!(
3.2 as f32,
properties
.try_get::<&str, Option<f32>>("score")
.unwrap()
.unwrap()
);
assert_eq!(
3.2 as f64,
properties
.try_get::<&str, Option<f64>>("score2")
.unwrap()
.unwrap()
);
assert_eq!(
now,
properties
.try_get::<&str, Option<chrono::DateTime<chrono::offset::Utc>>>("date")
.unwrap()
.unwrap()
);
assert_eq!(
uuid,
properties
.try_get::<&str, Option<uuid::Uuid>>("uuid")
.unwrap()
.unwrap()
);
assert_eq!(
true,
properties
.try_get::<&str, Option<bool>>("bool")
.unwrap()
.unwrap()
);
}

#[test]
fn test_complex_vertex_creation_with_properties() {
let graph = graph();
Expand Down

0 comments on commit 1cc84c9

Please sign in to comment.