From 6a94a88c0bb688e68f9443deb50ae0918eaa7fdd Mon Sep 17 00:00:00 2001 From: Allan Clements Date: Mon, 16 Sep 2024 20:21:56 -0500 Subject: [PATCH] Implemented None step --- gremlin-client/src/conversion.rs | 15 ++++++++- .../src/process/traversal/builder.rs | 6 ++++ .../src/process/traversal/graph_traversal.rs | 12 ++++++- gremlin-client/src/structure/mod.rs | 2 ++ gremlin-client/src/structure/null.rs | 2 ++ gremlin-client/tests/integration_traversal.rs | 31 +++++++++++++++++++ 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 gremlin-client/src/structure/null.rs diff --git a/gremlin-client/src/conversion.rs b/gremlin-client/src/conversion.rs index 5103e714..fd2102dd 100644 --- a/gremlin-client/src/conversion.rs +++ b/gremlin-client/src/conversion.rs @@ -1,6 +1,6 @@ use crate::{ process::traversal::Bytecode, - structure::{TextP, P as Predicate}, + structure::{Null, TextP, P as Predicate}, Edge, GKey, GValue, GremlinError, GremlinResult, IntermediateRepr, List, Map, Metric, Path, Property, Token, TraversalExplanation, TraversalMetrics, Vertex, VertexProperty, GID, }; @@ -134,6 +134,19 @@ impl_from_gvalue!(IntermediateRepr, GValue::IntermediateRepr); impl_from_gvalue!(chrono::DateTime, GValue::Date); impl_from_gvalue!(Traverser, GValue::Traverser); +impl FromGValue for Null { + fn from_gvalue(v: GValue) -> GremlinResult { + match v { + GValue::Null => Ok(crate::structure::Null {}), + _ => Err(GremlinError::Cast(format!( + "Cannot convert {:?} to {}", + v, + stringify!($t) + ))), + } + } +} + impl FromGValue for GKey { fn from_gvalue(v: GValue) -> GremlinResult { match v { diff --git a/gremlin-client/src/process/traversal/builder.rs b/gremlin-client/src/process/traversal/builder.rs index de159676..49491aea 100644 --- a/gremlin-client/src/process/traversal/builder.rs +++ b/gremlin-client/src/process/traversal/builder.rs @@ -299,6 +299,12 @@ impl TraversalBuilder { self } + pub fn none(mut self) -> Self { + self.bytecode.add_step(String::from("none"), vec![]); + + self + } + pub fn label(mut self) -> Self { self.bytecode.add_step(String::from("label"), vec![]); diff --git a/gremlin-client/src/process/traversal/graph_traversal.rs b/gremlin-client/src/process/traversal/graph_traversal.rs index b0984a53..be734946 100644 --- a/gremlin-client/src/process/traversal/graph_traversal.rs +++ b/gremlin-client/src/process/traversal/graph_traversal.rs @@ -22,7 +22,7 @@ use crate::process::traversal::strategies::{ RemoteStrategy, TraversalStrategies, TraversalStrategy, }; use crate::process::traversal::{Bytecode, Scope, TraversalBuilder, WRITE_OPERATORS}; -use crate::structure::{Cardinality, Labels}; +use crate::structure::{Cardinality, Labels, Null}; use crate::{ structure::GIDs, structure::GProperty, structure::IntoPredicate, Edge, GValue, GremlinClient, List, Map, Path, Vertex, @@ -302,6 +302,16 @@ impl> GraphTraversal { GraphTraversal::new(self.terminator, self.builder) } + ///Filters all objects from the traversal stream. Generally only useful for applying traversal sideffects and avoiding unwanted response I/O + pub fn none(mut self) -> GraphTraversal + where + T: Terminator, + { + self.builder = self.builder.none(); + + GraphTraversal::new(self.terminator, self.builder) + } + pub fn label(mut self) -> GraphTraversal where T: Terminator, diff --git a/gremlin-client/src/structure/mod.rs b/gremlin-client/src/structure/mod.rs index a2695315..523adbc1 100644 --- a/gremlin-client/src/structure/mod.rs +++ b/gremlin-client/src/structure/mod.rs @@ -10,6 +10,7 @@ mod macros; mod map; mod merge; mod metrics; +mod null; mod p; mod path; mod pop; @@ -28,6 +29,7 @@ pub use self::edge::Edge; pub use self::gid::{GIDs, GID}; pub use self::list::List; pub use self::metrics::{IntermediateRepr, Metric, TraversalExplanation, TraversalMetrics}; +pub use self::null::Null; pub use self::path::Path; pub use self::property::Property; pub use self::result::GResultSet; diff --git a/gremlin-client/src/structure/null.rs b/gremlin-client/src/structure/null.rs new file mode 100644 index 00000000..76dbac88 --- /dev/null +++ b/gremlin-client/src/structure/null.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Clone)] +pub struct Null {} diff --git a/gremlin-client/tests/integration_traversal.rs b/gremlin-client/tests/integration_traversal.rs index 6f973dda..20564cb0 100644 --- a/gremlin-client/tests/integration_traversal.rs +++ b/gremlin-client/tests/integration_traversal.rs @@ -2603,6 +2603,37 @@ fn test_coalesce_unfold() { ); } +#[test] +fn test_none_step() { + let client = graph(); + + drop_vertices(&client, "test_none_step").unwrap(); + + let g = traversal().with_remote(client); + + //The addition of a None step however should not IO a vertex back + let mut iter = g + .add_v("test_none_step") + .none() + .iter() + .expect("Should get a iter back"); + assert!( + iter.next().is_none(), + "But the iter should have no elements because of the None step" + ); + + //Make sure the vertex is present in the graph + let vertex_count = g + .v(()) + .has_label("test_none_step") + .count() + .next() + .ok() + .flatten() + .expect("Should have gotten a response"); + assert_eq!(1, vertex_count); +} + #[test] #[cfg(feature = "derive")] fn test_traversal_vertex_mapping() {