You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2021/11/09 11:31:47 UTC
[tinkerpop] 01/01: TINKERPOP-2613 Improved behavior of V(null)
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch TINKERPOP-2613
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 1d2a8453e09fb53f721b076dc11fbb87d18bf244
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Tue Nov 9 06:27:40 2021 -0500
TINKERPOP-2613 Improved behavior of V(null)
Prevented NPE and instead filtered results.
---
CHANGELOG.asciidoc | 1 +
.../traversal/dsl/graph/GraphTraversal.java | 9 ++--
.../traversal/dsl/graph/GraphTraversalSource.java | 14 ++++--
.../gremlin/structure/util/ElementHelper.java | 4 +-
.../translator/JavascriptTranslatorTest.java | 8 +++-
.../Process/Traversal/GraphTraversal.cs | 11 ++++-
.../Process/Traversal/GraphTraversalSource.cs | 22 +++++++--
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 5 ++
gremlin-javascript/build/generate.groovy | 4 ++
.../gremlin-javascript/test/cucumber/gremlin.js | 5 ++
gremlin-python/src/main/python/radish/gremlin.py | 5 ++
gremlin-test/features/map/Vertex.feature | 54 ++++++++++++++++++++++
.../gremlin/tinkergraph/structure/TinkerGraph.java | 2 +
13 files changed, 126 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d3fc76a..e3c1e7f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@ limitations under the License.
* Created `gremlin-annotations` module where the `@GremlinDsl` annotation and related code has been moved.
* Removed `groovy` and `groovy-json` dependencies from `gremlin-driver` as well as related `JsonBuilder` serialization support.
* Replaced log4j usage with logback where builds rely on and packaged distributions now contain the latter.
+* Improved behavior of `V()` when `null` is an argument producing a filtering behavior rather than an exception.
* Prevented metrics computation unless the traversal is in a locked state.
* Created a way to produce a corpus of Gremlin traversals via `FeatureReader` and `DocumentationReader` in `gremlin-language`.
* Exposed Gherkin tests as part of the provider test suite.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 9a45300..cd64f55 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -315,8 +315,10 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* @since 3.1.0-incubating
*/
public default GraphTraversal<S, Vertex> V(final Object... vertexIdsOrElements) {
- this.asAdmin().getBytecode().addStep(Symbols.V, vertexIdsOrElements);
- return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, vertexIdsOrElements));
+ // a single null is [null]
+ final Object[] ids = null == vertexIdsOrElements ? new Object[] { null } : vertexIdsOrElements;
+ this.asAdmin().getBytecode().addStep(Symbols.V, ids);
+ return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, ids));
}
/**
@@ -1606,8 +1608,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
public default GraphTraversal<S, E> hasId(final Object id, final Object... otherIds) {
if (id instanceof P) {
return this.hasId((P) id);
- }
- else {
+ } else {
Object[] ids;
if (id instanceof Object[]) {
ids = (Object[]) id;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index b7471b1..cae7e5c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -365,21 +365,25 @@ public class GraphTraversalSource implements TraversalSource {
* unique identifier.
*/
public GraphTraversal<Vertex, Vertex> V(final Object... vertexIds) {
+ // a single null is [null]
+ final Object[] ids = null == vertexIds ? new Object[] { null } : vertexIds;
final GraphTraversalSource clone = this.clone();
- clone.bytecode.addStep(GraphTraversal.Symbols.V, vertexIds);
+ clone.bytecode.addStep(GraphTraversal.Symbols.V, ids);
final GraphTraversal.Admin<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(clone);
- return traversal.addStep(new GraphStep<>(traversal, Vertex.class, true, vertexIds));
+ return traversal.addStep(new GraphStep<>(traversal, Vertex.class, true, ids));
}
/**
* Spawns a {@link GraphTraversal} starting with all edges or some subset of edges as specified by their unique
* identifier.
*/
- public GraphTraversal<Edge, Edge> E(final Object... edgesIds) {
+ public GraphTraversal<Edge, Edge> E(final Object... edgeIds) {
+ // a single null is [null]
+ final Object[] ids = null == edgeIds ? new Object[] { null } : edgeIds;
final GraphTraversalSource clone = this.clone();
- clone.bytecode.addStep(GraphTraversal.Symbols.E, edgesIds);
+ clone.bytecode.addStep(GraphTraversal.Symbols.E, ids);
final GraphTraversal.Admin<Edge, Edge> traversal = new DefaultGraphTraversal<>(clone);
- return traversal.addStep(new GraphStep<>(traversal, Edge.class, true, edgesIds));
+ return traversal.addStep(new GraphStep<>(traversal, Edge.class, true, ids));
}
/**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
index 48e8733..a742e7b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/ElementHelper.java
@@ -549,10 +549,10 @@ public final class ElementHelper {
// it is OK to evaluate equality of ids via toString() now given that the toString() the test suite
// enforces the value of id.()toString() to be a first class representation of the identifier
if (1 == providedIds.length) {
- return id.toString().equals(providedIds[0].toString());
+ return id != null && providedIds[0] != null && id.toString().equals(providedIds[0].toString());
} else {
for (final Object temp : providedIds) {
- if (temp.toString().equals(id.toString()))
+ if (id != null && temp != null && temp.toString().equals(id.toString()))
return true;
}
return false;
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
index 1a0f1c0..f2db89b 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
@@ -119,7 +119,13 @@ public class JavascriptTranslatorTest {
@Test
public void shouldHaveNull() {
- translator.translate(g.inject(null, null).asAdmin().getBytecode()).getScript();
+ assertEquals("g.inject(null,null)", translator.translate(g.inject(null, null).asAdmin().getBytecode()).getScript());
+ assertEquals("g.V()", translator.translate(g.V().asAdmin().getBytecode()).getScript());
+ assertEquals("g.V(null)", translator.translate(g.V(null).asAdmin().getBytecode()).getScript());
+ assertEquals("g.V(null,null)", translator.translate(g.V(null, null).asAdmin().getBytecode()).getScript());
+ assertEquals("g.E()", translator.translate(g.E().asAdmin().getBytecode()).getScript());
+ assertEquals("g.E(null)", translator.translate(g.E(null).asAdmin().getBytecode()).getScript());
+ assertEquals("g.E(null,null)", translator.translate(g.E(null, null).asAdmin().getBytecode()).getScript());
}
@Test
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index 2bc4de8..328e506 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -79,8 +79,15 @@ namespace Gremlin.Net.Process.Traversal
/// </summary>
public GraphTraversal<S, Vertex> V (params object[] vertexIdsOrElements)
{
- var args = new List<object>(0 + vertexIdsOrElements.Length) {};
- args.AddRange(vertexIdsOrElements);
+ var args = null == vertexIdsOrElements ? new List<object>(1) {} : new List<object>(0 + vertexIdsOrElements.Length) {};
+ if (null == vertexIdsOrElements)
+ {
+ args.Add(null);
+ }
+ else
+ {
+ args.AddRange(vertexIdsOrElements);
+ }
Bytecode.AddStep("V", args.ToArray());
return Wrap<S, Vertex>(this);
}
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
index 2ab9d01..ae5b1d9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
@@ -296,8 +296,15 @@ namespace Gremlin.Net.Process.Traversal
public GraphTraversal<Edge, Edge> E(params object[] edgesIds)
{
var traversal = new GraphTraversal<Edge, Edge>(TraversalStrategies, new Bytecode(Bytecode));
- var args = new List<object>(0 + edgesIds.Length) {};
- args.AddRange(edgesIds);
+ var args = null == edgesIds ? new List<object>(1) {} : new List<object>(0 + edgesIds.Length) {};
+ if (null == edgesIds)
+ {
+ args.Add(null);
+ }
+ else
+ {
+ args.AddRange(edgesIds);
+ }
traversal.Bytecode.AddStep("E", args.ToArray());
return traversal;
}
@@ -309,8 +316,15 @@ namespace Gremlin.Net.Process.Traversal
public GraphTraversal<Vertex, Vertex> V(params object[] vertexIds)
{
var traversal = new GraphTraversal<Vertex, Vertex>(TraversalStrategies, new Bytecode(Bytecode));
- var args = new List<object>(0 + vertexIds.Length) {};
- args.AddRange(vertexIds);
+ var args = null == vertexIds ? new List<object>(1) {} : new List<object>(0 + vertexIds.Length) {};
+ if (null == vertexIds)
+ {
+ args.Add(null);
+ }
+ else
+ {
+ args.AddRange(vertexIds);
+ }
traversal.Bytecode.AddStep("V", args.ToArray());
return traversal;
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 2c8d242..8cd8876 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -646,6 +646,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object,object>().With("~tinkerpop.valueMap.tokens")}},
{"g_VX1X_valueMapXname_locationX_byXunfoldX_by", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).ValueMap<object,object>("name","location").By(__.Unfold<object>()).By()}},
{"g_V_valueMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object,object>("name","age",null)}},
+ {"g_VXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(null)}},
+ {"g_VXlistXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"])}},
+ {"g_VX1_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],null)}},
{"g_VXlistX1_2_3XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Values<object>("name")}},
{"g_VXlistXv1_v2_v3XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"]).Values<object>("name")}},
{"g_V", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V()}},
@@ -686,6 +689,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").V().HasLabel("software").Values<object>("name")}},
{"g_V_hasLabelXloopsX_bothEXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").BothE("self")}},
{"g_V_hasLabelXloopsX_bothXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").Both("self")}},
+ {"g_injectX1X_VXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(1).V(null)}},
+ {"g_injectX1X_VX1_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(1).V(p["vid1"],null)}},
{"Primitives_Number_eqXintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}},
{"g_V_valueXnameX_aggregateXxX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate("x").Cap<object>("x")}},
{"g_V_valueXnameX_aggregateXglobal_xX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate(Scope.Global,"x").Cap<object>("x")}},
diff --git a/gremlin-javascript/build/generate.groovy b/gremlin-javascript/build/generate.groovy
index 75e7087..572d29c 100644
--- a/gremlin-javascript/build/generate.groovy
+++ b/gremlin-javascript/build/generate.groovy
@@ -99,6 +99,10 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
// solution may become necessary as testing of nulls expands.
def staticTranslate = [
g_injectXnull_nullX: " g_injectXnull_nullX: [function({g}) { return g.inject(null,null) }], ",
+ g_V_hasIdXnullX: " g_V_hasIdXnullX: [function({g}) { return g.V().hasId(null) }], ",
+ g_V_hasIdX1_nullX: " g_V_hasIdX1_nullX: [function({g, vid1}) { return g.V().hasId(vid1,null) }], ",
+ g_injectX1X_VXnullX: " g_injectX1X_VXnullX: [function({g}) { return g.inject(1).V(null) }], ",
+ g_injectX1X_VX1_nullX: " g_injectX1X_VX1_nullX: [function({g, vid1}) { return g.inject(1).V(vid1,null) }], ",
g_VX1X_valuesXageX_injectXnull_nullX: " g_VX1X_valuesXageX_injectXnull_nullX: [function({g, xx1}) { return g.V(xx1).values(\"age\").inject(null,null) }], "
]
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 8507405..a993219 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -635,6 +635,9 @@ const gremlins = {
g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX: [function({g}) { return g.V().hasLabel("person").filter(__.outE("created")).valueMap().with_("~tinkerpop.valueMap.tokens") }],
g_VX1X_valueMapXname_locationX_byXunfoldX_by: [function({g, vid1}) { return g.V(vid1).valueMap("name","location").by(__.unfold()).by() }],
g_V_valueMapXname_age_nullX: [function({g}) { return g.V().valueMap("name","age",null) }],
+ g_VXnullX: [function({g}) { return g.V(null) }],
+ g_VXlistXnullXX: [function({g, xx1}) { return g.V(xx1) }],
+ g_VX1_nullX: [function({g, vid1}) { return g.V(vid1,null) }],
g_VXlistX1_2_3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }],
g_VXlistXv1_v2_v3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }],
g_V: [function({g}) { return g.V() }],
@@ -675,6 +678,8 @@ const gremlins = {
g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name: [function({g}) { return g.V().hasLabel("person").V().hasLabel("software").values("name") }],
g_V_hasLabelXloopsX_bothEXselfX: [function({g}) { return g.V().hasLabel("loops").bothE("self") }],
g_V_hasLabelXloopsX_bothXselfX: [function({g}) { return g.V().hasLabel("loops").both("self") }],
+ g_injectX1X_VXnullX: [function({g}) { return g.inject(1).V(null) }],
+ g_injectX1X_VX1_nullX: [function({g, vid1}) { return g.inject(1).V(vid1,null) }],
Primitives_Number_eqXintX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }],
g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return g.V().values("name").aggregate("x").cap("x") }],
g_V_valueXnameX_aggregateXglobal_xX_capXxX: [function({g}) { return g.V().values("name").aggregate(Scope.global,"x").cap("x") }],
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 5f9535a..e4b187f 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -620,6 +620,9 @@ world.gremlins = {
'g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX': [(lambda g:g.V().hasLabel('person').filter(__.outE('created')).valueMap().with_('~tinkerpop.valueMap.tokens'))],
'g_VX1X_valueMapXname_locationX_byXunfoldX_by': [(lambda g, vid1=None:g.V(vid1).valueMap('name','location').by(__.unfold()).by())],
'g_V_valueMapXname_age_nullX': [(lambda g:g.V().valueMap('name','age',None))],
+ 'g_VXnullX': [(lambda g:g.V(None))],
+ 'g_VXlistXnullXX': [(lambda g, xx1=None:g.V(xx1))],
+ 'g_VX1_nullX': [(lambda g, vid1=None:g.V(vid1,None))],
'g_VXlistX1_2_3XX_name': [(lambda g, xx1=None:g.V(xx1).name)],
'g_VXlistXv1_v2_v3XX_name': [(lambda g, xx1=None:g.V(xx1).name)],
'g_V': [(lambda g:g.V())],
@@ -660,6 +663,8 @@ world.gremlins = {
'g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name': [(lambda g:g.V().hasLabel('person').V().hasLabel('software').name)],
'g_V_hasLabelXloopsX_bothEXselfX': [(lambda g:g.V().hasLabel('loops').bothE('self'))],
'g_V_hasLabelXloopsX_bothXselfX': [(lambda g:g.V().hasLabel('loops').both('self'))],
+ 'g_injectX1X_VXnullX': [(lambda g:g.inject(1).V(None))],
+ 'g_injectX1X_VX1_nullX': [(lambda g, vid1=None:g.inject(1).V(vid1,None))],
'Primitives_Number_eqXintX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))],
'g_V_valueXnameX_aggregateXxX_capXxX': [(lambda g:g.V().name.aggregate('x').cap('x'))],
'g_V_valueXnameX_aggregateXglobal_xX_capXxX': [(lambda g:g.V().name.aggregate(Scope.global_,'x').cap('x'))],
diff --git a/gremlin-test/features/map/Vertex.feature b/gremlin-test/features/map/Vertex.feature
index 37738bb..3e78c82 100644
--- a/gremlin-test/features/map/Vertex.feature
+++ b/gremlin-test/features/map/Vertex.feature
@@ -18,6 +18,37 @@
@StepClassMap @StepVertex
Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
+ Scenario: g_VXnullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V(null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_VXlistXnullXX
+ Given the modern graph
+ And using the parameter xx1 defined as "l[null]"
+ And the traversal of
+ """
+ g.V(xx1)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_VX1_nullX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.V(vid1,null)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
+
Scenario: g_VXlistX1_2_3XX_name
Given the modern graph
And using the parameter xx1 defined as "l[v[marko].id,v[vadas].id,v[lop].id]"
@@ -579,3 +610,26 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
| result |
| v[loop] |
| v[loop] |
+
+ @GraphComputerVerificationInjectionNotSupported @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectX1X_VXnullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.inject(1).V(null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ @GraphComputerVerificationInjectionNotSupported @GraphComputerVerificationMidVNotSupported
+ Scenario: g_injectX1X_VX1_nullX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And the traversal of
+ """
+ g.inject(1).V(vid1,null)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | v[marko] |
\ No newline at end of file
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
index 0343302..b9dda16 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
@@ -316,6 +316,8 @@ public final class TinkerGraph implements Graph {
// the assumption is that if it's already an Element, its identifier must be valid to the Graph and to
// its associated IdManager. All other objects are passed to the IdManager for conversion.
return new TinkerGraphIterator<>(IteratorUtils.filter(IteratorUtils.map(idList, id -> {
+ // ids cant be null so all of those filter out
+ if (null == id) return null;
final Object iid = clazz.isAssignableFrom(id.getClass()) ? clazz.cast(id).id() : idManager.convert(id);
return elements.get(idManager.convert(iid));
}).iterator(), Objects::nonNull));