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/09/02 20:20:53 UTC
[tinkerpop] 01/03: TINKERPOP-2605 Better handle hasKey/Value(null)
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch TINKERPOP-2605
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 53b5eb82cc0bbf17607e1965102e57096b57f55a
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Sep 2 15:20:03 2021 -0400
TINKERPOP-2605 Better handle hasKey/Value(null)
---
CHANGELOG.asciidoc | 3 +-
docs/src/upgrade/release-3.5.x.asciidoc | 7 +-
.../traversal/dsl/graph/GraphTraversal.java | 57 +++++---
.../traversal/translator/DotNetTranslator.java | 5 +-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 9 ++
.../gremlin-javascript/test/cucumber/gremlin.js | 9 ++
gremlin-python/src/main/python/radish/gremlin.py | 9 ++
gremlin-test/features/filter/Has.feature | 97 +++++++++++++-
.../process/traversal/step/filter/HasTest.java | 143 ++++++++++++++++++++-
9 files changed, 316 insertions(+), 23 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 0155cfc..edaff36 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -29,13 +29,14 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Ensured `PathRetractionStrategy` is applied after `InlineFilterStrategy` which prevents an error in traverser mapping in certain conditions.
* Deprecated `JsonBuilder` serialization for GraphSON and Gryo.
* Allowed `null` string values in the Gremlin grammar.
-* Prevented exception with `hasLabel(null)` and instead filter away traversers as labels can't ever be null.
+* Prevented exception with `hasLabel(null)` and `hasKey(null)` and instead filter away traversers as these structural components can't ever be null.
* Improved handling of `null` when passed to `P` predicates.
* Handled `null` for mathematical reducing operations of `sum()`, `mean()`, `max()` and `min()`.
* Allowed `null` values in `Memory` for `GraphComputer`.
* Fixed problems with `inject(null)` variations where `null` was the only value being submitted.
* Fixed problem with `GroovyTranslator` and `inject(null,null)` which could be interpreted as the Groovy JDK extension `inject(Object,Closure).
* Fixed error where certain variants of `inject()` with `null` might not properly construct a traversal in .NET.
+* Prevented exception with `hasValue(null)` and allowed filtering as expected.
* Refined `DotNetTranslator` to be more explicit with `null` arguments to ensure that the right overloads are called.
* Created `GremlinParser` to construct `Traversal` objects from `gremlin-language`.
diff --git a/docs/src/upgrade/release-3.5.x.asciidoc b/docs/src/upgrade/release-3.5.x.asciidoc
index b22965b..ac21888 100644
--- a/docs/src/upgrade/release-3.5.x.asciidoc
+++ b/docs/src/upgrade/release-3.5.x.asciidoc
@@ -37,8 +37,11 @@ been noted that supplying a `null` value as an argument to certain Gremlin steps
were either not clear or perhaps even unexpected. The following changes were made to help make these behaviors more
consistent and to further solidify the semantics of `null` usage in the Gremlin language:
-* `hasLabel(null)` and `has(T.label,null)` - These methods used to throw general `NullPointerException` failures,
-but now filter results. As a `T.label` can't be `null`, it will effectively filter all elements.
+* `hasKey(null)`, `hasLabel(null)` and `has(T.label,null)` - These methods used to throw general `NullPointerException`
+failures, but now filter results. As these structural elements of the graph can't be `null`, it will effectively
+filter all elements.
+* `hasValue(null)` - Formerly this method would throw a general `NullPointerException`, but now it will filter as
+expected.
* `sum()`, `mean()`, `max()` and `min()` - These methods used to throw general `NullPointerException` failures, but
now ignore `null` values when other numbers are present. If all of the values in the stream are `null` then `hasNext()`
return `false`.
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 f52c30f..8b0caf8 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
@@ -1664,16 +1664,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* @since 3.2.2
*/
public default GraphTraversal<S, E> hasKey(final String label, final String... otherLabels) {
- final String[] labels = new String[otherLabels.length + 1];
+ this.asAdmin().getBytecode().addStep(Symbols.hasKey, label, otherLabels);
+
+ // groovy evaluation seems to do strange things with varargs given hasLabel(null, null). odd someone would
+ // do this but the failure is ugly if not handled.
+ final int otherLabelsLength = null == otherLabels ? 0 : otherLabels.length;
+ final String[] labels = new String[otherLabelsLength + 1];
labels[0] = label;
- System.arraycopy(otherLabels, 0, labels, 1, otherLabels.length);
- this.asAdmin().getBytecode().addStep(Symbols.hasKey, labels);
+ if (otherLabelsLength > 0)
+ System.arraycopy(otherLabels, 0, labels, 1, otherLabelsLength);
return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.key.getAccessor(), labels.length == 1 ? P.eq(labels[0]) : P.within(labels)));
}
/**
* Filters {@link Property} objects based on their key. It is not meant to test key existence on an {@link Edge} or
- * a {@link Vertex}. In that case, prefer {@link #has(String)}.
+ * a {@link Vertex}. In that case, prefer {@link #has(String)}. Note that calling this step with {@code null} is
+ * the same as calling {@link #hasKey(String, String...)} with a single {@code null}.
*
* @param predicate the filter to apply to the key of the {@link Property}
* @return the traversal with an appended {@link HasStep}
@@ -1681,8 +1687,13 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* @since 3.2.4
*/
public default GraphTraversal<S, E> hasKey(final P<String> predicate) {
- this.asAdmin().getBytecode().addStep(Symbols.hasKey, predicate);
- return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.key.getAccessor(), predicate));
+ // if calling hasKey(null), the likely use the caller is going for is not a "no predicate" but a eq(null)
+ if (null == predicate) {
+ return hasKey((String) null);
+ } else {
+ this.asAdmin().getBytecode().addStep(Symbols.hasKey, predicate);
+ return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.key.getAccessor(), predicate));
+ }
}
/**
@@ -1694,27 +1705,36 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
*/
public default GraphTraversal<S, E> hasValue(final Object value, final Object... otherValues) {
+ this.asAdmin().getBytecode().addStep(Symbols.hasValue, value, otherValues);
+
if (value instanceof P)
return this.hasValue((P) value);
else {
final List<Object> values = new ArrayList<>();
if (value instanceof Object[]) {
Collections.addAll(values, (Object[]) value);
- } else
+ } else {
values.add(value);
- for (final Object v : otherValues) {
- if (v instanceof Object[]) {
- Collections.addAll(values, (Object[]) v);
- } else
- values.add(v);
}
- this.asAdmin().getBytecode().addStep(Symbols.hasValue, values.toArray());
+
+ if (null == otherValues) {
+ values.add(null);
+ } else {
+ for (final Object v : otherValues) {
+ if (v instanceof Object[]) {
+ Collections.addAll(values, (Object[]) v);
+ } else
+ values.add(v);
+ }
+ }
+
return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.value.getAccessor(), values.size() == 1 ? P.eq(values.get(0)) : P.within(values)));
}
}
/**
- * Filters {@link Property} objects based on their value.
+ * Filters {@link Property} objects based on their value.Note that calling this step with {@code null} is the same
+ * as calling {@link #hasValue(Object, Object...)} with a single {@code null}.
*
* @param predicate the filter to apply to the value of the {@link Element}
* @return the traversal with an appended {@link HasStep}
@@ -1722,8 +1742,13 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
* @since 3.2.4
*/
public default GraphTraversal<S, E> hasValue(final P<Object> predicate) {
- this.asAdmin().getBytecode().addStep(Symbols.hasValue, predicate);
- return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.value.getAccessor(), predicate));
+ // if calling hasValue(null), the likely use the caller is going for is not a "no predicate" but a eq(null)
+ if (null == predicate) {
+ return hasKey((String) null);
+ } else {
+ this.asAdmin().getBytecode().addStep(Symbols.hasValue, predicate);
+ return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.value.getAccessor(), predicate));
+ }
}
/**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
index d6ac2eb..65d4259 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
@@ -351,8 +351,11 @@ public final class DotNetTranslator implements Translator.ScriptTranslator {
// them i guess
if (null == instArg) {
if ((methodName.equals(GraphTraversal.Symbols.addV) && idx % 2 == 0) ||
- methodName.equals(GraphTraversal.Symbols.hasLabel)) {
+ methodName.equals(GraphTraversal.Symbols.hasLabel)||
+ methodName.equals(GraphTraversal.Symbols.hasKey)) {
script.append("(string) ");
+ } else if (methodName.equals(GraphTraversal.Symbols.hasValue)) {
+ script.append("(object) ");
} else if (methodName.equals(GraphTraversal.Symbols.has)) {
if (instArgs[0] instanceof T && idx > 0) script.append("(object) ");
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index dac2353..eaa13a2 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -235,6 +235,15 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_E_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel((string) null)}},
{"g_E_hasXlabel_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Has(T.Label,(object) null)}},
{"g_V_properties_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasLabel((string) null)}},
+ {"g_V_properties_hasKeyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey((string) null)}},
+ {"g_V_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey((string) null,(string) null)}},
+ {"g_V_properties_hasKeyXnull_ageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey((string) null,"age").Value<object>()}},
+ {"g_E_properties_hasKeyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey((string) null)}},
+ {"g_E_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey((string) null,(string) null)}},
+ {"g_E_properties_hasKeyXnull_weightX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey((string) null,"weight").Value<object>()}},
+ {"g_V_properties_hasValueXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey((string) null)}},
+ {"g_V_properties_hasValueXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue((object) null,(object) null)}},
+ {"g_V_properties_hasValueXnull_joshX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasValue((object) null,"josh").Value<object>()}},
{"g_V_valuesXageX_isX32X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(32)}},
{"g_V_valuesXageX_isXlte_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Lte(30))}},
{"g_V_valuesXageX_isXgte_29X_isXlt_34X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Is(P.Gte(29)).Is(P.Lt(34))}},
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 feb52ff..75c72c8 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
@@ -224,6 +224,15 @@ const gremlins = {
g_E_hasLabelXnullX: [function({g}) { return g.E().hasLabel(null) }],
g_E_hasXlabel_nullX: [function({g}) { return g.E().has(T.label,null) }],
g_V_properties_hasLabelXnullX: [function({g}) { return g.V().properties().hasLabel(null) }],
+ g_V_properties_hasKeyXnullX: [function({g}) { return g.V().properties().hasKey(null) }],
+ g_V_properties_hasKeyXnull_nullX: [function({g}) { return g.V().properties().hasKey(null,null) }],
+ g_V_properties_hasKeyXnull_ageX_value: [function({g}) { return g.V().properties().hasKey(null,"age").value() }],
+ g_E_properties_hasKeyXnullX: [function({g}) { return g.E().properties().hasKey(null) }],
+ g_E_properties_hasKeyXnull_nullX: [function({g}) { return g.E().properties().hasKey(null,null) }],
+ g_E_properties_hasKeyXnull_weightX_value: [function({g}) { return g.E().properties().hasKey(null,"weight").value() }],
+ g_V_properties_hasValueXnullX: [function({g}) { return g.V().properties().hasKey(null) }],
+ g_V_properties_hasValueXnull_nullX: [function({g}) { return g.V().properties().hasValue(null,null) }],
+ g_V_properties_hasValueXnull_joshX_value: [function({g}) { return g.V().properties().hasValue(null,"josh").value() }],
g_V_valuesXageX_isX32X: [function({g}) { return g.V().values("age").is(32) }],
g_V_valuesXageX_isXlte_30X: [function({g}) { return g.V().values("age").is(P.lte(30)) }],
g_V_valuesXageX_isXgte_29X_isXlt_34X: [function({g}) { return g.V().values("age").is(P.gte(29)).is(P.lt(34)) }],
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index defbf6b..2643a30 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -209,6 +209,15 @@ world.gremlins = {
'g_E_hasLabelXnullX': [(lambda g:g.E().hasLabel(None))],
'g_E_hasXlabel_nullX': [(lambda g:g.E().has(T.label,None))],
'g_V_properties_hasLabelXnullX': [(lambda g:g.V().properties().hasLabel(None))],
+ 'g_V_properties_hasKeyXnullX': [(lambda g:g.V().properties().hasKey(None))],
+ 'g_V_properties_hasKeyXnull_nullX': [(lambda g:g.V().properties().hasKey(None,None))],
+ 'g_V_properties_hasKeyXnull_ageX_value': [(lambda g:g.V().properties().hasKey(None,'age').value())],
+ 'g_E_properties_hasKeyXnullX': [(lambda g:g.E().properties().hasKey(None))],
+ 'g_E_properties_hasKeyXnull_nullX': [(lambda g:g.E().properties().hasKey(None,None))],
+ 'g_E_properties_hasKeyXnull_weightX_value': [(lambda g:g.E().properties().hasKey(None,'weight').value())],
+ 'g_V_properties_hasValueXnullX': [(lambda g:g.V().properties().hasKey(None))],
+ 'g_V_properties_hasValueXnull_nullX': [(lambda g:g.V().properties().hasValue(None,None))],
+ 'g_V_properties_hasValueXnull_joshX_value': [(lambda g:g.V().properties().hasValue(None,'josh').value())],
'g_V_valuesXageX_isX32X': [(lambda g:g.V().age.is_(32))],
'g_V_valuesXageX_isXlte_30X': [(lambda g:g.V().age.is_(P.lte(30)))],
'g_V_valuesXageX_isXgte_29X_isXlt_34X': [(lambda g:g.V().age.is_(P.gte(29)).is_(P.lt(34)))],
diff --git a/gremlin-test/features/filter/Has.feature b/gremlin-test/features/filter/Has.feature
index db78114..753f0dd 100644
--- a/gremlin-test/features/filter/Has.feature
+++ b/gremlin-test/features/filter/Has.feature
@@ -828,4 +828,99 @@ Feature: Step - has()
g.V().properties().hasLabel(null)
"""
When iterated to list
- Then the result should be empty
\ No newline at end of file
+ Then the result should be empty
+
+ Scenario: g_V_properties_hasKeyXnullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().properties().hasKey(null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_V_properties_hasKeyXnull_nullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().properties().hasKey(null,null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_V_properties_hasKeyXnull_ageX_value
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().properties().hasKey(null, "age").value()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[29].i |
+ | d[27].i |
+ | d[32].i |
+ | d[35].i |
+
+ Scenario: g_E_properties_hasKeyXnullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.E().properties().hasKey(null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_E_properties_hasKeyXnull_nullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.E().properties().hasKey(null,null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_E_properties_hasKeyXnull_weightX_value
+ Given the modern graph
+ And the traversal of
+ """
+ g.E().properties().hasKey(null, "weight").value()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | d[0.5].d |
+ | d[1.0].d |
+ | d[1.0].d |
+ | d[0.4].d |
+ | d[0.4].d |
+ | d[0.2].d |
+
+ Scenario: g_V_properties_hasValueXnullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().properties().hasValue(null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_V_properties_hasValueXnull_nullX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().properties().hasValue(null,null)
+ """
+ When iterated to list
+ Then the result should be empty
+
+ Scenario: g_V_properties_hasValueXnull_joshX_value
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().properties().hasValue(null, "josh").value()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | josh |
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java
index 77d3338..faa8f59 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java
@@ -98,7 +98,7 @@ public abstract class HasTest extends AbstractGremlinProcessTest {
public abstract Traversal<Edge, Edge> get_g_E_hasLabelXnullX();
- public abstract Traversal<Vertex, ? extends Property> get_g_V_properties_hasLabelXnullX();
+ public abstract Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasLabelXnullX();
public abstract Traversal<Edge, Edge> get_g_EX11X_outV_outE_hasXid_10X(final Object e11Id, final Object e8Id);
@@ -166,6 +166,24 @@ public abstract class HasTest extends AbstractGremlinProcessTest {
public abstract Traversal<Vertex, String> get_g_V_hasXk_withinXcXX_valuesXkX();
+ public abstract Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasKeyXnullX();
+
+ public abstract Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasKeyXnull_nullX();
+
+ public abstract Traversal<Vertex, Integer> get_g_V_properties_hasKeyXnull_ageX_value();
+
+ public abstract Traversal<Edge, ? extends Property<Object>> get_g_E_properties_hasKeyXnullX();
+
+ public abstract Traversal<Edge, ? extends Property<Object>> get_g_E_properties_hasKeyXnull_nullX();
+
+ public abstract Traversal<Edge, Double> get_g_E_properties_hasKeyXnull_weightX_value();
+
+ public abstract Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasValueXnullX();
+
+ public abstract Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasValueXnull_nullX();
+
+ public abstract Traversal<Vertex, String> get_g_V_properties_hasValueXnull_joshX_value();
+
@Test
@LoadGraphWith(MODERN)
public void g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name() {
@@ -780,6 +798,82 @@ public abstract class HasTest extends AbstractGremlinProcessTest {
assertFalse(traversal.hasNext());
}
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_properties_hasKeyXnullX() {
+ final Traversal<Vertex, ? extends Property<Object>> traversal = get_g_V_properties_hasKeyXnullX();
+ printTraversalForm(traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_properties_hasKeyXnull_nullX() {
+ final Traversal<Vertex, ? extends Property<Object>> traversal = get_g_V_properties_hasKeyXnull_nullX();
+ printTraversalForm(traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_properties_hasKeyXnull_ageX_value() {
+ final Traversal<Vertex, Integer> traversal = get_g_V_properties_hasKeyXnull_ageX_value();
+ printTraversalForm(traversal);
+ checkResults(Arrays.asList(27, 29, 32, 35), traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_E_properties_hasKeyXnullX() {
+ final Traversal<Edge, ? extends Property<Object>> traversal = get_g_E_properties_hasKeyXnullX();
+ printTraversalForm(traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_E_properties_hasKeyXnull_nullX() {
+ final Traversal<Edge, ? extends Property<Object>> traversal = get_g_E_properties_hasKeyXnull_nullX();
+ printTraversalForm(traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_E_properties_hasKeyXnull_weightX_value() {
+ final Traversal<Edge, Double> traversal = get_g_E_properties_hasKeyXnull_weightX_value();
+ printTraversalForm(traversal);
+ checkResults(Arrays.asList(0.5, 1.0, 1.0, 0.4, 0.4, 0.2), traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_properties_hasValueXnullX() {
+ final Traversal<Vertex, ? extends Property<Object>> traversal = get_g_V_properties_hasValueXnullX();
+ printTraversalForm(traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_properties_hasValueXnull_nullX() {
+ final Traversal<Vertex, ? extends Property<Object>> traversal = get_g_V_properties_hasValueXnull_nullX();
+ printTraversalForm(traversal);
+ assertThat(traversal.hasNext(), is(false));
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_properties_hasValueXnull_joshX_value() {
+ final Traversal<Vertex, String> traversal = get_g_V_properties_hasValueXnull_joshX_value();
+ printTraversalForm(traversal);
+ assertEquals("josh", traversal.next());
+ assertThat(traversal.hasNext(), is(false));
+ }
+
public static class Traversals extends HasTest {
@Override
public Traversal<Edge, Edge> get_g_EX11X_outV_outE_hasXid_10X(final Object e11Id, final Object e10Id) {
@@ -837,7 +931,7 @@ public abstract class HasTest extends AbstractGremlinProcessTest {
}
@Override
- public Traversal<Vertex, ? extends Property> get_g_V_properties_hasLabelXnullX() {
+ public Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasLabelXnullX() {
return g.V().properties().hasLabel(null);
}
@@ -1055,5 +1149,50 @@ public abstract class HasTest extends AbstractGremlinProcessTest {
public Traversal<Vertex, String> get_g_V_hasXk_withinXcXX_valuesXkX() {
return g.V().has("k", P.within("轉注", "✦", "♠")).values("k");
}
+
+ @Override
+ public Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasKeyXnullX() {
+ return g.V().properties().hasKey(null);
+ }
+
+ @Override
+ public Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasKeyXnull_nullX() {
+ return g.V().properties().hasKey(null,null);
+ }
+
+ @Override
+ public Traversal<Vertex, Integer> get_g_V_properties_hasKeyXnull_ageX_value() {
+ return g.V().properties().hasKey(null, "age").value();
+ }
+
+ @Override
+ public Traversal<Edge, ? extends Property<Object>> get_g_E_properties_hasKeyXnullX() {
+ return g.E().properties().hasKey(null);
+ }
+
+ @Override
+ public Traversal<Edge, ? extends Property<Object>> get_g_E_properties_hasKeyXnull_nullX() {
+ return g.E().properties().hasKey(null,null);
+ }
+
+ @Override
+ public Traversal<Edge, Double> get_g_E_properties_hasKeyXnull_weightX_value() {
+ return g.E().properties().hasKey(null, "weight").value();
+ }
+
+ @Override
+ public Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasValueXnullX() {
+ return g.V().properties().hasValue(null);
+ }
+
+ @Override
+ public Traversal<Vertex, ? extends Property<Object>> get_g_V_properties_hasValueXnull_nullX() {
+ return g.V().properties().hasValue(null,null);
+ }
+
+ @Override
+ public Traversal<Vertex, String> get_g_V_properties_hasValueXnull_joshX_value() {
+ return g.V().properties().hasValue(null, "josh").value();
+ }
}
}
\ No newline at end of file