diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 4971f792173..159df10fd32 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -34,6 +34,15 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Added explicit transaction support to all non-Java GLVs (gremlin-python, gremlin-go, gremlin-javascript, gremlin-dotnet). * Changed default transaction close behavior from commit to rollback across all GLVs to align with embedded graph defaults. * Refactored Go driver connection to block until response headers arrive, enabling synchronous error returns and proper transaction ordering. +* Added child traversal support to `has()`, `hasLabel()`, `V()`, `E()`, `property()`, `is()`, `where(P)`, `P.eq/neq/gt/lt/gte/lte/within/without()`, and `TextP` predicates. Child traversals are resolved per-traverser at runtime, enabling dynamic filtering and lookup patterns. +* Added multi-traversal `P.within(trav1, trav2, ...)` and `P.without(trav1, trav2, ...)` which combine results from multiple child traversals for collection membership testing. +* Added `V(traversal)` and `E(traversal)` as start steps with synthetic traverser seeding, consistent with `mergeV(traversal)` behavior. +* Added `ChildTraversalVerificationStrategy` that blocks mutating steps (`addV`, `addE`, `drop`, etc.) inside child traversals. All child traversals must be read-only. +* Added `hasLabel(Traversal)` overload with grammar support for dynamic label filtering. +* Added traversal-bearing predicate support to `where(P)` - resolves child traversal and tests against current value when `P.hasTraversal()` is true. +* Added rejection of traversal-bearing predicates in `choose(P)` and `choose().option(P, ...)` - the predicate's child traversal cannot be resolved in the branch-selection context. +* Added runtime Map validation for `property(traversal)` - rejects results that are not a `Map` of property key/value pairs. +* Added mixed traversal/literal detection in `P.within()` and `P.without()` - throws `IllegalArgumentException` with guidance to wrap literals in `__.constant()`. * Removed `uuid` dependency from `gremlin-javascript` in favor of the built-in `globalThis.crypto.randomUUID()`. * Added streaming HTTP response support to `gremlin-driver` for incremental result deserialization over GraphBinary. * Connected HTTP streaming response deserialization to the traversal API in `gremlin-javascript`, enabling `next()` to return the first result without waiting for the full response. diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc index bc05a52b44d..1fa4abebe15 100644 --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@ -1253,6 +1253,9 @@ IMPORTANT: It is important to think of `choose()` as a branching step and not a intuitively lead to thinking the latter, where no match would mean to remove the traverser from the stream. As shown in the examples, this is not what happens. +NOTE: The `choose(P)` form and `choose().option(P, ...)` currently do not support traversal-bearing predicates. +Dynamic branching is restricted in 4.0.0. + The `choose()`-step can be used within a `map()` step to apply the branching logic to each element in a collection. [gremlin-groovy,modern] @@ -2074,6 +2077,10 @@ It is possible to filter vertices, edges, and vertex properties based on their p * `has(key,value)`: Remove the traverser if its element does not have the provided key/value property. * `has(label, key, value)`: Remove the traverser if its element does not have the specified label and provided key/value property. * `has(key,predicate)`: Remove the traverser if its element does not have a key value that satisfies the bi-predicate. For more information on predicates, please read <>. + * `has(key, traversal)`: Remove the traverser if its element's key value does not equal the first result of the provided traversal. + * `has(T, traversal)`: Remove the traverser if its element's `T`-based value (e.g. `T.id`, `T.label`) does not equal the first result of the provided traversal. + * `has(label, key, traversal)`: Remove the traverser if its element does not have the specified label and its key value does not equal the first result of the provided traversal. + * `hasLabel(traversal)`: Remove the traverser if its element's label does not equal the first result of the provided traversal. * `hasLabel(labels...)`: Remove the traverser if its element does not have any of the labels. * `hasId(ids...)`: Remove the traverser if its element does not have any of the ids. * `hasKey(keys...)`: Remove the `Property` traverser if it does not match one of the provided keys. @@ -2112,6 +2119,24 @@ the key,value pairs for those vertices. <9> Property key is always stored as `String` and therefore an equality check with `null` will produce no result. <10> An example of using `has()` with regular expression predicate. +The traversal-accepting forms of `has()` allow for dynamic property comparisons. Rather than providing a literal value, +a child traversal is supplied and its first result is used as the comparison value. This follows the same first-result +semantics as `by(traversal)`. The child traversal must be read-only - mutating steps are rejected. + +[gremlin-groovy,modern] +---- +g.V().has('age', P.gt(__.V(1).values('age'))) <1> +g.V().has('name', __.V(1).values('name')) <2> +g.V().hasLabel(__.V(1).label()) <3> +---- + +<1> Find all vertices whose age is greater than marko's age using a traversal inside a predicate. +<2> Find all vertices whose name equals marko's name using a traversal as the value argument. +<3> Find all vertices whose label equals the label of vertex 1. + +NOTE: When a `Traversal` is provided directly as the value argument (not inside a `P`), it is internally wrapped in +`P.eq(traversal)`. See <> for more details on traversal-bearing predicates. + *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#has(java.lang.String)++[`has(String)`], @@ -2467,6 +2492,18 @@ g.V().where(__.in('created').values('age'). <2> Find projects having two or more contributors. <3> Find projects whose contributors average age is between 30 and 35. +The `is()` step also supports predicates that contain traversal arguments for dynamic threshold comparison. + +[gremlin-groovy,modern] +---- +g.V().values('age').is(P.gt(__.V(1).values('age'))) <1> +---- + +<1> Find all age values that are greater than marko's age using a traversal inside the predicate. + +NOTE: When `is(traversal)` is used directly (without an explicit predicate), it is internally wrapped in +`P.eq(traversal)`. + *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#is(java.lang.Object)++[`is(Object)`], @@ -3989,6 +4026,21 @@ g.addV().property(set, null) <7> The label value can be specified as a property only at the time a vertex is added and if one is not specified in the addV() <8> If you pass a `null` value for the Map this will be treated as a no-op and the input will be returned +The `property()` step also accepts a traversal that produces a `Map` of key-value pairs to set as properties. The +child traversal must be read-only - mutating steps are rejected. If the traversal does not produce a `Map`, the result +is rejected. Each entry in the resulting Map becomes a separate property on the element, allowing multiple properties +to be set in a single step. + +[gremlin-groovy,modern] +---- +g.V(4).property(__.V(1).project('friendCount','createdSoftware').by(__.out('knows').count()).by(__.out('created').values('name'))) <1> +g.V(4).valueMap('friendCount','createdSoftware') +---- + +<1> Set two properties on vertex 4 (josh) from a Map produced by a child traversal. The `project()` step builds a Map +with keys "friendCount" and "createdSoftware", whose values are computed from vertex 1's (marko's) relationships - +number of friends and name of software created. Both properties are applied to vertex 4 in one operation. + *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#property(java.lang.Object,java.lang.Object,java.lang.Object...)++[`property(Object, Object, Object...)`], @@ -5187,6 +5239,19 @@ g.V().has('name', within('marko', 'vadas', 'josh')).as('person'). <1> Normally the `V()`-step will iterate over all vertices. However, graph strategies can fold ``HasContainer``'s into a `GraphStep` to allow index lookups. <2> Whether the graph system provider supports mid-traversal `V()` index lookups or not can easily be determined by inspecting the `toString()` output of the iterated traversal. If `has` conditions were folded into the `V()`-step, an index - if one exists - will be used. +The `V()` step also accepts a traversal argument. The child traversal is evaluated and its results are used as the +vertex identifiers. This works both as a start step and mid-traversal. When used as a start step, a synthetic traverser +is provided to the child traversal. + +[gremlin-groovy,modern] +---- +g.V(__.V(1).id()).values('name') <1> +g.inject(1).V(__.identity()).values('name') <2> +---- + +<1> Use a child traversal to dynamically determine the vertex ID. Here the traversal resolves vertex 1's ID. +<2> Mid-traversal usage where the injected value is used via `identity()` as the ID argument to `V()`. + *Additional References* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#V(java.lang.Object...)++[`V(Object...)`] @@ -5399,6 +5464,18 @@ g.V().as('a').both().both().as('b'). <8> Marko is younger than josh, but josh knows someone equal in age to marko (which is marko). <9> The "age" property is not <> for all vertices and therefore those values are filtered. +The `where()` step also supports predicates that contain traversal arguments. When a predicate contains a child +traversal, the traversal is resolved per-traverser and the result is tested directly against the current value - +bypassing scope-label resolution. + +[gremlin-groovy,modern] +---- +g.V().values('age').where(P.gt(__.V(1).values('age'))) <1> +---- + +<1> Find all age values that are greater than marko's age. The child traversal inside `P.gt()` is resolved and the +current traverser's value is compared against the result. + WARNING: The anonymous traversal of `where()` processes the current object "locally". In OLAP, where the atomic unit of computing is the vertex and its local "star graph," it is important that the anonymous traversal does not leave the confines of the vertex's star graph. In other words, it can not traverse to an adjacent vertex's properties or @@ -5524,6 +5601,24 @@ NOTE: The TinkerPop reference implementation uses the Java `Pattern` and `Matche engine. Other implementations may decide to use a different regular expression engine. It's a good idea to check the documentation for the implementation you are using to verify the allowed regular expression syntax. +In addition to literal values, most predicates also accept a `Traversal` argument. When a traversal is provided, it is +evaluated and only its first result is used for comparison - consistent with `by(traversal)` first-result semantics. +The child traversal must be read-only; mutating steps are rejected. + +* For `within()` and `without()`, the first result should be a `Collection`. Use `fold()` in the child traversal to + produce one. +* The multi-traversal form `within(trav1, trav2, ...)` takes the first result from each traversal and combines them + into a collection for membership testing. + +[gremlin-groovy,modern] +---- +g.V().has('age', P.gt(__.V(1).values('age'))) <1> +g.V().has('age', P.within(__.V(1).out('knows').values('age').fold())) <2> +---- + +<1> Find vertices whose age is greater than marko's age using a traversal inside the predicate. +<2> Find vertices whose age is in the set of ages of marko's friends, using `fold()` to produce a collection. + [gremlin-groovy] ---- eq(2) diff --git a/docs/src/upgrade/release-4.x.x.asciidoc b/docs/src/upgrade/release-4.x.x.asciidoc index ac8debb0a99..ed92ed73a18 100644 --- a/docs/src/upgrade/release-4.x.x.asciidoc +++ b/docs/src/upgrade/release-4.x.x.asciidoc @@ -69,6 +69,32 @@ GLVs (including the Java driver). This aligns with the embedded graph transactio partial work is discarded if the user forgets to call `commit()`. In Java (both remote and embedded mode), the behavior can still be overridden via `tx.onClose(Transaction.CLOSE_BEHAVIOR.COMMIT)`. The non-Java GLVs do not support configuring close behavior and always rollback. +==== Traversal-Accepting Steps + +Steps and predicates that previously only accepted literal values now accept child traversals resolved per-traverser +at runtime. This enables dynamic filtering, lookup, and mutation patterns without `where()`/`select()` workarounds. + +Affected steps: `has()`, `hasLabel()`, `V()`, `E()`, `property()`, `is()`, `where(P)`, `P.eq/neq/gt/lt/gte/lte()`, +`P.within/without()`, and all `TextP` predicates. + +[source,groovy] +---- +// Dynamic property comparison +g.V().has("age", P.gt(__.V(1).values("age"))) + +// Dynamic vertex lookup: resolve the ids of marko's friends, then look them up by id +g.V(1).V(__.out("knows").id()).values("name") + +// Multi-source filtering with within() +g.V().has("name", P.within(__.V(1).out("knows").values("name").fold(), __.constant("peter"))) +---- + +Child traversals take only the first result (consistent with `by(traversal)` semantics). For `within()`/`without()`, +use `fold()` to collect multiple values into a list. + +All child traversals must be read-only. Mutating steps (`addV`, `addE`, `drop`, `property`) inside child traversals +are rejected at construction time with `IllegalArgumentException`. A `ChildTraversalVerificationStrategy` provides +additional safety at strategy time. ==== Removed `uuid` Dependency in gremlin-javascript @@ -565,6 +591,21 @@ benefiting all driver users transparently. See <> for full details on annotation usage, field filtering, nested types, and ServiceLoader registration. +===== Traversal-Accepting Steps - HasContainer Guard + +Steps and predicates now accept child traversals resolved at runtime. `HasContainer` instances that hold a child +traversal cannot be folded into index lookups because their value is dynamic (resolved per-traverser). Providers that +fold `HasContainer` predicates into their graph step must guard against this: + +[source,java] +---- +if (hasContainer.hasTraversal()) continue; // skip - dynamic value, cannot fold into index +---- + +`GraphStep.processHasContainerIds()` already includes this guard. Providers that implement their own `HasContainer` +folding strategy should add the same check. Without it, the container's value is read before it has been resolved +against a traverser, so an unresolved value would be folded into the index lookup and produce incorrect results. + ==== Graph Driver Providers == TinkerPop 4.0.0-beta.2 diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java index 760da5be7a9..be87c343bfb 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java @@ -455,6 +455,18 @@ protected void notImplemented(final ParseTree ctx) { * {@inheritDoc} */ @Override public T visitTraversalMethod_has_T_P(final GremlinParser.TraversalMethod_has_T_PContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_has_String_Traversal(final GremlinParser.TraversalMethod_has_String_TraversalContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_has_T_Traversal(final GremlinParser.TraversalMethod_has_T_TraversalContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_has_String_String_Traversal(final GremlinParser.TraversalMethod_has_String_String_TraversalContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ @@ -475,6 +487,10 @@ protected void notImplemented(final ParseTree ctx) { * {@inheritDoc} */ @Override public T visitTraversalMethod_hasLabel_P(final GremlinParser.TraversalMethod_hasLabel_PContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_hasLabel_Traversal(final GremlinParser.TraversalMethod_hasLabel_TraversalContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ @@ -703,6 +719,18 @@ protected void notImplemented(final ParseTree ctx) { * {@inheritDoc} */ @Override public T visitTraversalMethod_property_Object(final GremlinParser.TraversalMethod_property_ObjectContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_property_Cardinality_Object_Traversal(final GremlinParser.TraversalMethod_property_Cardinality_Object_TraversalContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_property_Object_Traversal(final GremlinParser.TraversalMethod_property_Object_TraversalContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_property_Traversal(final GremlinParser.TraversalMethod_property_TraversalContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java index 537bdcbe522..518196daef7 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java @@ -22,15 +22,23 @@ import org.apache.tinkerpop.gremlin.process.traversal.Merge; import org.apache.tinkerpop.gremlin.process.traversal.Operator; import org.apache.tinkerpop.gremlin.process.traversal.Order; +import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; import org.apache.tinkerpop.gremlin.process.traversal.Scope; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStepPlaceholder; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; import org.apache.tinkerpop.gremlin.structure.Column; import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.T; +import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality; import java.util.Arrays; @@ -65,7 +73,14 @@ public Traversal visitTraversalMethod(final GremlinParser.TraversalMethodContext */ @Override public GraphTraversal visitTraversalMethod_V(final GremlinParser.TraversalMethod_VContext ctx) { - return this.graphTraversal.V(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs())); + if (ctx.nestedTraversal() != null) { + return this.graphTraversal.V((Traversal) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()); + if (args.length == 1 && args[0] instanceof Traversal) { + return this.graphTraversal.V((Traversal) args[0]); + } + return this.graphTraversal.V(args); } /** @@ -73,7 +88,14 @@ public GraphTraversal visitTraversalMethod_V(final GremlinParser.TraversalMethod */ @Override public GraphTraversal visitTraversalMethod_E(final GremlinParser.TraversalMethod_EContext ctx) { - return this.graphTraversal.E(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs())); + if (ctx.nestedTraversal() != null) { + return this.graphTraversal.E((Traversal) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()); + if (args.length == 1 && args[0] instanceof Traversal) { + return this.graphTraversal.E((Traversal) args[0]); + } + return this.graphTraversal.E(args); } /** @@ -749,6 +771,15 @@ public GraphTraversal visitTraversalMethod_hasLabel_P(final GremlinParser.Traver return graphTraversal.hasLabel(antlr.traversalPredicateVisitor.visitTraversalPredicate(ctx.traversalPredicate())); } + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_hasLabel_Traversal(final GremlinParser.TraversalMethod_hasLabel_TraversalContext ctx) { + final Traversal.Admin traversal = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()); + return graphTraversal.hasLabel((Traversal) traversal); + } + /** * {@inheritDoc} */ @@ -820,8 +851,12 @@ public GraphTraversal visitTraversalMethod_has_String(final GremlinParser.Traver */ @Override public GraphTraversal visitTraversalMethod_has_String_Object(final GremlinParser.TraversalMethod_has_String_ObjectContext ctx) { - return graphTraversal.has(antlr.genericVisitor.parseString(ctx.stringNullableLiteral()), - antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument())); + final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral()); + final Object value = antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()); + if (value instanceof Traversal) { + return graphTraversal.has(key, (Traversal) value); + } + return graphTraversal.has(key, value); } /** @@ -839,14 +874,19 @@ public GraphTraversal visitTraversalMethod_has_String_P(final GremlinParser.Trav @Override public GraphTraversal visitTraversalMethod_has_String_String_Object(final GremlinParser.TraversalMethod_has_String_String_ObjectContext ctx) { final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument()); + final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral()); + final Object value = antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()); + if (value instanceof Traversal) { + if (GValue.valueInstanceOf(literalOrVar, String.class)) { + return graphTraversal.has(((GValue) literalOrVar).get(), key, (Traversal) value); + } else { + return graphTraversal.has((String) literalOrVar, key, (Traversal) value); + } + } if (GValue.valueInstanceOf(literalOrVar, String.class)) { - return graphTraversal.has((GValue) literalOrVar, - antlr.genericVisitor.parseString(ctx.stringNullableLiteral()), - antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument())); + return graphTraversal.has((GValue) literalOrVar, key, value); } else { - return graphTraversal.has((String) literalOrVar, - antlr.genericVisitor.parseString(ctx.stringNullableLiteral()), - antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument())); + return graphTraversal.has((String) literalOrVar, key, value); } } @@ -872,8 +912,12 @@ public GraphTraversal visitTraversalMethod_has_String_String_P(final GremlinPars */ @Override public GraphTraversal visitTraversalMethod_has_T_Object(final GremlinParser.TraversalMethod_has_T_ObjectContext ctx) { - return graphTraversal.has(TraversalEnumParser.parseTraversalEnumFromContext(T.class, ctx.traversalT()), - antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument())); + final T accessor = TraversalEnumParser.parseTraversalEnumFromContext(T.class, ctx.traversalT()); + final Object value = antlr.argumentVisitor.visitGenericArgument(ctx.genericArgument()); + if (value instanceof Traversal) { + return graphTraversal.has(accessor, (Traversal) value); + } + return graphTraversal.has(accessor, value); } /** @@ -885,6 +929,41 @@ public GraphTraversal visitTraversalMethod_has_T_P(final GremlinParser.Traversal antlr.traversalPredicateVisitor.visitTraversalPredicate(ctx.traversalPredicate())); } + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_has_String_Traversal(final GremlinParser.TraversalMethod_has_String_TraversalContext ctx) { + final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral()); + final Traversal.Admin traversal = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()); + return this.graphTraversal.has(key, (Traversal) traversal); + } + + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_has_String_String_Traversal(final GremlinParser.TraversalMethod_has_String_String_TraversalContext ctx) { + final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument()); + final String key = antlr.genericVisitor.parseString(ctx.stringNullableLiteral()); + final Traversal.Admin traversal = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()); + if (GValue.valueInstanceOf(literalOrVar, String.class)) { + return this.graphTraversal.has(((GValue) literalOrVar).get(), key, (Traversal) traversal); + } else { + return this.graphTraversal.has((String) literalOrVar, key, (Traversal) traversal); + } + } + + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_has_T_Traversal(final GremlinParser.TraversalMethod_has_T_TraversalContext ctx) { + final T accessor = TraversalEnumParser.parseTraversalEnumFromContext(T.class, ctx.traversalT()); + final Traversal.Admin traversal = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()); + return this.graphTraversal.has(accessor, (Traversal) traversal); + } + /** * {@inheritDoc} */ @@ -1432,6 +1511,36 @@ public Traversal visitTraversalMethod_property_Object(final GremlinParser.Traver return graphTraversal.property(antlr.argumentVisitor.parseMap(ctx.genericMapNullableArgument())); } + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_property_Cardinality_Object_Traversal(final GremlinParser.TraversalMethod_property_Cardinality_Object_TraversalContext ctx) { + return graphTraversal.property( + TraversalEnumParser.parseTraversalEnumFromContext(Cardinality.class, ctx.traversalCardinality()), + antlr.genericVisitor.visitGenericLiteral(ctx.genericLiteral()), + antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_property_Object_Traversal(final GremlinParser.TraversalMethod_property_Object_TraversalContext ctx) { + return graphTraversal.property( + antlr.genericVisitor.visitGenericLiteral(ctx.genericLiteral()), + antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_property_Traversal(final GremlinParser.TraversalMethod_property_TraversalContext ctx) { + final Traversal traversal = (Traversal) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()); + return this.graphTraversal.property(traversal); + } + /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java index 19a5ab4f29c..c504c2e76d9 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalPredicateVisitor.java @@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.GType; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.TextP; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import java.util.Collection; @@ -67,6 +68,9 @@ public P visitTraversalPredicate(final GremlinParser.TraversalPredicateContext c */ @Override public P visitTraversalPredicate_eq(final GremlinParser.TraversalPredicate_eqContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.eq((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return P.eq(getSingleGenericLiteralArgument(ctx)); } @@ -75,6 +79,9 @@ public P visitTraversalPredicate_eq(final GremlinParser.TraversalPredicate_eqCon */ @Override public P visitTraversalPredicate_neq(final GremlinParser.TraversalPredicate_neqContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.neq((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return P.neq(getSingleGenericLiteralArgument(ctx)); } @@ -97,6 +104,9 @@ public P visitTraversalPredicate_typeOf(final GremlinParser.TraversalPredicate_t */ @Override public P visitTraversalPredicate_lt(final GremlinParser.TraversalPredicate_ltContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.lt((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return P.lt(getSingleGenericLiteralArgument(ctx)); } @@ -105,6 +115,9 @@ public P visitTraversalPredicate_lt(final GremlinParser.TraversalPredicate_ltCon */ @Override public P visitTraversalPredicate_lte(final GremlinParser.TraversalPredicate_lteContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.lte((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return P.lte(getSingleGenericLiteralArgument(ctx)); } @@ -113,6 +126,9 @@ public P visitTraversalPredicate_lte(final GremlinParser.TraversalPredicate_lteC */ @Override public P visitTraversalPredicate_gt(final GremlinParser.TraversalPredicate_gtContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.gt((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return P.gt(getSingleGenericLiteralArgument(ctx)); } @@ -121,6 +137,9 @@ public P visitTraversalPredicate_gt(final GremlinParser.TraversalPredicate_gtCon */ @Override public P visitTraversalPredicate_gte(final GremlinParser.TraversalPredicate_gteContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.gte((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return P.gte(getSingleGenericLiteralArgument(ctx)); } @@ -129,6 +148,11 @@ public P visitTraversalPredicate_gte(final GremlinParser.TraversalPredicate_gteC */ @Override public P visitTraversalPredicate_inside(final GremlinParser.TraversalPredicate_insideContext ctx) { + if (!ctx.nestedTraversal().isEmpty()) { + final Traversal.Admin first = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(0)); + final Traversal.Admin second = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(1)); + return P.gt(first).and(P.lt(second)); + } final Object[] arguments = getDoubleGenericLiteralArgument(ctx); return P.inside(arguments[0], arguments[1]); } @@ -138,6 +162,11 @@ public P visitTraversalPredicate_inside(final GremlinParser.TraversalPredicate_i */ @Override public P visitTraversalPredicate_outside(final GremlinParser.TraversalPredicate_outsideContext ctx) { + if (!ctx.nestedTraversal().isEmpty()) { + final Traversal.Admin first = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(0)); + final Traversal.Admin second = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(1)); + return P.lt(first).or(P.gt(second)); + } final Object[] arguments = getDoubleGenericLiteralArgument(ctx); return P.outside(arguments[0], arguments[1]); } @@ -147,6 +176,11 @@ public P visitTraversalPredicate_outside(final GremlinParser.TraversalPredicate_ */ @Override public P visitTraversalPredicate_between(final GremlinParser.TraversalPredicate_betweenContext ctx) { + if (!ctx.nestedTraversal().isEmpty()) { + final Traversal.Admin first = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(0)); + final Traversal.Admin second = (Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal(1)); + return P.gte(first).and(P.lt(second)); + } final Object[] arguments = getDoubleGenericLiteralArgument(ctx); return P.between(arguments[0], arguments[1]); } @@ -156,6 +190,10 @@ public P visitTraversalPredicate_between(final GremlinParser.TraversalPredicate_ */ @Override public P visitTraversalPredicate_within(final GremlinParser.TraversalPredicate_withinContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.within((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + // called with no args which is valid for java/groovy if (null == ctx.genericArgumentVarargs()) return P.within(); @@ -175,6 +213,10 @@ public P visitTraversalPredicate_within(final GremlinParser.TraversalPredicate_w */ @Override public P visitTraversalPredicate_without(final GremlinParser.TraversalPredicate_withoutContext ctx) { + if (ctx.nestedTraversal() != null) { + return P.without((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + // called with no args which is valid for java/groovy if (null == ctx.genericArgumentVarargs()) return P.without(); @@ -199,31 +241,49 @@ public P visitTraversalPredicate_not(final GremlinParser.TraversalPredicate_notC @Override public P visitTraversalPredicate_containing(final GremlinParser.TraversalPredicate_containingContext ctx) { + if (ctx.nestedTraversal() != null) { + return TextP.containing((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return TextP.containing((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument())); } @Override public P visitTraversalPredicate_notContaining(final GremlinParser.TraversalPredicate_notContainingContext ctx) { + if (ctx.nestedTraversal() != null) { + return TextP.notContaining((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return TextP.notContaining((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument())); } @Override public P visitTraversalPredicate_notEndingWith(final GremlinParser.TraversalPredicate_notEndingWithContext ctx) { + if (ctx.nestedTraversal() != null) { + return TextP.notEndingWith((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return TextP.notEndingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument())); } @Override public P visitTraversalPredicate_endingWith(final GremlinParser.TraversalPredicate_endingWithContext ctx) { + if (ctx.nestedTraversal() != null) { + return TextP.endingWith((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return TextP.endingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument())); } @Override public P visitTraversalPredicate_startingWith(final GremlinParser.TraversalPredicate_startingWithContext ctx) { + if (ctx.nestedTraversal() != null) { + return TextP.startingWith((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return TextP.startingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument())); } @Override public P visitTraversalPredicate_notStartingWith(final GremlinParser.TraversalPredicate_notStartingWithContext ctx) { + if (ctx.nestedTraversal() != null) { + return TextP.notStartingWith((Traversal.Admin) antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal())); + } return TextP.notStartingWith((String) antlr.argumentVisitor.visitStringArgument(ctx.stringArgument())); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java index a57f9cf40b3..bed196c29eb 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java @@ -19,9 +19,14 @@ package org.apache.tinkerpop.gremlin.language.grammar; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; + import java.util.Map; /** @@ -94,7 +99,14 @@ public GraphTraversal visitTraversalSourceSpawnMethod_addV(final GremlinParser.T */ @Override public GraphTraversal visitTraversalSourceSpawnMethod_E(final GremlinParser.TraversalSourceSpawnMethod_EContext ctx) { - return this.traversalSource.E(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs())); + if (ctx.nestedTraversal() != null) { + return this.traversalSource.E((Traversal) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()); + if (args.length == 1 && args[0] instanceof Traversal) { + return this.traversalSource.E((Traversal) args[0]); + } + return this.traversalSource.E(args); } /** @@ -102,7 +114,14 @@ public GraphTraversal visitTraversalSourceSpawnMethod_E(final GremlinParser.Trav */ @Override public GraphTraversal visitTraversalSourceSpawnMethod_V(final GremlinParser.TraversalSourceSpawnMethod_VContext ctx) { - return this.traversalSource.V(antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs())); + if (ctx.nestedTraversal() != null) { + return this.traversalSource.V((Traversal) anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal())); + } + final Object[] args = antlr.argumentVisitor.parseObjectVarargs(ctx.genericArgumentVarargs()); + if (args.length == 1 && args[0] instanceof Traversal) { + return this.traversalSource.V((Traversal) args[0]); + } + return this.traversalSource.V(args); } /** diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java index 7c296572cf4..f1fda293d5d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java @@ -745,6 +745,16 @@ public Void visitTraversalMethod_hasLabel_P(final GremlinParser.TraversalMethod_ return null; } + @Override + public Void visitTraversalMethod_hasLabel_Traversal(final GremlinParser.TraversalMethod_hasLabel_TraversalContext ctx) { + final String step = ctx.getChild(0).getText(); + sb.append(convertToPascalCase(step)); + sb.append("("); + visit(ctx.nestedTraversal()); + sb.append(")"); + return null; + } + @Override public Void visitTraversalMethod_hasLabel_String_String(final GremlinParser.TraversalMethod_hasLabel_String_StringContext ctx) { // if there is only one argument then cast to string otherwise it's ambiguous with hasLabel(P) @@ -962,6 +972,49 @@ public Void visitTraversalMethod_properties(final GremlinParser.TraversalMethod_ return handleGenerics(ctx); } + @Override + public Void visitTraversalMethod_property_Object(final GremlinParser.TraversalMethod_property_ObjectContext ctx) { + // Property(null) is ambiguous with Property(ITraversal) - cast null to IDictionary to disambiguate + if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null && + ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) { + visit(ctx.getChild(0)); + sb.append("("); + sb.append("(IDictionary) "); + visit(ctx.genericMapNullableArgument()); + sb.append(")"); + return null; + } + return super.visitTraversalMethod_property_Object(ctx); + } + + @Override + public Void visitTraversalMethod_property_Cardinality_Object(final GremlinParser.TraversalMethod_property_Cardinality_ObjectContext ctx) { + // Property(Cardinality, null) - cast null to IDictionary to disambiguate + if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null && + ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) { + visit(ctx.getChild(0)); + sb.append("("); + visit(ctx.traversalCardinality()); + sb.append(", "); + sb.append("(IDictionary) "); + visit(ctx.genericMapNullableArgument()); + sb.append(")"); + return null; + } + return super.visitTraversalMethod_property_Cardinality_Object(ctx); + } + + @Override + public Void visitTraversalMethod_property_Traversal(final GremlinParser.TraversalMethod_property_TraversalContext ctx) { + // Property(ITraversal) - cast to ITraversal to disambiguate + visit(ctx.getChild(0)); + sb.append("("); + sb.append("(ITraversal) "); + visit(ctx.nestedTraversal()); + sb.append(")"); + return null; + } + @Override public Void visitTraversalMethod_property_Cardinality_Object_Object_Object(final GremlinParser.TraversalMethod_property_Cardinality_Object_Object_ObjectContext ctx) { if (ctx.genericArgumentVarargs() == null || ctx.genericArgumentVarargs().getChildCount() == 0) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java index 3bd1cb5287c..289e8a6974e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java @@ -317,7 +317,11 @@ private String asString(final P p) { final StringBuilder sb = new StringBuilder(); if (p instanceof TextP) { sb.append("TextP.").append(p.getPredicateName()).append("("); - sb.append(argAsString(p.getValue())); + if (p.hasTraversal()) { + sb.append(argAsString(p.getTraversalValue())); + } else { + sb.append(argAsString(p.getValue())); + } } else if (p instanceof ConnectiveP) { // ConnectiveP gets some special handling because it's reduced to and(P, P, P) and we want it // generated the way it was written which was P.and(P).and(P) @@ -337,6 +341,19 @@ private String asString(final P p) { } else if (p instanceof NotP) { sb.append("P.not("); sb.append(argAsString(p.negate())); // Wrap internal P in `P.not(%s)` + } else if (p.hasTraversal()) { + // Traversal-bearing predicate: serialize as P.op(traversalGremlinLang) + sb.append("P.").append(p.getPredicateName()).append("("); + if (p.getTraversalValues() != null) { + // Multi-traversal predicate (within/without with multiple traversals) + final List> traversals = p.getTraversalValues(); + for (int i = 0; i < traversals.size(); i++) { + if (i > 0) sb.append(","); + sb.append(argAsString(traversals.get(i))); + } + } else { + sb.append(argAsString(p.getTraversalValue())); + } } else { sb.append("P.").append(p.getPredicateName()).append("("); sb.append(argAsString(p.getValue())); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java index f77f0f59742..aca1d241e40 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/NotP.java @@ -59,17 +59,41 @@ public String toString() { } /** - * Returns the original unwrapped P contained within this NotP, as double negation cancels out. + * Returns the inner predicate wrapped by this NotP. + */ + public P getWrapped() { + return this.originalP; + } + + /** + * Returns the original unwrapped P, since double negation cancels out. + * @apiNote Functionally identical to {@link #getWrapped()}, but fulfills the {@link java.util.function.Predicate#negate()} contract. */ @Override public P negate() { - return originalP; + return getWrapped(); } public P clone() { return new NotP<>(this.originalP.clone()); } + @Override + public boolean hasTraversal() { + return super.hasTraversal() || this.originalP.hasTraversal(); + } + + @Override + public boolean isResolvedEmpty() { + return this.originalP.isResolvedEmpty(); + } + + @Override + public void resolve(final Traverser.Admin traverser) { + super.resolve(traverser); + this.originalP.resolve(traverser); + } + /** * A NotPBiPredicate wraps a PBiPredicate and represents its negation. */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java index afc41b5681c..5f0606bd079 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java @@ -20,9 +20,13 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; +import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; +import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; +import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator; import java.io.Serializable; import java.util.ArrayList; @@ -31,7 +35,10 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; @@ -49,10 +56,23 @@ public class P implements Predicate, Serializable, Cloneable { protected Map variables = new HashMap<>(); protected Collection literals = Collections.EMPTY_LIST; private boolean isCollection = false; + private boolean resolvedEmpty = false; + private Traversal.Admin traversalValue; + private List> traversalValues; public P(final PBiPredicate biPredicate, final V value) { - setValue(value); this.biPredicate = biPredicate; + // If the value is a DefaultGraphTraversal (the type created by __.xxx() anonymous traversals), + // treat it as a child traversal rather than a literal. This handles the case where Java's + // overload resolution picks P(BiPredicate, V) instead of P(BiPredicate, Traversal) when + // the caller passes a GraphTraversal. We specifically check for DefaultGraphTraversal + // rather than Traversal to avoid catching internal traversal types like ConstantTraversal, + // ValueTraversal, and IdentityTraversal which are used as literal values in P. + if (value instanceof org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal) { + this.traversalValue = ((Traversal) value).asAdmin(); + } else { + setValue(value); + } } public P(final PBiPredicate biPredicate, final GValue value) { @@ -81,6 +101,29 @@ protected P(final PBiPredicate biPredicate, final Collection literals, this.isCollection = isCollection; } + /** + * Constructs a {@code P} with a child traversal whose result is resolved at runtime against the current + * traverser. The literals and variables are left at their defaults and will be populated when + * {@link #resolve(Traverser.Admin)} is called. + */ + public P(final PBiPredicate biPredicate, final Traversal.Admin traversalValue) { + this.biPredicate = biPredicate; + this.traversalValue = traversalValue; + } + + /** + * Constructs a {@code P} with multiple child traversals whose results are unioned at runtime against the + * current traverser. Only valid for collection predicates ({@link Contains#within}, {@link Contains#without}). + * The literals and variables are left at their defaults and will be populated when + * {@link #resolve(Traverser.Admin)} is called. + * + * @since 4.0.0 + */ + public P(final PBiPredicate biPredicate, final List> traversalValues) { + this.biPredicate = biPredicate; + this.traversalValues = traversalValues; + } + public PBiPredicate getBiPredicate() { return this.biPredicate; } @@ -162,6 +205,10 @@ public int hashCode() { result ^= this.variables.hashCode(); if (null != this.literals) result ^= this.literals.hashCode(); + if (null != this.traversalValue) + result ^= this.traversalValue.hashCode(); + if (null != this.traversalValues) + result ^= this.traversalValues.hashCode(); return result; } @@ -171,7 +218,9 @@ public boolean equals(final Object other) { ((P) other).getClass().equals(this.getClass()) && ((P) other).getBiPredicate().equals(this.biPredicate) && ((((P) other).variables == null && this.variables == null) || (((P) other).variables != null && ((P) other).variables.equals(this.variables))) && - ((((P) other).literals == null && this.literals == null) || (((P) other).literals != null && CollectionUtils.isEqualCollection(((P) other).literals, this.literals))); + ((((P) other).literals == null && this.literals == null) || (((P) other).literals != null && CollectionUtils.isEqualCollection(((P) other).literals, this.literals))) && + Objects.equals(((P) other).traversalValue, this.traversalValue) && + Objects.equals(((P) other).traversalValues, this.traversalValues); } @Override @@ -200,7 +249,17 @@ public P or(final Predicate predicate) { public P clone() { try { - return (P) super.clone(); + final P clone = (P) super.clone(); + if (this.traversalValue != null) { + clone.traversalValue = this.traversalValue.clone(); + } + if (this.traversalValues != null) { + clone.traversalValues = new ArrayList<>(this.traversalValues.size()); + for (final Traversal.Admin tv : this.traversalValues) { + clone.traversalValues.add(tv.clone()); + } + } + return clone; } catch (final CloneNotSupportedException e) { throw new IllegalStateException(e.getMessage(), e); } @@ -224,6 +283,187 @@ public Set> getGValues() { return results; } + /** + * Determines if this predicate holds a child traversal whose result is resolved at runtime. + */ + public boolean hasTraversal() { + return this.traversalValue != null || (this.traversalValues != null && !this.traversalValues.isEmpty()); + } + + /** + * Returns {@code true} if the most recent call to {@link #resolve(Traverser.Admin)} produced no results. + * Steps should check this after calling {@code resolve()} and short-circuit appropriately rather than + * calling {@link #test(Object)}, which would compare against {@code null}. + */ + public boolean isResolvedEmpty() { + return this.resolvedEmpty; + } + + /** + * Gets the child traversal value, if one was provided. Returns {@code null} when this predicate uses + * literal values or variables. + */ + public Traversal.Admin getTraversalValue() { + return this.traversalValue; + } + + /** + * Gets the list of child traversal values for multi-traversal predicates (e.g., {@code within(trav1, trav2)}). + * Returns {@code null} when this predicate uses a single traversal or literal values. + * + * @since 4.0.0 + */ + public List> getTraversalValues() { + return this.traversalValues; + } + + /** + * Resolves the child traversal against the given traverser, replacing the traversal value with the + * resolved literal(s) for this test cycle. If no traversal is present, this method returns immediately. + * + *

For all predicates, only the first result from the child traversal is used, + * consistent with {@code by(traversal)} semantics. For collection predicates + * ({@link Contains#within}, {@link Contains#without}), the first result should be a + * {@link Collection} (e.g., produced by {@code fold()}).

+ * + *

When multiple traversals are present (via {@link #traversalValues}), each traversal is evaluated + * independently, the first result from each is taken, and results are combined into a single collection. + * This is only valid for collection predicates ({@link Contains#within}, {@link Contains#without}).

+ */ + @SuppressWarnings("unchecked") + public void resolve(final Traverser.Admin traverser) { + if (this.traversalValues != null && !this.traversalValues.isEmpty()) { + resolveMultipleTraversals(traverser); + return; + } + + if (this.traversalValue == null) return; + + final Traversal.Admin trav = (Traversal.Admin) (Traversal.Admin) this.traversalValue; + prepareChildTraversal(traverser, trav); + + try { + if (!trav.hasNext()) { + // No results from the child traversal. For collection predicates (within/without) this is a + // legitimate empty set: within(empty) -> false, without(empty) -> true. Resolve to an empty + // collection and let Contains.test() apply the correct semantics rather than short-circuiting. + // For scalar predicates (eq/gt/lt/etc.) there is no comparison value, so flag as resolved-empty + // and let the step short-circuit (cannot satisfy). + this.literals = Collections.emptyList(); + if (this.biPredicate instanceof Contains) { + this.resolvedEmpty = false; + this.isCollection = true; + } else { + this.resolvedEmpty = true; + this.isCollection = false; + } + } else { + this.resolvedEmpty = false; + final Object firstResult = trav.next(); + if (this.biPredicate instanceof Contains) { + if (firstResult instanceof Collection) { + this.literals = (Collection) firstResult; + } else { + this.literals = Collections.singletonList((V) firstResult); + } + this.isCollection = true; + } else { + setValue((V) firstResult); + } + } + } finally { + CloseableIterator.closeIterator(trav); + } + } + + /** + * Resolves multiple child traversals, taking the first result from each and combining into a collection. + * Only valid for collection predicates ({@link Contains}). + */ + @SuppressWarnings("unchecked") + private void resolveMultipleTraversals(final Traverser.Admin traverser) { + final List allResults = new ArrayList<>(); + + for (final Traversal.Admin tv : this.traversalValues) { + final Traversal.Admin trav = (Traversal.Admin) (Traversal.Admin) tv; + prepareChildTraversal(traverser, trav); + + try { + if (trav.hasNext()) { + final Object firstResult = trav.next(); + if (firstResult instanceof Collection) { + allResults.addAll((Collection) firstResult); + } else { + allResults.add(firstResult); + } + } + } finally { + CloseableIterator.closeIterator(trav); + } + } + + // Multi-traversal resolution is only valid for collection predicates (within/without). An empty + // combined result is a legitimate empty set, so resolve to an empty collection and let Contains.test() + // apply the correct semantics (within(empty) -> false, without(empty) -> true) instead of short-circuiting. + this.resolvedEmpty = false; + this.isCollection = true; + this.literals = allResults.isEmpty() + ? Collections.emptyList() + : (Collection) (Collection) allResults; + } + + /** + * Prepares a child traversal for evaluation by splitting the current traverser and seeding it. + */ + @SuppressWarnings("unchecked") + private static void prepareChildTraversal(final Traverser.Admin traverser, final Traversal.Admin trav) { + final Traverser.Admin split = (Traverser.Admin) traverser.split(); + split.setSideEffects(trav.getSideEffects()); + split.setBulk(1L); + trav.reset(); + trav.addStart(split); + } + + //////////////// predicate traversal utilities + + /** + * Recursively integrates all child traversals found in the predicate tree into the given parent step. + * Handles {@link ConnectiveP} (recurses into children) and {@link NotP} (recurses into wrapped predicate). + */ + public static void integrateTraversals(final P p, final TraversalParent parent) { + if (p instanceof ConnectiveP) { + for (final P child : ((ConnectiveP) p).getPredicates()) { + integrateTraversals(child, parent); + } + } else if (p instanceof NotP) { + integrateTraversals(((NotP) p).getWrapped(), parent); + } else if (p.getTraversalValue() != null) { + parent.integrateChild(p.getTraversalValue()); + } else if (p.getTraversalValues() != null) { + for (final Traversal.Admin tv : p.getTraversalValues()) { + parent.integrateChild(tv); + } + } + } + + /** + * Recursively collects all child traversals from a predicate tree. + * Handles {@link ConnectiveP} (recurses into children) and {@link NotP} (recurses into wrapped predicate). + */ + public static void collectTraversals(final P p, final List> traversals) { + if (p instanceof ConnectiveP) { + for (final P child : ((ConnectiveP) p).getPredicates()) { + collectTraversals(child, traversals); + } + } else if (p instanceof NotP) { + collectTraversals(((NotP) p).getWrapped(), traversals); + } else if (p.getTraversalValue() != null) { + traversals.add(p.getTraversalValue()); + } else if (p.getTraversalValues() != null) { + traversals.addAll(p.getTraversalValues()); + } + } + //////////////// statics /** @@ -394,6 +634,8 @@ public static P between(final GValue first, final GValue second) { * @since 3.0.0-incubating */ public static P within(final V... values) { + final P traversalP = handleContainsVarargs(values, Contains.within, "within"); + if (traversalP != null) return traversalP; final V[] v = null == values ? (V[]) new Object[] { null } : (V[]) values; return P.within(Arrays.asList(v)); } @@ -427,6 +669,8 @@ public static P within(final Collection value) { * @since 3.0.0-incubating */ public static P without(final V... values) { + final P traversalP = handleContainsVarargs(values, Contains.without, "without"); + if (traversalP != null) return traversalP; final V[] v = null == values ? (V[]) new Object[] { null } : values; return P.without(Arrays.asList(v)); } @@ -453,6 +697,106 @@ public static P without(final Collection value) { return new P(Contains.without, value); } + /** + * Determines if values are equal using a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P eq(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Compare.eq, traversalValue.asAdmin()); + } + + /** + * Determines if values are not equal using a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P neq(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Compare.neq, traversalValue.asAdmin()); + } + + /** + * Determines if a value is less than another using a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P lt(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Compare.lt, traversalValue.asAdmin()); + } + + /** + * Determines if a value is less than or equal to another using a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P lte(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Compare.lte, traversalValue.asAdmin()); + } + + /** + * Determines if a value is greater than another using a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P gt(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Compare.gt, traversalValue.asAdmin()); + } + + /** + * Determines if a value is greater than or equal to another using a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P gte(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Compare.gte, traversalValue.asAdmin()); + } + + /** + * Determines if a value is within the results of a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P within(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Contains.within, traversalValue.asAdmin()); + } + + /** + * Determines if a value is within the union of results from multiple child traversals resolved at runtime. + * Each traversal is evaluated independently and results are combined into a single collection. + * + * @since 4.0.0 + */ + public static P within(final Traversal first, final Traversal second, final Traversal... more) { + return containsTraversals(Contains.within, first, second, more); + } + + /** + * Determines if a value is not within the results of a child traversal resolved at runtime. + * + * @since 4.0.0 + */ + public static P without(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new P(Contains.without, traversalValue.asAdmin()); + } + + /** + * Determines if a value is not within the union of results from multiple child traversals resolved at runtime. + * Each traversal is evaluated independently and results are combined into a single collection. + * + * @since 4.0.0 + */ + public static P without(final Traversal first, final Traversal second, final Traversal... more) { + return containsTraversals(Contains.without, first, second, more); + } + /** * Determines if a value is of a type denoted by {@code GType}. * @@ -497,4 +841,79 @@ public static P test(final PBiPredicate biPredicate, final Object value) { public static P not(final P predicate) { return predicate.negate(); } + + /** + * Handles varargs traversal detection for within/without. Returns a P if traversals were found, + * or null if the values are plain literals. + */ + @SuppressWarnings("unchecked") + private static P handleContainsVarargs(final V[] values, final PBiPredicate predicate, final String stepName) { + if (values != null && values.length == 1 && values[0] instanceof Traversal) { + final Traversal trav = (Traversal) values[0]; + ChildTraversalValidator.validate(trav.asAdmin()); + return new P(predicate, trav.asAdmin()); + } + if (values != null && values.length > 1 && allTraversals(values)) { + final List> traversals = new ArrayList<>(values.length); + for (final V v : values) { + traversals.add(((Traversal) v).asAdmin()); + } + for (final Traversal.Admin tv : traversals) { + ChildTraversalValidator.validate(tv); + } + return new P(predicate, traversals); + } + if (values != null && values.length > 1 && anyTraversals(values)) { + throw new IllegalArgumentException( + "Cannot mix traversals and literal values in " + stepName + "(). " + + "Use " + stepName + "(__.constant(val1), __.constant(val2)) to wrap all values as traversals."); + } + return null; + } + + /** + * Creates a Contains predicate from multiple validated child traversals. + */ + @SuppressWarnings("unchecked") + private static P containsTraversals(final PBiPredicate predicate, final Traversal first, + final Traversal second, final Traversal... more) { + final List> traversals = new ArrayList<>(2 + (more != null ? more.length : 0)); + traversals.add(first.asAdmin()); + traversals.add(second.asAdmin()); + if (more != null) { + for (final Traversal tv : more) { + traversals.add(tv.asAdmin()); + } + } + for (final Traversal.Admin tv : traversals) { + ChildTraversalValidator.validate(tv); + } + return new P(predicate, traversals); + } + + /** + * Checks if all elements in the array are {@link Traversal} instances (specifically + * {@link org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal}). + */ + private static boolean allTraversals(final V[] values) { + for (final V v : values) { + if (!(v instanceof org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal)) { + return false; + } + } + return true; + } + + /** + * Checks if any element in the array is a {@link Traversal} instance (specifically + * {@link org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal}). + */ + private static boolean anyTraversals(final V[] values) { + for (final V v : values) { + if (v instanceof org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal) { + return true; + } + } + return false; + } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java index d1d8c210197..c0bd1551854 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator; import java.util.Collection; import java.util.Map; @@ -38,6 +39,16 @@ public TextP(final PBiPredicate biPredicate, final GValue biPredicate, final Traversal.Admin traversalValue) { + super(biPredicate, traversalValue); + } + protected TextP(final PBiPredicate biPredicate, final Collection literals, final Map variables) { super(biPredicate, literals, variables, false); } @@ -76,6 +87,16 @@ public static TextP startingWith(final GValue value) { return new TextP(Text.startingWith, value); } + /** + * Determines if String does start with the value resolved from a child traversal at runtime. + * + * @since 4.0.0 + */ + public static TextP startingWith(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new TextP(Text.startingWith, traversalValue.asAdmin()); + } + /** * Determines if String does not start with the given value. * @@ -95,7 +116,17 @@ public static TextP notStartingWith(final GValue value) { } /** - * Determines if String does start with the given value. + * Determines if String does not start with the value resolved from a child traversal at runtime. + * + * @since 4.0.0 + */ + public static TextP notStartingWith(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new TextP(Text.notStartingWith, traversalValue.asAdmin()); + } + + /** + * Determines if String does end with the given value. * * @since 3.4.0 */ @@ -104,7 +135,7 @@ public static TextP endingWith(final String value) { } /** - * Determines if String does start with the given value. + * Determines if String does end with the given value. * * @since 3.8.0 */ @@ -113,7 +144,17 @@ public static TextP endingWith(final GValue value) { } /** - * Determines if String does not start with the given value. + * Determines if String does end with the value resolved from a child traversal at runtime. + * + * @since 4.0.0 + */ + public static TextP endingWith(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new TextP(Text.endingWith, traversalValue.asAdmin()); + } + + /** + * Determines if String does not end with the given value. * * @since 3.4.0 */ @@ -122,7 +163,7 @@ public static TextP notEndingWith(final String value) { } /** - * Determines if String does not start with the given value. + * Determines if String does not end with the given value. * * @since 3.8.0 */ @@ -130,6 +171,16 @@ public static TextP notEndingWith(final GValue value) { return new TextP(Text.notEndingWith, value); } + /** + * Determines if String does not end with the value resolved from a child traversal at runtime. + * + * @since 4.0.0 + */ + public static TextP notEndingWith(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new TextP(Text.notEndingWith, traversalValue.asAdmin()); + } + /** * Determines if String does contain the given value. * @@ -148,6 +199,16 @@ public static TextP containing(final GValue value) { return new TextP(Text.containing, value); } + /** + * Determines if String does contain the value resolved from a child traversal at runtime. + * + * @since 4.0.0 + */ + public static TextP containing(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new TextP(Text.containing, traversalValue.asAdmin()); + } + /** * Determines if String does not contain the given value. * @@ -165,6 +226,16 @@ public static TextP notContaining(final String value) { public static TextP notContaining(final GValue value) { return new TextP(Text.notContaining, value); } + + /** + * Determines if String does not contain the value resolved from a child traversal at runtime. + * + * @since 4.0.0 + */ + public static TextP notContaining(final Traversal traversalValue) { + ChildTraversalValidator.validate(traversalValue.asAdmin()); + return new TextP(Text.notContaining, traversalValue.asAdmin()); + } /** * Determines if String has a match with the given regex pattern. The TinkerPop reference implementation uses diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java index bccb983665e..e3f0d90ff6d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalStrategies.java @@ -52,6 +52,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.ProductiveByStrategy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ChildTraversalVerificationStrategy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy; @@ -287,6 +288,7 @@ public static final class GlobalCache { LazyBarrierStrategy.instance(), ProfileStrategy.instance(), StandardVerificationStrategy.instance(), + ChildTraversalVerificationStrategy.instance(), GValueReductionStrategy.instance()); registerStrategies(Graph.class, graphStrategies); registerStrategies(EmptyGraph.class, new DefaultTraversalStrategies()); 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 c42859f7a58..81844bd35b5 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 @@ -209,6 +209,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics; +import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator; import org.apache.tinkerpop.gremlin.structure.Column; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; @@ -414,6 +415,23 @@ public default GraphTraversal V(final Object... vertexIdsOrElements) return this.asAdmin().addStep(step); } + /** + * A {@code V} step that accepts a child traversal whose results are used as vertex IDs for lookup. + * This form is only valid as a mid-traversal step; using it as a start step will throw an + * {@link IllegalStateException} at runtime because there is no traverser context to evaluate the child traversal. + * + * @param traversal the child traversal that produces vertex IDs + * @return the traversal with an appended {@link GraphStep} + * @see Reference Documentation - Graph Step + * @since 4.0.0 + */ + public default GraphTraversal V(final Traversal traversal) { + if (null == traversal) return V(new Object[]{ null }); + ChildTraversalValidator.validate(traversal.asAdmin()); + this.asAdmin().getGremlinLang().addStep(Symbols.V, traversal); + return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Vertex.class, false, traversal.asAdmin())); + } + /** * A {@code E} step is usually used to start a traversal but it may also be used mid-traversal. * @@ -437,6 +455,23 @@ public default GraphTraversal E(final Object... edgeIdsOrElements) { return this.asAdmin().addStep(step); } + /** + * A {@code E} step that accepts a child traversal whose results are used as edge IDs for lookup. + * This form is only valid as a mid-traversal step; using it as a start step will throw an + * {@link IllegalStateException} at runtime because there is no traverser context to evaluate the child traversal. + * + * @param traversal the child traversal that produces edge IDs + * @return the traversal with an appended {@link GraphStep} + * @see Reference Documentation - E Step + * @since 4.0.0 + */ + public default GraphTraversal E(final Traversal traversal) { + if (null == traversal) return E(new Object[]{ null }); + ChildTraversalValidator.validate(traversal.asAdmin()); + this.asAdmin().getGremlinLang().addStep(Symbols.E, traversal); + return this.asAdmin().addStep(new GraphStep<>(this.asAdmin(), Edge.class, false, traversal.asAdmin())); + } + /** * Map the {@link Vertex} to its adjacent vertices given a direction. * @@ -2670,6 +2705,47 @@ public default GraphTraversal has(final T accessor, final Object value) { } } + /** + * Filters vertices, edges and vertex properties based on their properties using a child traversal + * whose results are resolved at runtime against the current traverser. The resolved results are used + * with {@code P.within()} semantics for comparison against the named property. + * + * @param propertyKey the key of the property to filter on + * @param traversal the child traversal whose results are used as the filter value + * @return the traversal with an appended {@link HasStep} + * @see Reference Documentation - Has Step + * @since 4.0.0 + */ + public default GraphTraversal has(final String propertyKey, final Traversal traversal) { + if (null == traversal) return has(propertyKey, (Object) null); + ChildTraversalValidator.validate(traversal.asAdmin()); + this.asAdmin().getGremlinLang().addStep(Symbols.has, propertyKey, traversal); + final HasContainer hasContainer = new HasContainer(propertyKey, P.eq(traversal.asAdmin())); + return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer)); + } + + /** + * Filters vertices, edges and vertex properties based on their properties using a child traversal + * whose results are resolved at runtime against the current traverser. The resolved results are used + * with {@code P.within()} semantics for comparison against the T-accessor value (id or label). + * + * @param accessor the {@link T} accessor of the property to filter on + * @param traversal the child traversal whose results are used as the filter value + * @return the traversal with an appended {@link HasStep} + * @see Reference Documentation - Has Step + * @since 4.0.0 + */ + public default GraphTraversal has(final T accessor, final Traversal traversal) { + if (null == accessor) + throw new IllegalArgumentException("The T accessor value of has(T,Traversal) cannot be null"); + if (null == traversal) return has(accessor, (Object) null); + ChildTraversalValidator.validate(traversal.asAdmin()); + + this.asAdmin().getGremlinLang().addStep(Symbols.has, accessor, traversal); + final HasContainer hasContainer = new HasContainer(accessor.getAccessor(), P.eq(traversal.asAdmin())); + return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer)); + } + /** * Filters vertices, edges and vertex properties based on their properties. * @@ -2702,6 +2778,27 @@ public default GraphTraversal has(final String label, final String propert return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(propertyKey, value instanceof P ? (P) value : P.eq(value))); } + /** + * Filters vertices, edges and vertex properties based on their label and a property value resolved + * from a child traversal at runtime. The label is matched first, then the child traversal results + * are used with {@code P.within()} semantics for comparison against the named property. + * + * @param label the label of the {@link Element} + * @param propertyKey the key of the property to filter on + * @param traversal the child traversal whose results are used as the filter value + * @return the traversal with an appended {@link HasStep} + * @see Reference Documentation - Has Step + * @since 4.0.0 + */ + public default GraphTraversal has(final String label, final String propertyKey, final Traversal traversal) { + if (null == traversal) return has(label, propertyKey, (Object) null); + ChildTraversalValidator.validate(traversal.asAdmin()); + this.asAdmin().getGremlinLang().addStep(Symbols.has, label, propertyKey, traversal); + TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), P.eq(label))); + final HasContainer hasContainer = new HasContainer(propertyKey, P.eq(traversal.asAdmin())); + return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer)); + } + /** * Filters vertices, edges and vertex properties based on the existence of properties. * @@ -2797,6 +2894,23 @@ public default GraphTraversal hasLabel(final P predicate) { } } + /** + * Filters vertices, edges and vertex properties based on their label using a child traversal + * whose results are resolved at runtime against the current traverser. + * + * @param traversal the child traversal whose results are used as the label filter value + * @return the traversal with an appended {@link HasStep} + * @see Reference Documentation - Has Step + * @since 4.0.0 + */ + public default GraphTraversal hasLabel(final Traversal traversal) { + if (null == traversal) return hasLabel((String) null); + ChildTraversalValidator.validate(traversal.asAdmin()); + this.asAdmin().getGremlinLang().addStep(Symbols.hasLabel, traversal); + final HasContainer hasContainer = new HasContainer(T.label.getAccessor(), P.eq(traversal.asAdmin())); + return this.asAdmin().addStep(new HasStep(this.asAdmin(), hasContainer)); + } + /** * Filters vertices, edges and vertex properties based on their label. * @@ -3022,7 +3136,14 @@ public default GraphTraversal is(final P predicate) { */ public default GraphTraversal is(final Object value) { this.asAdmin().getGremlinLang().addStep(Symbols.is, value); - P predicate = value instanceof P ? (P) value : P.eq((E) value); + P predicate; + if (value instanceof P) { + predicate = (P) value; + } else if (value instanceof Traversal) { + predicate = (P) P.eq(((Traversal) value).asAdmin()); + } else { + predicate = P.eq((E) value); + } return this.asAdmin().addStep(predicate.isParameterized() ? new IsStepPlaceholder<>(this.asAdmin(), predicate) : new IsStep<>(this.asAdmin(), predicate)); } @@ -3825,6 +3946,25 @@ public default GraphTraversal property(final Map value) { } return this; } + + /** + * Sets properties on the current element using a child traversal that produces a {@code Map}. + * Each entry in the resulting Map becomes a property (key → value) on the element. The traversal + * is evaluated at execution time against the current traverser. + * + * @param mapTraversal a traversal that produces a {@code Map} of property key/value pairs + * @return the traversal with the {@link AddPropertyStepPlaceholder} added + * @see AddProperty Step + * @since 4.0.0 + */ + public default GraphTraversal property(final Traversal mapTraversal) { + if (null == mapTraversal) return this; + ChildTraversalValidator.validate(mapTraversal.asAdmin()); + this.asAdmin().getGremlinLang().addStep(Symbols.property, mapTraversal); + this.asAdmin().addStep(new AddPropertyStepPlaceholder(this.asAdmin(), null, null, mapTraversal.asAdmin(), true)); + return this; + } + ///////////////////// BRANCH STEPS ///////////////////// /** @@ -3972,6 +4112,10 @@ public default GraphTraversal choose(final P choosePredicate, if (choosePredicate.isParameterized()) { throw new IllegalArgumentException("Parameterized predicates are not supported by choose()"); } + if (choosePredicate.hasTraversal()) { + throw new IllegalArgumentException("Traversal-bearing predicates are not supported by choose(). " + + "The predicate's child traversal cannot be resolved in this context."); + } this.asAdmin().getGremlinLang().addStep(Symbols.choose, choosePredicate, trueChoice, falseChoice); return this.asAdmin().addStep(new ChooseStep(this.asAdmin(), (Traversal.Admin) __.is(choosePredicate), (Traversal.Admin) trueChoice, (Traversal.Admin) falseChoice)); } @@ -4009,6 +4153,10 @@ public default GraphTraversal choose(final P choosePredicate, if (choosePredicate.isParameterized()) { throw new IllegalArgumentException("Parameterized predicates are not supported by choose()"); } + if (choosePredicate.hasTraversal()) { + throw new IllegalArgumentException("Traversal-bearing predicates are not supported by choose(). " + + "The predicate's child traversal cannot be resolved in this context."); + } this.asAdmin().getGremlinLang().addStep(Symbols.choose, choosePredicate, trueChoice); return this.asAdmin().addStep(new ChooseStep(this.asAdmin(), (Traversal.Admin) __.is(choosePredicate), (Traversal.Admin) trueChoice, (Traversal.Admin) __.identity())); } 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 aec1d6fadd8..3bce63c4012 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 @@ -42,6 +42,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStepContract; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.RequirementsStrategy; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; +import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -540,6 +541,24 @@ public GraphTraversal V(final Object... vertexIds) { return traversal.addStep(step); } + /** + * Spawns a {@link GraphTraversal} starting with vertices whose IDs are resolved from a child traversal. + * As a start step, a synthetic traverser is generated to seed the child traversal evaluation, + * consistent with how {@code mergeV(traversal)} handles start steps. The child traversal should + * be self-contained (e.g., {@code __.V(1).id()}) rather than dependent on an incoming traverser. + * + * @param traversal the child traversal that produces vertex IDs + * @since 4.0.0 + */ + public GraphTraversal V(final Traversal traversal) { + if (null == traversal) return V(new Object[]{ null }); + ChildTraversalValidator.validate(traversal.asAdmin()); + final GraphTraversalSource clone = this.clone(); + clone.gremlinLang.addStep(GraphTraversal.Symbols.V, traversal); + final GraphTraversal.Admin traversalAdmin = new DefaultGraphTraversal<>(clone); + return traversalAdmin.addStep(new GraphStep<>(traversalAdmin, Vertex.class, true, traversal.asAdmin())); + } + /** * Spawns a {@link GraphTraversal} starting with all edges or some subset of edges as specified by their unique * identifier. @@ -561,6 +580,24 @@ public GraphTraversal E(final Object... edgeIds) { return traversal.addStep(step); } + /** + * Spawns a {@link GraphTraversal} starting with edges whose IDs are resolved from a child traversal. + * As a start step, a synthetic traverser is generated to seed the child traversal evaluation, + * consistent with how {@code mergeE(traversal)} handles start steps. The child traversal should + * be self-contained (e.g., {@code __.V(1).outE().id()}) rather than dependent on an incoming traverser. + * + * @param traversal the child traversal that produces edge IDs + * @since 4.0.0 + */ + public GraphTraversal E(final Traversal traversal) { + if (null == traversal) return E(new Object[]{ null }); + ChildTraversalValidator.validate(traversal.asAdmin()); + final GraphTraversalSource clone = this.clone(); + clone.gremlinLang.addStep(GraphTraversal.Symbols.E, traversal); + final GraphTraversal.Admin traversalAdmin = new DefaultGraphTraversal<>(clone); + return traversalAdmin.addStep(new GraphStep<>(traversalAdmin, Edge.class, true, traversal.asAdmin())); + } + /** * Spawns a {@link GraphTraversal} starting with a list of available services. * diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java index 01986b45348..46eddc4e2fc 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java @@ -140,6 +140,13 @@ public static GraphTraversal V(final Object... vertexIdsOrElement return __.start().V(vertexIdsOrElements); } + /** + * @see GraphTraversal#V(Traversal) + */ + public static GraphTraversal V(final Traversal traversal) { + return __.start().V(traversal); + } + /** * @see GraphTraversal#E(Object...) */ @@ -147,6 +154,13 @@ public static GraphTraversal E(final Object... edgeIdsOrElements) { return __.start().E(edgeIdsOrElements); } + /** + * @see GraphTraversal#E(Traversal) + */ + public static GraphTraversal E(final Traversal traversal) { + return __.start().E(traversal); + } + /** * @see GraphTraversal#to(Direction) */ @@ -1092,6 +1106,13 @@ public static GraphTraversal has(final String propertyKey, final P return __.start().has(propertyKey, predicate); } + /** + * @see GraphTraversal#has(String, Traversal) + */ + public static GraphTraversal has(final String propertyKey, final Traversal traversal) { + return __.start().has(propertyKey, traversal); + } + /** * @see GraphTraversal#has(T, P) */ @@ -1113,6 +1134,13 @@ public static GraphTraversal has(final T accessor, final Object value) return __.start().has(accessor, value); } + /** + * @see GraphTraversal#has(T, Traversal) + */ + public static GraphTraversal has(final T accessor, final Traversal traversal) { + return __.start().has(accessor, traversal); + } + /** * @see GraphTraversal#has(String, String, Object) */ @@ -1142,6 +1170,13 @@ public static GraphTraversal has(final String label, final String prop return __.start().has(label, propertyKey, predicate); } + /** + * @see GraphTraversal#has(String, String, Traversal) + */ + public static GraphTraversal has(final String label, final String propertyKey, final Traversal traversal) { + return __.start().has(label, propertyKey, traversal); + } + /** * @see GraphTraversal#has(String) */ @@ -1177,6 +1212,13 @@ public static GraphTraversal hasLabel(final P predicate) { return __.start().hasLabel(predicate); } + /** + * @see GraphTraversal#hasLabel(Traversal) + */ + public static GraphTraversal hasLabel(final Traversal traversal) { + return __.start().hasLabel(traversal); + } + /** * @see GraphTraversal#hasId(Object, Object...) */ @@ -1558,6 +1600,13 @@ public static GraphTraversal property(final Map value) return __.start().property(value); } + /** + * @see GraphTraversal#property(Traversal) + */ + public static GraphTraversal property(final Traversal mapTraversal) { + return __.start().property(mapTraversal); + } + ///////////////////// BRANCH STEPS ///////////////////// /** diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/AcceptsChildPredicateTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/AcceptsChildPredicateTraversal.java new file mode 100644 index 00000000000..fef3841441b --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/AcceptsChildPredicateTraversal.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.step; + +/** + * Marker interface for steps that accept user-supplied child traversals embedded as predicate or lookup + * arguments (for example {@code has(key, traversal)}, {@code is(P.gt(traversal))}, + * {@code V(traversal)}, or {@code property(traversal)}). + *

+ * The {@link org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ChildTraversalVerificationStrategy} + * validates the local children of every step implementing this interface, rejecting child traversals that + * contain mutating steps. New steps that accept such traversals should implement this interface so they are + * validated automatically rather than relying on a hardcoded step list. + * + * @since 4.0.0 + */ +public interface AcceptsChildPredicateTraversal { +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java index 73bec11d64d..c84028f9017 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.branch; +import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Pick; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal; @@ -122,6 +123,10 @@ public void addChildOption(final M pickToken, final Traversal.Admin traver } } else if (pickToken instanceof Traversal) { throw new IllegalArgumentException("Traversal is not allowed as a Pick token for choose().option()"); + } else if (pickToken instanceof P && ((P) pickToken).hasTraversal()) { + throw new IllegalArgumentException( + "Traversal-bearing predicates are not supported as option keys in choose(). " + + "The predicate's child traversal cannot be resolved in this context."); } else { super.addChildOption(pickToken, traversalOption); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java index 64853f6614f..f17795dc0b4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java @@ -21,15 +21,19 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import java.util.EnumSet; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Set; -public final class AllStep extends FilterStep { +public final class AllStep extends FilterStep implements TraversalParent, AcceptsChildPredicateTraversal { private P predicate; @@ -41,10 +45,16 @@ public AllStep(final Traversal.Admin traversal, final P predicate) { } this.predicate = predicate; + P.integrateTraversals(this.predicate, this); } @Override protected boolean filter(final Traverser.Admin traverser) { + if (this.predicate.hasTraversal()) { + this.predicate.resolve(traverser); + if (this.predicate.isResolvedEmpty()) return false; + } + final S item = traverser.get(); if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) { @@ -65,6 +75,14 @@ public String toString() { return StringFactory.stepString(this, this.predicate); } + @SuppressWarnings("unchecked") + @Override + public List> getLocalChildren() { + final List> traversals = new ArrayList<>(); + P.collectTraversals(this.predicate, traversals); + return (List) Collections.unmodifiableList(traversals); + } + @Override public AllStep clone() { final AllStep clone = (AllStep) super.clone(); @@ -74,6 +92,12 @@ public AllStep clone() { @Override public Set getRequirements() { - return EnumSet.of(TraverserRequirement.OBJECT); + return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT); + } + + @Override + public void setTraversal(final Traversal.Admin parentTraversal) { + super.setTraversal(parentTraversal); + P.integrateTraversals(this.predicate, this); } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java index 9881186d7ca..ed0216934c6 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java @@ -21,15 +21,19 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import java.util.EnumSet; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Set; -public final class AnyStep extends FilterStep { +public final class AnyStep extends FilterStep implements TraversalParent, AcceptsChildPredicateTraversal { private P predicate; @@ -41,10 +45,16 @@ public AnyStep(final Traversal.Admin traversal, final P predicate) { } this.predicate = predicate; + P.integrateTraversals(this.predicate, this); } @Override protected boolean filter(final Traverser.Admin traverser) { + if (this.predicate.hasTraversal()) { + this.predicate.resolve(traverser); + if (this.predicate.isResolvedEmpty()) return false; + } + final S item = traverser.get(); if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) { @@ -65,6 +75,14 @@ public String toString() { return StringFactory.stepString(this, this.predicate); } + @SuppressWarnings("unchecked") + @Override + public List> getLocalChildren() { + final List> traversals = new ArrayList<>(); + P.collectTraversals(this.predicate, traversals); + return (List) Collections.unmodifiableList(traversals); + } + @Override public AnyStep clone() { final AnyStep clone = (AnyStep) super.clone(); @@ -74,6 +92,12 @@ public AnyStep clone() { @Override public Set getRequirements() { - return EnumSet.of(TraverserRequirement.OBJECT); + return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT); + } + + @Override + public void setTraversal(final Traversal.Admin parentTraversal) { + super.setTraversal(parentTraversal); + P.integrateTraversals(this.predicate, this); } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java index e7ef0095657..a69e8f78719 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java @@ -18,10 +18,13 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.filter; +import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring; import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; @@ -31,22 +34,25 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.EnumSet; import java.util.List; import java.util.Set; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public class HasStep extends FilterStep implements HasContainerHolder, Configuring { +public class HasStep extends FilterStep implements HasContainerHolder, Configuring, TraversalParent, AcceptsChildPredicateTraversal { private final Parameters parameters = new Parameters(); private List hasContainers; + private List> childTraversals = new ArrayList<>(); public HasStep(final Traversal.Admin traversal, final HasContainer... hasContainers) { super(traversal); this.hasContainers = new ArrayList<>(); - Collections.addAll(this.hasContainers, hasContainers); + for (final HasContainer hc : hasContainers) { + this.hasContainers.add(hc); + collectChildTraversals(hc); + } } @Override @@ -63,14 +69,71 @@ public void configure(final Object... keyValues) { protected boolean filter(final Traverser.Admin traverser) { // the generic S is defined as Element but Property can also be used with HasStep so this seems to cause // problems with some jdk versions. - if (traverser.get() instanceof Element) - return HasContainer.testAll(traverser.get(), this.hasContainers); - else if (traverser.get() instanceof Property) - return HasContainer.testAll((Property) traverser.get(), this.hasContainers); - else + // Check Property BEFORE Element because VertexProperty implements both interfaces. + // HasContainer.test(Property) correctly handles T.key and T.value accessors, whereas + // HasContainer.test(Element) would fall through to element.properties("~key") which fails. + if (traverser.get() instanceof Property) { + return testAllWithTraversals(traverser, (Property) traverser.get()); + } else if (traverser.get() instanceof Element) { + return testAllWithTraversals(traverser, (Element) traverser.get()); + } else { throw new IllegalStateException(String.format( "Traverser to has() must be of type Property or Element, not %s", traverser.get().getClass().getName())); + } + } + + /** + * Tests all HasContainers against an Element. Traversal-bearing containers carry a {@code P} predicate + * (e.g. {@code P.eq(traversal)}) whose child traversal is resolved against the current traverser before + * the standard {@link HasContainer#test(Element)} is applied. + */ + private boolean testAllWithTraversals(final Traverser.Admin traverser, final Element element) { + for (final HasContainer hc : this.hasContainers) { + if (!resolvePredicate(hc, traverser) || !hc.test(element)) { + return false; + } + } + return true; + } + + /** + * Tests all HasContainers against a Property. See {@link #testAllWithTraversals(Traverser.Admin, Element)}. + */ + private boolean testAllWithTraversals(final Traverser.Admin traverser, final Property property) { + for (final HasContainer hc : this.hasContainers) { + if (!resolvePredicate(hc, traverser) || !hc.test(property)) { + return false; + } + } + return true; + } + + /** + * Resolves a container's predicate traversal (if any) against the current traverser, mutating the + * predicate with the resolved value for this test cycle. + * + * @return {@code false} if the predicate resolved empty (no comparison value), meaning the element + * cannot match and the caller should short-circuit; {@code true} otherwise. + */ + private boolean resolvePredicate(final HasContainer hc, final Traverser.Admin traverser) { + if (hc.hasTraversal()) { + hc.getPredicate().resolve(traverser); + return !hc.getPredicate().isResolvedEmpty(); + } + return true; + } + + /** + * Collects the child traversals embedded within a HasContainer's predicate (including + * {@link org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP}, which may carry traversals on + * child predicates) into {@link #childTraversals}. Parenting is deferred to + * {@link #setTraversal(Traversal.Admin)} which is the single integration point. + */ + private void collectChildTraversals(final HasContainer hc) { + if (hc.getPredicate().hasTraversal()) { + P.collectTraversals(hc.getPredicate(), this.childTraversals); + } } @Override @@ -91,23 +154,49 @@ public void removeHasContainer(final HasContainer hasContainer) { @Override public void addHasContainer(final HasContainer hasContainer) { this.hasContainers.add(hasContainer); + // A container may be added after this step has already been parented (e.g. by a strategy), so collect + // its child traversals and integrate just those new ones immediately. + final int before = this.childTraversals.size(); + collectChildTraversals(hasContainer); + for (int i = before; i < this.childTraversals.size(); i++) { + this.integrateChild(this.childTraversals.get(i)); + } + } + + @SuppressWarnings("unchecked") + @Override + public List> getLocalChildren() { + return (List) Collections.unmodifiableList(this.childTraversals); } @Override public Set getRequirements() { - return EnumSet.of(TraverserRequirement.OBJECT); + return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT); } @Override public HasStep clone() { final HasStep clone = (HasStep) super.clone(); clone.hasContainers = new ArrayList<>(); + clone.childTraversals = new ArrayList<>(); for (final HasContainer hasContainer : this.hasContainers) { - clone.addHasContainer(hasContainer.clone()); + final HasContainer clonedHc = hasContainer.clone(); + clone.hasContainers.add(clonedHc); + if (clonedHc.getPredicate().hasTraversal()) { + P.collectTraversals(clonedHc.getPredicate(), clone.childTraversals); + } } return clone; } + @Override + public void setTraversal(final Traversal.Admin parentTraversal) { + super.setTraversal(parentTraversal); + for (final Traversal.Admin childTraversal : this.childTraversals) { + this.integrateChild(childTraversal); + } + } + @Override public int hashCode() { int result = super.hashCode(); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java index 70ad55ff318..e49c7e35376 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java @@ -21,27 +21,36 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; -import java.util.EnumSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Set; /** * @author Daniel Kuppitz (http://gremlin.guru) * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class IsStep extends FilterStep implements IsStepContract { +public final class IsStep extends FilterStep implements IsStepContract, TraversalParent, AcceptsChildPredicateTraversal { private P predicate; public IsStep(final Traversal.Admin traversal, final P predicate) { super(traversal); this.predicate = predicate; + P.integrateTraversals(this.predicate, this); } @Override protected boolean filter(final Traverser.Admin traverser) { + if (this.predicate.hasTraversal()) { + this.predicate.resolve(traverser); + if (this.predicate.isResolvedEmpty()) return false; + } return this.predicate.test(traverser.get()); } @@ -55,6 +64,14 @@ public P getPredicate() { return this.predicate; } + @SuppressWarnings("unchecked") + @Override + public List> getLocalChildren() { + final List> traversals = new ArrayList<>(); + P.collectTraversals(this.predicate, traversals); + return (List) Collections.unmodifiableList(traversals); + } + @Override public IsStep clone() { final IsStep clone = (IsStep) super.clone(); @@ -69,7 +86,12 @@ public int hashCode() { @Override public Set getRequirements() { - return EnumSet.of(TraverserRequirement.OBJECT); + return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT); } + @Override + public void setTraversal(final Traversal.Admin parentTraversal) { + super.setTraversal(parentTraversal); + P.integrateTraversals(this.predicate, this); + } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java index 542d16ca5c2..6344e3a2b8e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java @@ -21,15 +21,19 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import java.util.EnumSet; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Set; -public final class NoneStep extends FilterStep { +public final class NoneStep extends FilterStep implements TraversalParent, AcceptsChildPredicateTraversal { private P predicate; @@ -41,10 +45,18 @@ public NoneStep(final Traversal.Admin traversal, final P predicate) { } this.predicate = predicate; + P.integrateTraversals(this.predicate, this); } @Override protected boolean filter(final Traverser.Admin traverser) { + if (this.predicate.hasTraversal()) { + this.predicate.resolve(traverser); + // Vacuously true: if the predicate can't be evaluated (no comparison value), + // then no item can match, so none() is satisfied. + if (this.predicate.isResolvedEmpty()) return true; + } + final S item = traverser.get(); if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) { @@ -65,6 +77,14 @@ public String toString() { return StringFactory.stepString(this, this.predicate); } + @SuppressWarnings("unchecked") + @Override + public List> getLocalChildren() { + final List> traversals = new ArrayList<>(); + P.collectTraversals(this.predicate, traversals); + return (List) Collections.unmodifiableList(traversals); + } + @Override public NoneStep clone() { final NoneStep clone = (NoneStep) super.clone(); @@ -74,6 +94,12 @@ public NoneStep clone() { @Override public Set getRequirements() { - return EnumSet.of(TraverserRequirement.OBJECT); + return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT); + } + + @Override + public void setTraversal(final Traversal.Admin parentTraversal) { + super.setTraversal(parentTraversal); + P.integrateTraversals(this.predicate, this); } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java index 77c3f4abc98..6a2a3a57706 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java @@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating; import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor; import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; @@ -45,7 +46,7 @@ /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class WherePredicateStep extends FilterStep implements Scoping, PathProcessor, ByModulating, TraversalParent { +public final class WherePredicateStep extends FilterStep implements Scoping, PathProcessor, ByModulating, TraversalParent, AcceptsChildPredicateTraversal { protected String startKey; protected List selectKeys; @@ -54,6 +55,7 @@ public final class WherePredicateStep extends FilterStep implements Scopin protected Set keepLabels; protected TraversalRing traversalRing = new TraversalRing<>(); + private List> predicateTraversals; public WherePredicateStep(final Traversal.Admin traversal, final Optional startKey, final P predicate) { super(traversal); @@ -63,12 +65,19 @@ public WherePredicateStep(final Traversal.Admin traversal, final Optional(); this.configurePredicates(this.predicate); + // Cache and integrate child traversals from the predicate + this.predicateTraversals = new ArrayList<>(); + P.collectTraversals(this.predicate, this.predicateTraversals); + for (final Traversal.Admin t : this.predicateTraversals) { + this.integrateChild(t); + } } private void configurePredicates(final P predicate) { if (predicate instanceof ConnectiveP) ((ConnectiveP) predicate).getPredicates().forEach(this::configurePredicates); - else { + else if (!predicate.hasTraversal()) { + // Only configure scope keys for non-traversal predicates (string label references) final String selectKey = getSelectKey(predicate); this.selectKeys.add(selectKey); this.scopeKeys.add(selectKey); @@ -112,14 +121,28 @@ public void removeStartKey() { @Override protected boolean filter(final Traverser.Admin traverser) { + // Resolve the left-hand value (current traverser or startKey scope value) final TraversalProduct product = null == this.startKey ? TraversalUtil.produce(traverser, this.traversalRing.next()) : TraversalUtil.produce((S) this.getSafeScopeValue(Pop.last, this.startKey, traverser), this.traversalRing.next()); - final boolean predicateValuesProductive = this.setPredicateValues(this.predicate, traverser, this.selectKeys.iterator()); - this.traversalRing.reset(); + if (!product.isProductive()) { + this.traversalRing.reset(); + return false; + } - return product.isProductive() && predicateValuesProductive && this.predicate.test(product.get()); + if (this.predicate.hasTraversal()) { + // Traversal-bearing predicate: resolve the child traversal, then test + this.traversalRing.reset(); + this.predicate.resolve(traverser); + if (this.predicate.isResolvedEmpty()) return false; + return this.predicate.test(product.get()); + } else { + // Standard scope-label path: resolve predicate values from path labels + final boolean predicateValuesProductive = this.setPredicateValues(this.predicate, traverser, this.selectKeys.iterator()); + this.traversalRing.reset(); + return predicateValuesProductive && this.predicate.test(product.get()); + } } @Override @@ -166,7 +189,12 @@ public Set getRequirements() { @Override public List> getLocalChildren() { - return (List) this.traversalRing.getTraversals(); + if (this.predicateTraversals.isEmpty()) { + return (List) this.traversalRing.getTraversals(); + } + final List> children = new ArrayList<>((List) this.traversalRing.getTraversals()); + children.addAll((List) this.predicateTraversals); + return children; } @Override diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java index 7e64cd391a5..c000c7c1644 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java @@ -24,11 +24,14 @@ import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters; import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.T; @@ -37,10 +40,12 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.EmptyIterator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Objects; import java.util.function.Supplier; @@ -48,7 +53,7 @@ * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Pieter Martin */ -public class GraphStep extends AbstractStep implements GraphStepContract { +public class GraphStep extends AbstractStep implements GraphStepContract, TraversalParent, AcceptsChildPredicateTraversal { protected Parameters parameters = new Parameters(); protected final Class returnClass; @@ -58,6 +63,7 @@ public class GraphStep extends AbstractStep implemen protected boolean done = false; private Traverser.Admin head = null; private Iterator iterator = EmptyIterator.instance(); + private Traversal.Admin idTraversal; public GraphStep(final Traversal.Admin traversal, final Class returnClass, final boolean isStart, final Object... ids) { @@ -76,7 +82,36 @@ public GraphStep(final Traversal.Admin traversal, final Class returnClass, fi this.getTraversal().getGraph().get().edges(this.ids)); } + public GraphStep(final Traversal.Admin traversal, final Class returnClass, final boolean isStart, final Traversal.Admin idTraversal) { + this(traversal, returnClass, isStart); + this.idTraversal = idTraversal; + if (this.idTraversal != null) { + this.integrateChild(this.idTraversal); + } + } + + /** + * Returns the child traversal used to resolve element IDs, or {@code null} if literal IDs are used. + */ + public Traversal.Admin getIdTraversal() { + return this.idTraversal; + } + + /** + * Sets the child traversal used to resolve element IDs. Calls {@link #integrateChild(Traversal.Admin)} + * on the provided traversal. + */ + public void setIdTraversal(final Traversal.Admin idTraversal) { + this.idTraversal = idTraversal; + if (this.idTraversal != null) { + this.integrateChild(this.idTraversal); + } + } + public String toString() { + if (this.idTraversal != null) { + return StringFactory.stepString(this, this.returnClass.getSimpleName().toLowerCase(), this.idTraversal); + } return StringFactory.stepString(this, this.returnClass.getSimpleName().toLowerCase(), Arrays.toString(this.ids)); } @@ -164,16 +199,65 @@ protected Traverser.Admin processNextStart() { if (this.isStart) { if (this.done) throw FastNoSuchElementException.instance(); - else { + if (this.idTraversal != null) { + // Start step with idTraversal: generate a synthetic traverser to seed + // the child traversal, consistent with how mergeV/addV handle start steps. + this.done = true; + final Traverser.Admin syntheticTraverser = (Traverser.Admin) + this.getTraversal().getTraverserGenerator().generate(false, (Step) this, 1L); + final Object[] resolvedIds = resolveTraversalIds(syntheticTraverser); + this.iterator = lookupElements(resolvedIds); + } else { this.done = true; this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get(); } } else { this.head = this.starts.next(); - this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get(); + if (this.idTraversal != null) { + final Object[] resolvedIds = resolveTraversalIds(this.head); + this.iterator = lookupElements(resolvedIds); + } else { + this.iterator = null == this.iteratorSupplier ? EmptyIterator.instance() : this.iteratorSupplier.get(); + } + } + } + } + } + + /** + * Resolves element IDs by evaluating the child traversal against the current traverser. + * Handles Element (extract ID), Collection (unpack), and raw values. + */ + @SuppressWarnings("unchecked") + private Object[] resolveTraversalIds(final Traverser.Admin traverser) { + final List ids = new ArrayList<>(); + TraversalUtil.prepare(traverser, (Traversal.Admin) this.idTraversal); + while (this.idTraversal.hasNext()) { + final Object result = this.idTraversal.next(); + if (result instanceof Element) { + ids.add(((Element) result).id()); + } else if (result instanceof Collection) { + for (final Object item : (Collection) result) { + ids.add(item instanceof Element ? ((Element) item).id() : item); } + } else { + ids.add(result); } } + return ids.toArray(); + } + + /** + * Looks up elements (vertices or edges) by the given IDs using the graph. + */ + @SuppressWarnings("unchecked") + private Iterator lookupElements(final Object[] elementIds) { + if (elementIds.length == 0) { + return EmptyIterator.instance(); + } + return (Iterator) (Vertex.class.isAssignableFrom(this.returnClass) ? + this.getTraversal().getGraph().get().vertices(elementIds) : + this.getTraversal().getGraph().get().edges(elementIds)); } @Override @@ -182,6 +266,9 @@ public void reset() { this.head = null; this.done = false; this.iterator = EmptyIterator.instance(); + if (this.idTraversal != null) { + this.idTraversal.reset(); + } } @Override @@ -195,6 +282,31 @@ public int hashCode() { return result; } + @SuppressWarnings("unchecked") + @Override + public List> getLocalChildren() { + return this.idTraversal != null + ? Collections.singletonList((Traversal.Admin) this.idTraversal) + : Collections.emptyList(); + } + + @Override + public GraphStep clone() { + final GraphStep clone = (GraphStep) super.clone(); + if (this.idTraversal != null) { + clone.idTraversal = this.idTraversal.clone(); + } + return clone; + } + + @Override + public void setTraversal(final Traversal.Admin parentTraversal) { + super.setTraversal(parentTraversal); + if (this.idTraversal != null) { + this.integrateChild(this.idTraversal); + } + } + /** * Attempts to close an underlying iterator if it is of type {@link CloseableIterator}. Graph providers may choose * to return this interface containing their vertices and edges if there are expensive resources that might need to @@ -203,6 +315,11 @@ public int hashCode() { @Override public void close() { CloseableIterator.closeIterator(iterator); + try { + TraversalParent.super.close(); + } catch (final Exception e) { + throw new RuntimeException(e); + } } /** @@ -213,6 +330,7 @@ public void close() { * @return true if the {@link HasContainer} updated ids and thus, was processed. */ public static boolean processHasContainerIds(final GraphStep graphStep, final HasContainer hasContainer) { + if (hasContainer.hasTraversal()) return false; final String key = hasContainer.getKey(); if (key != null && key.equals(T.id.getAccessor()) && graphStep.ids.length == 0 && (hasContainer.getBiPredicate() == Compare.eq || hasContainer.getBiPredicate() == Contains.within)) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java index 4223f98bd5c..0901a671962 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java @@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.*; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Property; @@ -35,6 +36,7 @@ import org.apache.tinkerpop.gremlin.structure.util.keyed.KeyedProperty; import org.apache.tinkerpop.gremlin.structure.util.keyed.KeyedVertexProperty; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -50,12 +52,22 @@ public class AddPropertyStep extends SideEffectStep implem private Parameters internalParameters = new Parameters(); private Parameters withConfiguration = new Parameters(); private final VertexProperty.Cardinality cardinality; + /** + * Marks the single-argument {@code property(traversal)} form whose child traversal must produce a Map of + * property key/value pairs. Dispatch is driven by this flag rather than by inspecting the property key. + */ + private final boolean mapForm; private CallbackRegistry callbackRegistry; public AddPropertyStep(final Traversal.Admin traversal, final VertexProperty.Cardinality cardinality, final Object keyObject, final Object valueObject) { + this(traversal, cardinality, keyObject, valueObject, false); + } + + public AddPropertyStep(final Traversal.Admin traversal, final VertexProperty.Cardinality cardinality, final Object keyObject, final Object valueObject, final boolean mapForm) { super(traversal); this.internalParameters.set(this, T.key, keyObject, T.value, valueObject); this.cardinality = cardinality; + this.mapForm = mapForm; } @Override @@ -89,11 +101,109 @@ protected void sideEffect(final Traverser.Admin traverser) { throw new IllegalStateException(String.format("T.%s is immutable on existing elements", ((T) k).name())); final String key = (String) k; - final Object value = this.internalParameters.get(traverser, T.value, () -> { - throw new IllegalStateException("The AddPropertyStep does not have a provided value: " + this); - }).get(0); + + // Check if the raw value is a traversal to enable multi-result handling. + // Exclude ConstantTraversal which is used internally by TinkerPop to wrap literal values. + final List rawValues = this.internalParameters.get(T.value, null); + final boolean valueIsTraversal = !rawValues.isEmpty() + && rawValues.get(0) instanceof Traversal.Admin + && !(rawValues.get(0) instanceof ConstantTraversal); + + if (valueIsTraversal) { + handleTraversalValue(traverser, key); + } else { + final Object value = this.internalParameters.get(traverser, T.value, () -> { + throw new IllegalStateException("The AddPropertyStep does not have a provided value: " + this); + }).get(0); + final Object[] vertexPropertyKeyValues = this.internalParameters.getKeyValues(traverser, T.key, T.value); + applyPropertyMutation(traverser, key, value, vertexPropertyKeyValues); + } + } + + /** + * Handles the case where the value argument is a child traversal, supporting multi-result + * resolution, Map-producing traversals, and cardinality-aware property setting. + */ + private void handleTraversalValue(final Traverser.Admin traverser, final String key) { + final List rawValues = this.internalParameters.get(T.value, null); + final Traversal.Admin valueTraversal = (Traversal.Admin) rawValues.get(0); + + // Collect all results from the child traversal + final List results = new ArrayList<>(); + final Traverser.Admin trav = traverser; + final Iterator itty = TraversalUtil.applyAll(trav, (Traversal.Admin) (Traversal.Admin) valueTraversal); + while (itty.hasNext()) { + results.add(itty.next()); + } + + // No-result case: skip mutation, pass element through unchanged + if (results.isEmpty()) { + return; + } + + final Element element = traverser.get(); final Object[] vertexPropertyKeyValues = this.internalParameters.getKeyValues(traverser, T.key, T.value); + // Map-producing form: single-argument property(traversal) where the traversal produces a Map. + // Only the dedicated map form expands a Map into per-entry properties; for the key+traversal form a + // Map result is treated as an ordinary property value. + if (this.mapForm) { + if (results.size() == 1 && results.get(0) instanceof Map) { + final Map map = (Map) results.get(0); + for (final Map.Entry entry : map.entrySet()) { + if (!(entry.getKey() instanceof String)) { + throw new IllegalArgumentException( + "Property key must be a String but found " + entry.getKey().getClass().getSimpleName()); + } + final String mapKey = (String) entry.getKey(); + applyPropertyMutation(traverser, mapKey, entry.getValue(), vertexPropertyKeyValues); + } + return; + } + + // The map form requires a Map result. Reject anything else rather than guessing. + final Object result = results.get(0); + throw new IllegalArgumentException( + "property(traversal) requires the traversal to produce a Map, but got: " + + (result == null ? "null" : result.getClass().getSimpleName())); + } + + // Multi-result handling with cardinality awareness + if (results.size() > 1) { + // Determine effective cardinality + final VertexProperty.Cardinality effectiveCard = this.cardinality != null + ? this.cardinality + : (element instanceof Vertex ? element.graph().features().vertex().getCardinality(key) : null); + + if (effectiveCard == VertexProperty.Cardinality.single) { + throw new IllegalArgumentException( + "Single-cardinality property requires exactly one value, but traversal produced " + + results.size() + " results"); + } + + // For list/set cardinality with multiple results, add each as a separate property value + if (effectiveCard == VertexProperty.Cardinality.list || effectiveCard == VertexProperty.Cardinality.set) { + if (!(element instanceof Vertex)) { + throw new IllegalStateException(String.format( + "Property cardinality can only be set for a Vertex but the traversal encountered %s for key: %s", + element.getClass().getSimpleName(), key)); + } + for (final Object v : results) { + applyPropertyMutation(traverser, key, v, vertexPropertyKeyValues); + } + return; + } + } + + // Single result or default cardinality: use the first result + applyPropertyMutation(traverser, key, results.get(0), vertexPropertyKeyValues); + } + + /** + * Applies a single property mutation to the element, handling eventing and cardinality. + */ + private void applyPropertyMutation(final Traverser.Admin traverser, final String key, + final Object value, final Object[] vertexPropertyKeyValues) { final Element element = traverser.get(); // can't set cardinality if the element is something other than a vertex as only vertices can have @@ -116,7 +226,7 @@ protected void sideEffect(final Traverser.Admin traverser) { final VertexProperty.Cardinality card = this.cardinality != null ? this.cardinality - : element.graph().features().vertex().getCardinality(key); + : (element instanceof Vertex ? element.graph().features().vertex().getCardinality(key) : null); // update property if (element instanceof Vertex) { @@ -183,7 +293,7 @@ public CallbackRegistry getMutatingCallbackRe @Override public int hashCode() { - final int hash = super.hashCode() ^ this.internalParameters.hashCode() ^ this.withConfiguration.hashCode(); + int hash = super.hashCode() ^ this.internalParameters.hashCode() ^ this.withConfiguration.hashCode() ^ Boolean.hashCode(this.mapForm); return (null != this.cardinality) ? (hash ^ cardinality.hashCode()) : hash; } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepContract.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepContract.java index c6547ad425d..70f430db4a8 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepContract.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepContract.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect; import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring; import org.apache.tinkerpop.gremlin.process.traversal.step.Deleting; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; @@ -33,7 +34,8 @@ import java.util.List; public interface AddPropertyStepContract extends Step, TraversalParent, Scoping, PropertiesHolder, - Writing, Deleting, Configuring { + Writing, Deleting, Configuring, + AcceptsChildPredicateTraversal { /** * Concrete implementations of this contract that can be referenced as TinkerPop implementations. diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepPlaceholder.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepPlaceholder.java index 3bb1c087cfc..3dd2734cf32 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepPlaceholder.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStepPlaceholder.java @@ -62,8 +62,18 @@ public class AddPropertyStepPlaceholder extends SideEffectSte private Parameters withConfiguration = new Parameters(); + /** + * Marks the single-argument {@code property(traversal)} (Map-producing) form. + */ + private boolean mapForm; + public AddPropertyStepPlaceholder(final Traversal.Admin traversal, final VertexProperty.Cardinality cardinality, final Object keyObject, final Object valueObject) { + this(traversal, cardinality, keyObject, valueObject, false); + } + + public AddPropertyStepPlaceholder(final Traversal.Admin traversal, final VertexProperty.Cardinality cardinality, final Object keyObject, final Object valueObject, final boolean mapForm) { super(traversal); + this.mapForm = mapForm; if (keyObject instanceof GValue) { throw new IllegalArgumentException("GValue is not allowed for property keys"); } @@ -128,13 +138,14 @@ public boolean equals(Object o) { return Objects.equals(key, that.key) && Objects.equals(value, that.value) && cardinality == that.cardinality && + mapForm == that.mapForm && Objects.equals(properties, that.properties) && Objects.equals(withConfiguration, that.withConfiguration); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), key, value, cardinality, properties, withConfiguration); + return Objects.hash(super.hashCode(), key, value, cardinality, mapForm, properties, withConfiguration); } @Override @@ -176,6 +187,7 @@ public Object getValueWithGValue() { public AddPropertyStepPlaceholder clone() { final AddPropertyStepPlaceholder clone = (AddPropertyStepPlaceholder) super.clone(); clone.cardinality = cardinality; + clone.mapForm = mapForm; // Attempt to deep clone key for Traversal and GValue. Shallow copy is fine if key is a String or enum if (this.key instanceof Traversal) { @@ -218,7 +230,7 @@ public AddPropertyStepPlaceholder clone() { @Override public AddPropertyStep asConcreteStep() { - AddPropertyStep step = new AddPropertyStep<>(traversal, cardinality, key, value instanceof GValue ? ((GValue) value).get() : value); + AddPropertyStep step = new AddPropertyStep<>(traversal, cardinality, key, value instanceof GValue ? ((GValue) value).get() : value, mapForm); for (final Map.Entry> entry : properties.entrySet()) { for (Object value : entry.getValue()) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java index 99a9c4e959d..82204d49f29 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java @@ -119,7 +119,7 @@ public HasContainer clone() { @Override public int hashCode() { - return (this.key != null ? this.key.hashCode() : 0) ^ (this.predicate != null ? this.predicate.hashCode() : 0); + return (this.key != null ? this.key.hashCode() : 0) ^ this.predicate.hashCode(); } public final String getKey() { @@ -142,6 +142,14 @@ public final Object getValue() { return this.predicate.getValue(); } + /** + * Determines if this {@code HasContainer}'s predicate holds a child traversal whose result is resolved + * at runtime (e.g. {@code P.eq(traversal)} or {@code P.within(traversal)}). + */ + public boolean hasTraversal() { + return this.predicate.hasTraversal(); + } + //////////// /** diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java index 8a6edcde280..d8c260d87fd 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java @@ -114,6 +114,10 @@ step instanceof OrStep && processOrStep((OrStep) step, traversal) || /////////////////////////// private static boolean processHasStep(final HasStep step, final Traversal.Admin traversal) { + if (step.getHasContainers().stream().anyMatch(HasContainer::hasTraversal)) return false; + if (step.getPreviousStep() instanceof HasStep) { + if (((HasStep) step.getPreviousStep()).getHasContainers().stream().anyMatch(HasContainer::hasTraversal)) return false; + } if (step.getPreviousStep() instanceof HasStep) { final HasStep previousStep = (HasStep) step.getPreviousStep(); final List hasContainers = new ArrayList<>(step.getHasContainers()); @@ -221,6 +225,11 @@ private static boolean processOrStep(final OrStep step, final Traversal.Admin InlineFilterStrategy.instance().apply(childTraversal); for (final Step childStep : childTraversal.getSteps()) { if (childStep instanceof HasStep) { + // Skip optimization if any HasContainer has a traversal-bearing predicate + if (((HasStep) childStep).getHasContainers().stream().anyMatch(HasContainer::hasTraversal)) { + process = false; + break; + } P p = null; for (final HasContainer hasContainer : ((HasStep) childStep).getHasContainers()) { if (null == key) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java new file mode 100644 index 00000000000..240cc08a859 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategy.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification; + +import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.step.AcceptsChildPredicateTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.util.ChildTraversalValidator; + +/** + * Validates that child traversals in filter, lookup, and mutation steps do not contain mutating steps. + * Serves as a safety net for programmatic traversal construction that bypasses the DSL's + * construction-time validation. + */ +public final class ChildTraversalVerificationStrategy + extends AbstractTraversalStrategy + implements TraversalStrategy.VerificationStrategy { + + private static final ChildTraversalVerificationStrategy INSTANCE = new ChildTraversalVerificationStrategy(); + + private ChildTraversalVerificationStrategy() { + } + + @Override + public void apply(final Traversal.Admin traversal) { + for (final Step step : traversal.getSteps()) { + if (step instanceof AcceptsChildPredicateTraversal && step instanceof TraversalParent) { + for (final Traversal.Admin child : ((TraversalParent) step).getLocalChildren()) { + try { + ChildTraversalValidator.validate(child); + } catch (final IllegalArgumentException e) { + throw new VerificationException(e.getMessage(), traversal); + } + } + } + } + } + + public static ChildTraversalVerificationStrategy instance() { + return INSTANCE; + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java index db5cced9ecf..1275e08f04c 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java @@ -20,6 +20,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.PBiPredicate; +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import java.io.Serializable; @@ -56,6 +57,34 @@ public P negate() { return new OrP<>(this.predicates); } + /** + * Resolves child predicates with short-circuiting. Because a conjunction fails as soon as any child + * predicate cannot be satisfied, resolution stops at the first child that resolves empty (i.e. a scalar + * predicate whose child traversal produced no comparison value). This avoids evaluating the remaining + * child traversals, which may be expensive. Collection predicates (within/without) never resolve empty + * (they resolve to an empty collection), so they do not trigger the short-circuit. + */ + @Override + public void resolve(final Traverser.Admin traverser) { + // No super.resolve(): a connective predicate carries no child traversal of its own; only its + // operands do. Resolving each operand directly is sufficient (and enables the short-circuit below). + for (final P p : this.predicates) { + if (p.hasTraversal()) { + p.resolve(traverser); + if (p.isResolvedEmpty()) return; + } + } + } + + @Override + public boolean isResolvedEmpty() { + // AND short-circuits: if any child resolved empty, the conjunction cannot be satisfied + for (final P p : this.predicates) { + if (p.hasTraversal() && p.isResolvedEmpty()) return true; + } + return false; + } + @Override public String toString() { return "and(" + StringFactory.removeEndBrackets(this.predicates) + ")"; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java new file mode 100644 index 00000000000..5e54d6d5991 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidator.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.util; + +import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; + +/** + * Validates that child traversals do not contain mutating steps. Child traversals used as + * arguments to filter predicates ({@code has()}, {@code is()}, etc.), lookup steps + * ({@code V(traversal)}, {@code E(traversal)}), and mutation steps ({@code property(traversal)}) + * must be read-only - their purpose is to compute values, not produce side effects. + *

+ * Recursion walks both {@link TraversalParent#getLocalChildren()} and + * {@link TraversalParent#getGlobalChildren()} to detect mutations nested inside + * {@code map()}, {@code union()}, {@code choose()}, {@code coalesce()}, or any other parent step. + */ +public final class ChildTraversalValidator { + + private ChildTraversalValidator() { + } + + /** + * Validates that a child traversal contains no {@link Mutating} steps at any nesting depth. + * Throws {@link IllegalArgumentException} if one is found. + */ + public static void validate(final Traversal.Admin child) { + for (final Step step : child.getSteps()) { + if (step instanceof Mutating) { + throw new IllegalArgumentException( + "Child traversal contains mutating step " + + step.getClass().getSimpleName() + ". Mutating steps are not allowed in child traversals."); + } + if (step instanceof TraversalParent) { + for (final Traversal.Admin nested : ((TraversalParent) step).getLocalChildren()) { + validate(nested); + } + for (final Traversal.Admin nested : ((TraversalParent) step).getGlobalChildren()) { + validate(nested); + } + } + } + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java index ef5a1142c31..fa277d2806c 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.util; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; import java.util.ArrayList; @@ -134,4 +135,21 @@ public Set> getGValues() { } return allGValues; } + + @Override + public boolean hasTraversal() { + if (super.hasTraversal()) return true; + for (final P p : this.predicates) { + if (p.hasTraversal()) return true; + } + return false; + } + + @Override + public void resolve(final Traverser.Admin traverser) { + super.resolve(traverser); + for (final P p : this.predicates) { + p.resolve(traverser); + } + } } \ No newline at end of file diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java index 2a0c27c7af2..0a054033e99 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java @@ -57,6 +57,19 @@ public P negate() { return new AndP<>(this.predicates); } + @Override + public boolean isResolvedEmpty() { + // OR short-circuits: only empty if ALL traversal-bearing children resolved empty + boolean anyTraversal = false; + for (final P p : this.predicates) { + if (p.hasTraversal()) { + anyTraversal = true; + if (!p.isResolvedEmpty()) return false; + } + } + return anyTraversal; + } + @Override public String toString() { return "or(" + StringFactory.removeEndBrackets(this.predicates) + ")"; diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java index e26a621ba00..cd16ef308c4 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java @@ -96,7 +96,7 @@ public void shouldParseVariableWithNoOp() { VariableResolver.NullVariableResolver.instance()); final GraphTraversal t = (GraphTraversal) GremlinQueryParser.parse("g.V().has('name',gt(z))", gremlinAntlrToJava); - assertEquals(g.V().has("name", P.gt(null)).asAdmin().getGremlinLang(), + assertEquals(g.V().has("name", P.gt((Object) null)).asAdmin().getGremlinLang(), t.asAdmin().getGremlinLang()); } @@ -107,7 +107,7 @@ public void shouldParseMultiVariablesWithNoOp() { VariableResolver.NullVariableResolver.instance()); final GraphTraversal t = (GraphTraversal) GremlinQueryParser.parse("g.V(a,b,c).has('name',gt(z))", gremlinAntlrToJava); - assertEquals(g.V(null, null, null).has("name", P.gt(null)).asAdmin().getGremlinLang(), + assertEquals(g.V(null, null, null).has("name", P.gt((Object) null)).asAdmin().getGremlinLang(), t.asAdmin().getGremlinLang()); } diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTraversalTest.java new file mode 100644 index 00000000000..12e0ab78ec1 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTraversalTest.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.language.grammar; + +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.T; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; +import org.junit.Before; +import org.junit.Test; + +import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; +import static org.junit.Assert.assertEquals; + +/** + * Tests that the Gremlin grammar correctly parses the new traversal-accepting syntax forms + * for has(), V(), E(), property(), and predicates. + */ +public class GremlinQueryParserTraversalTest { + + private GraphTraversalSource g; + private GremlinAntlrToJava antlrToLanguage; + + @Before + public void setup() { + g = traversal().withEmbedded(EmptyGraph.instance()); + antlrToLanguage = new GremlinAntlrToJava(); + } + + private Object eval(final String query) { + final GremlinLexer lexer = new GremlinLexer(CharStreams.fromString(query)); + final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer)); + return antlrToLanguage.visit(parser.queryList()); + } + + private void compare(final Object expected, final Object actual) { + assertEquals(((DefaultGraphTraversal) expected).asAdmin().getGremlinLang(), + ((DefaultGraphTraversal) actual).asAdmin().getGremlinLang()); + } + + // ---- has(key, traversal) ---- + + @Test + public void shouldParseHasStringTraversal() { + compare(g.V().has("name", __.values("x")), + eval("g.V().has('name', __.values('x'))")); + } + + // ---- has(label, key, traversal) ---- + + @Test + public void shouldParseHasStringStringTraversal() { + compare(g.V().has("person", "name", __.values("x")), + eval("g.V().has('person', 'name', __.values('x'))")); + } + + // ---- has(T, traversal) ---- + + @Test + public void shouldParseHasTTraversal() { + compare(g.V().has(T.id, __.values("x")), + eval("g.V().has(T.id, __.values('x'))")); + } + + // ---- V(traversal) mid-traversal ---- + + @Test + public void shouldParseVTraversalMidTraversal() { + compare(g.V().out().V(__.select("ids")), + eval("g.V().out().V(__.select('ids'))")); + } + + // ---- E(traversal) mid-traversal ---- + + @Test + public void shouldParseETraversalMidTraversal() { + compare(g.V().out().E(__.select("ids")), + eval("g.V().out().E(__.select('ids'))")); + } + + // ---- property(key, traversal) ---- + + @Test + public void shouldParsePropertyKeyTraversal() { + compare(g.V().property("key", __.select("val")), + eval("g.V().property('key', __.select('val'))")); + } + + // ---- property(Cardinality, key, traversal) ---- + + @Test + public void shouldParsePropertyCardinalityKeyTraversal() { + compare(g.V().property(VertexProperty.Cardinality.single, "key", __.select("val")), + eval("g.V().property(Cardinality.single, 'key', __.select('val'))")); + } + + // ---- P.eq(traversal) via has ---- + + @Test + public void shouldParseHasWithPEqTraversal() { + compare(g.V().has("name", P.eq(__.values("x"))), + eval("g.V().has('name', P.eq(__.values('x')))")); + } + + // ---- P.gt(traversal) via has ---- + + @Test + public void shouldParseHasWithPGtTraversal() { + compare(g.V().has("age", P.gt(__.values("x"))), + eval("g.V().has('age', P.gt(__.values('x')))")); + } + + // ---- P.within(traversal) via has ---- + + @Test + public void shouldParseHasWithPWithinTraversal() { + compare(g.V().has("name", P.within(__.values("x"))), + eval("g.V().has('name', P.within(__.values('x')))")); + } + + // ---- property(traversal) - Map-producing form ---- + + @Test + public void shouldParsePropertyTraversal() { + compare(g.V().property(__.V().project("a").by("name")), + eval("g.V().property(__.V().project('a').by('name'))")); + } +} diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLangTraversalRoundTripTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLangTraversalRoundTripTest.java new file mode 100644 index 00000000000..ff1cc9a6a73 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLangTraversalRoundTripTest.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.language.grammar.GremlinAntlrToJava; +import org.apache.tinkerpop.gremlin.language.grammar.GremlinQueryParser; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; +import org.junit.Test; + +import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; +import static org.junit.Assert.assertEquals; + +/** + * Tests that GremlinLang serialization round-trips preserve traversal arguments. + * For any step containing a child traversal argument, serializing to GremlinLang and parsing back + * produces a structurally equivalent traversal. + */ +public class GremlinLangTraversalRoundTripTest { + + private static final GraphTraversalSource g = traversal().with(EmptyGraph.instance()); + + /** + * Serializes a traversal to GremlinLang, parses it back, and verifies structural equivalence + * by comparing the GremlinLang output of both the original and the round-tripped traversal. + */ + private void assertRoundTrip(final Traversal traversal) { + final String originalGremlin = traversal.asAdmin().getGremlinLang().getGremlin(); + + // Parse the GremlinLang string back into a traversal + final GremlinAntlrToJava antlr = new GremlinAntlrToJava(); + final Object parsed = GremlinQueryParser.parse(originalGremlin, antlr); + + // Get the GremlinLang of the parsed traversal + final String roundTrippedGremlin = ((Traversal) parsed).asAdmin().getGremlinLang().getGremlin(); + + assertEquals("GremlinLang round-trip should preserve traversal structure for: " + originalGremlin, + originalGremlin, roundTrippedGremlin); + } + + @Test + public void shouldRoundTripHasWithTraversalValue() { + // g.V().has("name", __.values("x")) + assertRoundTrip(g.V().has("name", __.values("x"))); + } + + @Test + public void shouldRoundTripHasWithPredicateTraversal() { + // g.V().has("name", P.eq(__.values("x"))) + assertRoundTrip(g.V().has("name", P.eq(__.values("x").asAdmin()))); + } + + @Test + public void shouldRoundTripVWithTraversal() { + // g.V().V(__.select("ids")) + assertRoundTrip(g.V().V(__.select("ids"))); + } + + @Test + public void shouldRoundTripPropertyWithTraversal() { + // g.V().property("key", __.select("val")) + assertRoundTrip(g.V().property("key", __.select("val"))); + } + + @Test + public void shouldRoundTripHasWithConstantTraversal() { + // g.V().has("name", __.constant("marko")) + assertRoundTrip(g.V().has("name", __.constant("marko"))); + } + + @Test + public void shouldRoundTripLiteralHasUnchanged() { + // Backward compatibility: literal has() should still round-trip correctly + assertRoundTrip(g.V().has("name", "marko")); + } + + @Test + public void shouldRoundTripLiteralPredicateUnchanged() { + // Backward compatibility: literal P.eq() should still round-trip correctly + assertRoundTrip(g.V().has("name", P.eq("marko"))); + } + + @Test + public void shouldRoundTripHasWithPGtTraversal() { + // g.V().has("age", P.gt(__.constant(30))) + assertRoundTrip(g.V().has("age", P.gt(__.constant(30).asAdmin()))); + } + + @Test + public void shouldRoundTripEWithTraversal() { + // g.V().E(__.select("edgeIds")) + assertRoundTrip(g.V().E(__.select("edgeIds"))); + } + + @Test + public void shouldRoundTripPropertyWithMapTraversal() { + // g.V().property(__.V().project("a").by("name")) - the Map-producing form + assertRoundTrip(g.V().property(__.V().project("a").by("name"))); + } +} diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java index 4a8959a1ee1..80f65c59db4 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java @@ -65,8 +65,8 @@ public static Iterable data() { {P.eq(-0), +0, true}, {P.eq(0), 1, false}, {P.eq(0), null, false}, - {P.eq(null), null, true}, - {P.eq(null), 0, false}, + {P.eq((Object) null), null, true}, + {P.eq((Object) null), 0, false}, {P.eq(Double.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, false}, {P.eq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY, false}, {P.eq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, false}, @@ -82,8 +82,8 @@ public static Iterable data() { {P.neq(-0), +0, false}, {P.neq(0), 1, true}, {P.neq(0), null, true}, - {P.neq(null), null, false}, - {P.neq(null), 0, true}, + {P.neq((Object) null), null, false}, + {P.neq((Object) null), 0, true}, {P.neq(Double.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, true}, {P.neq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY, true}, {P.neq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, true}, @@ -468,7 +468,7 @@ public void shouldHandleNullValuesForSetValue() { assertTrue(predicate.test(null)); assertFalse(predicate.test(INITIAL_VALUE)); assertEquals("eq", predicate.toString()); - assertEquals(predicate, P.eq(null)); + assertEquals(predicate, P.eq((Object) null)); assertNotEquals(predicate, P.eq(INITIAL_VALUE)); } diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java new file mode 100644 index 00000000000..86c82c2b22a --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTraversalTest.java @@ -0,0 +1,529 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.GValue; +import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_Traverser; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Tests for traversal-aware behavior in {@link P}, covering traversal detection accuracy + * and single-value predicate rejection of multiple traversal results. + */ +@RunWith(Enclosed.class) +public class PTraversalTest { + + /** + * Tests that traversal detection in predicates is accurate: {@code P.hasTraversal()} returns + * true for traversal-bearing predicates and false for literal/GValue predicates. + */ + public static class TraversalDetectionTest { + + @Test + public void shouldDetectTraversalInComparisonPredicate() { + final P p = P.eq(__.identity().asAdmin()); + assertThat(p.hasTraversal(), is(true)); + } + + @Test + public void shouldDetectTraversalInCollectionPredicate() { + final P p = P.within(__.inject(1, 2, 3).asAdmin()); + assertThat(p.hasTraversal(), is(true)); + } + + @Test + public void shouldNotDetectTraversalInLiteralPredicate() { + final P p = P.eq("value"); + assertThat(p.hasTraversal(), is(false)); + } + + @Test + public void shouldNotDetectTraversalInGValuePredicate() { + final P p = P.eq(GValue.of("x", "value")); + assertThat(p.hasTraversal(), is(false)); + } + + @Test + public void shouldReturnTraversalValueWhenPresent() { + final Traversal.Admin traversal = __.inject(42).asAdmin(); + final P p = P.eq(traversal); + assertThat(p.getTraversalValue(), is(sameInstance(traversal))); + } + + @Test + public void shouldReturnNullTraversalValueForLiteral() { + final P p = P.eq("value"); + assertThat(p.getTraversalValue(), is(nullValue())); + } + } + + /** + * Tests first-result semantics: single-value predicates (eq, neq, gt, lt, gte, lte) take the + * first result from a multi-result traversal. Collection predicates (within, without) accept + * all results as the collection value. + */ + public static class SingleValuePredicateRejectionTest { + + private Traverser.Admin createTraverser(final Object value) { + return new B_O_Traverser<>(value, 1L); + } + + // --- Single-value predicates take first result, ignore extras (consistent with by()) --- + + @SuppressWarnings("unchecked") + @Test + public void shouldTakeFirstResultForEq() { + final P p = P.eq(__.union(__.constant(1), __.constant(2)).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(1), is(true)); + assertThat(p.test(2), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldTakeFirstResultForNeq() { + final P p = P.neq(__.union(__.constant(1), __.constant(2)).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(1), is(false)); + assertThat(p.test(2), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldTakeFirstResultForGt() { + final P p = P.gt(__.union(__.constant(10), __.constant(20)).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(11), is(true)); + assertThat(p.test(10), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldTakeFirstResultForLt() { + final P p = P.lt(__.union(__.constant(10), __.constant(20)).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(9), is(true)); + assertThat(p.test(10), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldTakeFirstResultForGte() { + final P p = P.gte(__.union(__.constant(10), __.constant(20)).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(10), is(true)); + assertThat(p.test(9), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldTakeFirstResultForLte() { + final P p = P.lte(__.union(__.constant(10), __.constant(20)).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(10), is(true)); + assertThat(p.test(11), is(false)); + } + + // --- Collection predicates should accept multiple results --- + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptMultipleResultsForWithin() { + // within(traversal) takes first result only. Use fold() to get a collection. + final P p = P.within(__.inject(1, 2, 3).fold().asAdmin()); + p.resolve(createTraverser("start")); + // After resolve, the predicate should have the collection value and be testable + assertThat(p.test(1), is(true)); + assertThat(p.test(2), is(true)); + assertThat(p.test(3), is(true)); + assertThat(p.test(4), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptMultipleResultsForWithout() { + // without(traversal) takes first result only. Use fold() to get a collection. + final P p = P.without(__.inject(1, 2, 3).fold().asAdmin()); + p.resolve(createTraverser("start")); + // After resolve, without should exclude the resolved values + assertThat(p.test(1), is(false)); + assertThat(p.test(2), is(false)); + assertThat(p.test(3), is(false)); + assertThat(p.test(4), is(true)); + } + + // --- Single-value predicates should succeed with exactly one result --- + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptSingleResultForEq() { + final P p = P.eq(__.constant(42).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(42), is(true)); + assertThat(p.test(99), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptSingleResultForNeq() { + final P p = P.neq(__.constant(42).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(42), is(false)); + assertThat(p.test(99), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptSingleResultForGt() { + final P p = P.gt(__.constant(10).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(11), is(true)); + assertThat(p.test(10), is(false)); + assertThat(p.test(9), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptSingleResultForLt() { + final P p = P.lt(__.constant(10).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(9), is(true)); + assertThat(p.test(10), is(false)); + assertThat(p.test(11), is(false)); + } + + // --- Collection predicates should also work with single result --- + + @SuppressWarnings("unchecked") + @Test + public void shouldAcceptSingleResultForWithin() { + final P p = P.within(__.constant(42).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(42), is(true)); + assertThat(p.test(99), is(false)); + } + } + + /** + * Tests for multi-traversal support in within() and without(). + *

+ * When multiple traversals are passed to within(trav1, trav2, ...), each traversal is evaluated + * independently and results are unioned into a single collection for the Contains test. + */ + public static class MultiTraversalTest { + + private Traverser.Admin createTraverser(final Object value) { + return new B_O_Traverser<>(value, 1L); + } + + // --- Detection --- + + @Test + public void shouldDetectMultipleTraversalsInWithin() { + final P p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + assertThat(p.hasTraversal(), is(true)); + } + + @Test + public void shouldDetectMultipleTraversalsInWithout() { + final P p = P.without(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + assertThat(p.hasTraversal(), is(true)); + } + + @Test + public void shouldReturnTraversalValuesListForMultiTraversal() { + final P p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + assertThat(p.getTraversalValues(), is(notNullValue())); + assertThat(p.getTraversalValues().size(), is(2)); + } + + @Test + public void shouldReturnNullTraversalValueForMultiTraversal() { + // Single traversalValue should be null when using multi-traversal form + final P p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + assertThat(p.getTraversalValue(), is(nullValue())); + } + + // --- Resolution and testing --- + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveMultipleTraversalsForWithin() { + // within(__.constant(1), __.constant(2)) should union results: [1, 2] + final P p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(1), is(true)); + assertThat(p.test(2), is(true)); + assertThat(p.test(3), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveMultipleTraversalsForWithout() { + // without(__.constant(1), __.constant(2)) should union results: [1, 2] + final P p = P.without(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(1), is(false)); + assertThat(p.test(2), is(false)); + assertThat(p.test(3), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveMultipleTraversalsWithMultipleResultsEach() { + // within(__.inject(1,2).fold(), __.inject(3,4).fold()) - each fold() produces a list, unpacked into union + final P p = P.within(__.inject(1, 2).fold().asAdmin(), __.inject(3, 4).fold().asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test(1), is(true)); + assertThat(p.test(2), is(true)); + assertThat(p.test(3), is(true)); + assertThat(p.test(4), is(true)); + assertThat(p.test(5), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldHandleEmptyResultFromOneTraversal() { + // within(__.inject(1,2).fold(), __.limit(0)) where second produces nothing + // Should still match on results from first traversal + final P p = P.within(__.inject(1, 2).fold().asAdmin(), __.limit(0).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.isResolvedEmpty(), is(false)); + assertThat(p.test(1), is(true)); + assertThat(p.test(2), is(true)); + assertThat(p.test(3), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldHandleAllEmptyResults() { + // within(__.limit(0), __.limit(0)) where both produce nothing. A collection predicate resolves to + // an empty set rather than flagging resolved-empty, so within() simply matches nothing. + final P p = P.within(__.limit(0).asAdmin(), __.limit(0).asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.isResolvedEmpty(), is(false)); + assertThat(p.test(1), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveThreeTraversals() { + // within(__.constant("a"), __.constant("b"), __.constant("c")) + final P p = P.within(__.constant("a").asAdmin(), __.constant("b").asAdmin(), __.constant("c").asAdmin()); + p.resolve(createTraverser("start")); + assertThat(p.test("a"), is(true)); + assertThat(p.test("b"), is(true)); + assertThat(p.test("c"), is(true)); + assertThat(p.test("d"), is(false)); + } + + // --- Clone independence --- + + @SuppressWarnings("unchecked") + @Test + public void shouldCloneMultiTraversalPredicate() { + final P original = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin()); + final P clone = original.clone(); + + // Clone should have independent traversal values + assertThat(clone.hasTraversal(), is(true)); + assertThat(clone.getTraversalValues(), is(notNullValue())); + assertThat(clone.getTraversalValues().size(), is(2)); + + // Resolve the clone - this mutates the clone's internal state + clone.resolve(createTraverser("start")); + assertThat(clone.test(1), is(true)); + + // Original should be unaffected: resolving it independently should still work correctly + original.resolve(createTraverser("other")); + assertThat(original.test(1), is(true)); + assertThat(original.test(2), is(true)); + } + + // --- Varargs detection --- + + @SuppressWarnings("unchecked") + @Test + public void shouldDetectMultipleTraversalsInVarargs() { + // This tests the varargs path: P.within(trav1, trav2) going through within(V... values) + final Traversal trav1 = __.constant(10); + final Traversal trav2 = __.constant(20); + final P p = (P) P.within(trav1, trav2); + assertThat(p.hasTraversal(), is(true)); + assertThat(p.getTraversalValues() != null, is(true)); + assertThat(p.getTraversalValues().size(), is(2)); + p.resolve(createTraverser("start")); + assertThat(p.test(10), is(true)); + assertThat(p.test(20), is(true)); + assertThat(p.test(30), is(false)); + } + + // --- collectTraversals and integrateTraversals --- + + @Test + public void shouldCollectTraversalsFromMultiTraversalPredicate() { + final P p = P.within(__.constant(1).asAdmin(), __.constant(2).asAdmin(), __.constant(3).asAdmin()); + final java.util.List> collected = new java.util.ArrayList<>(); + P.collectTraversals(p, collected); + assertThat(collected.size(), is(3)); + } + } + + /** + * Covers the empty-result semantics of collection (within/without) versus scalar predicates and the + * behavior of connective predicates (AndP/OrP) and NotP when their operands carry child traversals. + *

+ * Regression coverage for: within(empty) -> false, without(empty) -> true (collection predicates resolve + * to an empty collection rather than short-circuiting), scalar predicates remain resolved-empty, and the + * shared-state safety of resolving the same predicate across many traversers sequentially. + */ + public static class EmptyResolutionAndConnectiveTest { + + private Traverser.Admin createTraverser(final Object value) { + return new B_O_Traverser<>(value, 1L); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldPassWithoutWhenTraversalResolvesEmpty() { + // without(empty set) -> nothing to exclude -> everything passes + final P p = P.without(__.limit(0).asAdmin()); + p.resolve(createTraverser("anything")); + assertThat(p.isResolvedEmpty(), is(false)); + assertThat(p.test("anything"), is(true)); + assertThat(p.test(42), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldFailWithinWhenTraversalResolvesEmpty() { + // within(empty set) -> nothing matches -> everything fails + final P p = P.within(__.limit(0).asAdmin()); + p.resolve(createTraverser("anything")); + assertThat(p.isResolvedEmpty(), is(false)); + assertThat(p.test("anything"), is(false)); + assertThat(p.test(42), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldPassWithoutWhenFoldedTraversalIsEmpty() { + // explicit empty collection via fold() of nothing + final P p = P.without(__.limit(0).fold().asAdmin()); + p.resolve(createTraverser("anything")); + assertThat(p.test("anything"), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldFailWithinWhenMultiTraversalResolvesAllEmpty() { + final P p = P.within(__.limit(0).asAdmin(), __.limit(0).asAdmin()); + p.resolve(createTraverser("anything")); + assertThat(p.isResolvedEmpty(), is(false)); + assertThat(p.test(1), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldRemainResolvedEmptyForScalarPredicateWithEmptyTraversal() { + // eq(empty) has no comparison value -> resolved empty so the step can short-circuit + final P p = P.eq(__.limit(0).asAdmin()); + p.resolve(createTraverser("anything")); + assertThat(p.isResolvedEmpty(), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveAndPWithTraversalOperands() { + final P p = (P) (P) P.gt(__.constant(10).asAdmin()).and(P.lt(__.constant(20).asAdmin())); + p.resolve(createTraverser("start")); + assertThat(p.test(15), is(true)); + assertThat(p.test(10), is(false)); + assertThat(p.test(25), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldShortCircuitAndPResolveWhenScalarChildEmpty() { + // first child resolves empty (no comparison value); AndP cannot be satisfied + final P p = (P) (P) P.eq(__.limit(0).asAdmin()).and(P.gt(__.constant(5).asAdmin())); + p.resolve(createTraverser("start")); + assertThat(p.isResolvedEmpty(), is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveOrPWithTraversalOperands() { + final P p = (P) (P) P.eq(__.constant(1).asAdmin()).or(P.eq(__.constant(2).asAdmin())); + p.resolve(createTraverser("start")); + assertThat(p.test(1), is(true)); + assertThat(p.test(2), is(true)); + assertThat(p.test(3), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldReturnFalseForOrPWhenResolvedNonEmptyButNonMatching() { + // a non-empty within() resolution that simply does not contain the test value must still return false + final P p = (P) (P) P.within(__.inject(1, 2, 3).fold().asAdmin()) + .or(P.within(__.inject(4, 5, 6).fold().asAdmin())); + p.resolve(createTraverser("start")); + assertThat(p.test(2), is(true)); + assertThat(p.test(5), is(true)); + assertThat(p.test(9), is(false)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldResolveNotPWrappingTraversalPredicate() { + final P p = P.eq(__.constant(42).asAdmin()).negate(); + p.resolve(createTraverser("start")); + assertThat(p.test(42), is(false)); + assertThat(p.test(99), is(true)); + } + + @Test + public void shouldExposeWrappedPredicateFromNotP() { + final P inner = P.eq(__.constant(42).asAdmin()); + final NotP notP = new NotP<>(inner); + assertThat(notP.getWrapped() == inner, is(true)); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldProduceConsistentResultsAcrossManySequentialResolves() { + // resolve() mutates the predicate per traverser; verify repeated resolve+test cycles are stable + final P p = P.gt(__.constant(10).asAdmin()); + for (int i = 0; i < 1000; i++) { + p.resolve(createTraverser("start" + i)); + assertThat(p.test(11), is(true)); + assertThat(p.test(5), is(false)); + } + } + } +} diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/CloneIndependenceTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/CloneIndependenceTraversalTest.java new file mode 100644 index 00000000000..4c8d6ff8501 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/CloneIndependenceTraversalTest.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.step; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; +import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsSame.sameInstance; + +/** + * Property 8: Clone independence for traversal-bearing steps. + *

+ * For any step containing child traversal arguments, cloning the step SHALL produce a deep copy + * where modifying the clone's child traversal state does NOT affect the original step's child + * traversal state. + */ +public class CloneIndependenceTraversalTest { + + @Test + public void shouldProduceIndependentCloneForHasStepWithTraversalValue() { + // Create a HasStep with a traversal-bearing HasContainer (P.eq(traversal)) + final Traversal.Admin childTraversal = __.constant("marko").asAdmin(); + final HasContainer hc = new HasContainer("name", P.eq(childTraversal)); + final HasStep original = new HasStep<>(EmptyTraversal.instance(), hc); + + // Clone the step + final HasStep clone = original.clone(); + + // Verify the clone has child traversals + final List> originalChildren = (List) original.getLocalChildren(); + final List> cloneChildren = (List) clone.getLocalChildren(); + + assertThat(originalChildren.size(), is(1)); + assertThat(cloneChildren.size(), is(1)); + + // The child traversals should be different instances (deep copy) + assertThat(cloneChildren.get(0), is(not(sameInstance(originalChildren.get(0))))); + + // Verify HasContainers are also independent + final List originalContainers = original.getHasContainers(); + final List cloneContainers = clone.getHasContainers(); + assertThat(cloneContainers.get(0), is(not(sameInstance(originalContainers.get(0))))); + assertThat(cloneContainers.get(0).getPredicate().getTraversalValue(), + is(not(sameInstance(originalContainers.get(0).getPredicate().getTraversalValue())))); + } + + @Test + public void shouldProduceIndependentCloneForGraphStepWithIdTraversal() { + // Create a GraphStep with an idTraversal + final Traversal.Admin idTraversal = __.select("ids").asAdmin(); + final GraphStep original = + new GraphStep<>(EmptyTraversal.instance(), Vertex.class, false, idTraversal); + + // Clone the step + final GraphStep clone = original.clone(); + + // Verify the clone has a child traversal + assertThat(original.getIdTraversal(), is(notNullValue())); + assertThat(clone.getIdTraversal(), is(notNullValue())); + + // The idTraversal should be a different instance (deep copy) + assertThat(clone.getIdTraversal(), is(not(sameInstance(original.getIdTraversal())))); + } + + @Test + public void shouldProduceIndependentCloneForHasStepWithMultipleContainers() { + // Create a HasStep with multiple HasContainers, some with traversals + final HasContainer hc1 = new HasContainer("name", P.eq(__.constant("marko").asAdmin())); + final HasContainer hc2 = new HasContainer("age", P.eq(__.constant(29).asAdmin())); + final HasStep original = new HasStep<>(EmptyTraversal.instance(), hc1, hc2); + + // Clone the step + final HasStep clone = original.clone(); + + // Verify all containers are independent + final List originalContainers = original.getHasContainers(); + final List cloneContainers = clone.getHasContainers(); + + assertThat(originalContainers.size(), is(2)); + assertThat(cloneContainers.size(), is(2)); + + for (int i = 0; i < originalContainers.size(); i++) { + assertThat(cloneContainers.get(i), is(not(sameInstance(originalContainers.get(i))))); + assertThat(cloneContainers.get(i).getPredicate().getTraversalValue(), + is(not(sameInstance(originalContainers.get(i).getPredicate().getTraversalValue())))); + } + } + +} diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainerTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainerTest.java new file mode 100644 index 00000000000..efe7072ad08 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainerTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.step.util; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.core.IsSame.sameInstance; +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link HasContainer}, including traversal-bearing predicates and lifecycle methods. + * A traversal-bearing container holds a {@link P} whose value is resolved at runtime from a child traversal + * (e.g. {@code P.eq(traversal)}); the container exposes this via {@link HasContainer#hasTraversal()}. + */ +public class HasContainerTest { + + @Test + public void shouldReturnFalseForHasTraversalWithLiteralPredicate() { + final HasContainer hc = new HasContainer("name", P.eq("marko")); + assertThat(hc.hasTraversal(), is(false)); + } + + @Test + public void shouldReturnTrueForHasTraversalWithTraversalPredicate() { + final Traversal.Admin traversal = __.identity().asAdmin(); + final HasContainer hc = new HasContainer("name", P.eq(traversal)); + assertThat(hc.hasTraversal(), is(true)); + } + + @Test + public void shouldSetFieldsCorrectlyWithTraversalPredicate() { + final Traversal.Admin traversal = __.identity().asAdmin(); + final HasContainer hc = new HasContainer("age", P.eq(traversal)); + + assertEquals("age", hc.getKey()); + assertThat(hc.getPredicate().getTraversalValue(), is(sameInstance(traversal))); + } + + @Test + public void shouldCloneProduceIndependentDeepCopyOfTraversalPredicate() { + final Traversal.Admin traversal = __.identity().asAdmin(); + final HasContainer original = new HasContainer("name", P.eq(traversal)); + final HasContainer clone = original.clone(); + + // clone's predicate should carry a traversal that is not the same instance + assertThat(clone.getPredicate().getTraversalValue(), is(notNullValue())); + assertThat(clone.getPredicate().getTraversalValue(), + is(not(sameInstance(original.getPredicate().getTraversalValue())))); + + // key should be equal + assertEquals(original.getKey(), clone.getKey()); + + // both should still report hasTraversal + assertThat(clone.hasTraversal(), is(true)); + } + + @Test + public void shouldCloneLiteralHasContainerWithoutTraversal() { + final HasContainer original = new HasContainer("name", P.eq("marko")); + final HasContainer clone = original.clone(); + + assertThat(clone.hasTraversal(), is(false)); + assertEquals("name", clone.getKey()); + assertEquals(P.eq("marko"), clone.getPredicate()); + } +} diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategyTest.java new file mode 100644 index 00000000000..feb0688283a --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ChildTraversalVerificationStrategyTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.strategy.verification; + +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; +import org.junit.Test; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +/** + * Tests for the ChildTraversalVerificationStrategy (strategy-time layer). + */ +public class ChildTraversalVerificationStrategyTest { + + private final GraphTraversalSource g = EmptyGraph.instance().traversal(); + + @Test + public void shouldBeRegisteredByDefault() { + // The strategy should be present in the default Graph strategy set (not EmptyGraph which has none) + assertTrue(TraversalStrategies.GlobalCache + .getStrategies(Graph.class) + .getStrategy(ChildTraversalVerificationStrategy.class).isPresent()); + } + + @Test + public void shouldBeRemovableViaWithoutStrategies() { + // Users should be able to remove the strategy if needed + final GraphTraversalSource gNoVerify = g.withoutStrategies(ChildTraversalVerificationStrategy.class); + assertFalse(gNoVerify.getStrategies().getStrategy(ChildTraversalVerificationStrategy.class).isPresent()); + } + + @Test + public void shouldNotRejectValidReadOnlyTraversal() { + // Valid traversal should pass strategy application without error + final Traversal.Admin traversal = g.V().has("name", __.V().values("name")).asAdmin(); + traversal.applyStrategies(); + // If we get here without exception, the test passes + } + + @Test + public void shouldNotRejectValidLookupTraversal() { + // Valid V(traversal) should pass + final Traversal.Admin traversal = g.V().V(__.out("knows").id()).asAdmin(); + traversal.applyStrategies(); + } +} diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java new file mode 100644 index 00000000000..49561b4cd95 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/ChildTraversalValidatorTest.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.util; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TextP; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; +import org.junit.Test; + +import static org.junit.Assert.assertThrows; + +/** + * Tests for construction-time child traversal validation. + */ +public class ChildTraversalValidatorTest { + + private final GraphTraversalSource g = EmptyGraph.instance().traversal(); + + // ===== FILTER CONTEXT: should reject mutating steps ===== + + @Test + public void shouldRejectAddVInHasTraversal() { + assertThrows(IllegalArgumentException.class, () -> + g.V().has("name", __.addV("x").values("name"))); + } + + @Test + public void shouldRejectDropInHasTraversal() { + assertThrows(IllegalArgumentException.class, () -> + g.V().has("name", __.V().drop().constant("x"))); + } + + @Test + public void shouldRejectNestedMutatingInHasTraversal() { + assertThrows(IllegalArgumentException.class, () -> + g.V().has("name", __.V().map(__.addV("x")).values("name"))); + } + + @Test + public void shouldRejectMutatingInHasWithTAccessor() { + assertThrows(IllegalArgumentException.class, () -> + g.V().has(org.apache.tinkerpop.gremlin.structure.T.label, __.addV("x").label())); + } + + @Test + public void shouldRejectMutatingInHasWithLabel() { + assertThrows(IllegalArgumentException.class, () -> + g.V().has("person", "name", __.addV("x").values("name"))); + } + + // ===== LOOKUP CONTEXT: should reject mutating steps ===== + + @Test + public void shouldRejectAddVInMidTraversalV() { + assertThrows(IllegalArgumentException.class, () -> + g.V().V(__.addV("x").id())); + } + + @Test + public void shouldRejectAddVInMidTraversalE() { + assertThrows(IllegalArgumentException.class, () -> + g.V().E(__.addV("x").id())); + } + + @Test + public void shouldRejectAddVInStartStepV() { + assertThrows(IllegalArgumentException.class, () -> + g.V(__.addV("x").id())); + } + + @Test + public void shouldRejectAddVInStartStepE() { + assertThrows(IllegalArgumentException.class, () -> + g.E(__.addV("x").id())); + } + + // ===== P FACTORY METHODS: should reject mutating steps ===== + + @Test + public void shouldRejectMutatingInPEq() { + assertThrows(IllegalArgumentException.class, () -> + P.eq(__.addV("x").values("name"))); + } + + @Test + public void shouldRejectMutatingInPNeq() { + assertThrows(IllegalArgumentException.class, () -> + P.neq(__.addV("x").values("name"))); + } + + @Test + public void shouldRejectMutatingInPGt() { + assertThrows(IllegalArgumentException.class, () -> + P.gt(__.addV("x").values("age"))); + } + + @Test + public void shouldRejectMutatingInPLt() { + assertThrows(IllegalArgumentException.class, () -> + P.lt(__.addV("x").values("age"))); + } + + @Test + public void shouldRejectMutatingInPGte() { + assertThrows(IllegalArgumentException.class, () -> + P.gte(__.addV("x").values("age"))); + } + + @Test + public void shouldRejectMutatingInPLte() { + assertThrows(IllegalArgumentException.class, () -> + P.lte(__.addV("x").values("age"))); + } + + @Test + public void shouldRejectMutatingInPWithin() { + assertThrows(IllegalArgumentException.class, () -> + P.within(__.addV("x").values("name"))); + } + + @Test + public void shouldRejectMutatingInPWithout() { + assertThrows(IllegalArgumentException.class, () -> + P.without(__.addV("x").values("name"))); + } + + @Test + public void shouldRejectMutatingInMultiTraversalWithin() { + assertThrows(IllegalArgumentException.class, () -> + P.within(__.V().values("name"), __.addV("x").values("name"))); + } + + @Test + public void shouldRejectMutatingInMultiTraversalWithout() { + assertThrows(IllegalArgumentException.class, () -> + P.without(__.V().values("name"), __.addV("x").values("name"))); + } + + // ===== TextP FACTORY METHODS: should reject mutating steps ===== + + @Test + public void shouldRejectMutatingInTextPStartingWith() { + assertThrows(IllegalArgumentException.class, () -> + TextP.startingWith(__.addV("x").values("name"))); + } + + @Test + public void shouldRejectMutatingInTextPContaining() { + assertThrows(IllegalArgumentException.class, () -> + TextP.containing(__.addV("x").values("name"))); + } + + // ===== MUTATION CONTEXT: should reject DropStep but allow other mutations ===== + + @Test + public void shouldRejectDropInPropertyTraversal() { + assertThrows(IllegalArgumentException.class, () -> + g.V().property(__.V().map(__.drop()).project("x").by("name"))); + } + + @Test + public void shouldRejectNestedDropInPropertyTraversal() { + assertThrows(IllegalArgumentException.class, () -> + g.V().property(__.V().union(__.drop(), __.constant("x")).project("k").by())); + } + + // ===== VALID TRAVERSALS: should pass without error ===== + + @Test + public void shouldAllowReadOnlyHasTraversal() { + // Should not throw + g.V().has("name", __.V().values("name")); + } + + @Test + public void shouldAllowNavigationInHasTraversal() { + // Should not throw + g.V().has("name", __.V().out("knows").values("name")); + } + + @Test + public void shouldAllowReadOnlyLookupTraversal() { + // Should not throw + g.V().V(__.out("knows").id()); + } + + @Test + public void shouldAllowReadOnlyStartStepV() { + // Should not throw + g.V(__.V().id()); + } + + @Test + public void shouldAllowReadOnlyPredicate() { + // Should not throw + P.eq(__.V().values("age")); + } + + @Test + public void shouldRejectAddVInMutationContext() { + // addV is blocked in property(traversal) - mutating steps are blocked in child traversals + assertThrows(IllegalArgumentException.class, () -> + g.V().property(__.V().addV("temp").project("k").by("name"))); + } + + @Test + public void shouldAllowReadOnlyPropertyTraversal() { + // Should not throw + g.V().property(__.V().project("name").by("name")); + } + + // ===== CHOOSE CONTEXT: should reject traversal-bearing predicates ===== + + @Test + public void shouldRejectTraversalPredicateInChooseIfThen() { + assertThrows(IllegalArgumentException.class, () -> + g.V().values("age").choose(P.gt(__.V().values("age")), __.constant("older"), __.constant("younger"))); + } + + @Test + public void shouldRejectTraversalPredicateInChooseIfOnly() { + assertThrows(IllegalArgumentException.class, () -> + g.V().values("age").choose(P.gt(__.V().values("age")), __.constant("older"))); + } + + @Test + public void shouldRejectTraversalPredicateInChooseOption() { + assertThrows(IllegalArgumentException.class, () -> + g.V().values("age").choose(__.identity()).option(P.gt(__.V().values("age")), __.constant("older"))); + } + + @Test + public void shouldAllowLiteralPredicateInChoose() { + // Literal predicates should still work + g.V().values("age").choose(P.gt(30), __.constant("older"), __.constant("younger")); + } + + @Test + public void shouldAllowLiteralPredicateInChooseOption() { + // Literal predicates as option keys should still work + g.V().values("age").choose(__.identity()).option(P.gt(30), __.constant("older")); + } +} \ No newline at end of file diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs index de01df33678..5f5852ec1de 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs @@ -1825,6 +1825,16 @@ public GraphTraversal Property(Cardinality cardinality, IDictionar return Wrap(this); } + ///

+ /// Adds the property step with a map-producing traversal to this . + /// The traversal must produce a Map whose entries become properties on the element. + /// + public GraphTraversal Property(ITraversal propertyTraversal) + { + GremlinLang.AddStep("property", propertyTraversal); + return Wrap(this); + } + /// /// Adds the propertyMap step to this . diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs index 684a76c2f6f..8bdb2e4c84c 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GremlinLang.cs @@ -26,6 +26,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Numerics; using System.Reflection; using System.Text; @@ -472,11 +473,21 @@ private string AsString(P p) } else if (p.Value is IList listVal && (p.OperatorName == "within" || p.OperatorName == "without")) { - // within/without with a list value - render as [e1,e2,...] + // within/without with a list value if (listVal.Count == 0) { // empty within() - no brackets } + else if (listVal.Cast().All(v => v is ITraversal)) + { + // All elements are traversals - serialize as comma-separated args (no brackets) + // This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs + for (int i = 0; i < listVal.Count; i++) + { + if (i > 0) sb.Append(','); + sb.Append(ArgAsString(listVal[i])); + } + } else { sb.Append('['); diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs index fe33aec3e88..18f827a7ea1 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/P.cs @@ -157,12 +157,22 @@ public static P TypeOf(params object[]? args) public static P Within(params object[]? args) { + if (args is { Length: 1 } && args[0] is ITraversal) + return new P("within", args[0]); + // Multiple traversals - store as list preserving ITraversal type for serializer detection + if (args is { Length: > 1 } && args.All(a => a is ITraversal)) + return new P("within", new List(args)); var x = args is { Length: 1 } && args[0] is ICollection collection ? collection : args; return new P("within", ToGenericList(x)); } public static P Without(params object[]? args) { + if (args is { Length: 1 } && args[0] is ITraversal) + return new P("without", args[0]); + // Multiple traversals - store as list preserving ITraversal type for serializer detection + if (args is { Length: > 1 } && args.All(a => a is ITraversal)) + return new P("without", new List(args)); var x = args is { Length: 1 } && args[0] is ICollection collection ? collection : args; return new P("without", ToGenericList(x)); } diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs index cc94f346819..8b0d81e1344 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TextP.cs @@ -51,31 +51,61 @@ public static TextP Containing(string value) return new TextP("containing", value); } + public static P Containing(object value) + { + return new P("containing", value); + } + public static TextP EndingWith(string value) { return new TextP("endingWith", value); } + public static P EndingWith(object value) + { + return new P("endingWith", value); + } + public static TextP NotContaining(string value) { return new TextP("notContaining", value); } + public static P NotContaining(object value) + { + return new P("notContaining", value); + } + public static TextP NotEndingWith(string value) { return new TextP("notEndingWith", value); } + public static P NotEndingWith(object value) + { + return new P("notEndingWith", value); + } + public static TextP NotStartingWith(string value) { return new TextP("notStartingWith", value); } + public static P NotStartingWith(object value) + { + return new P("notStartingWith", value); + } + public static TextP StartingWith(string value) { return new TextP("startingWith", value); } + public static P StartingWith(object value) + { + return new P("startingWith", value); + } + public static TextP Regex(string value) { return new TextP("regex", value); diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs index b16732a61b0..3ccccdd839a 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs @@ -1256,6 +1256,15 @@ public static GraphTraversal Property(IDictionary().Property(map); } + /// + /// Spawns a and adds the property step with a + /// map-producing traversal to that traversal. + /// + public static GraphTraversal Property(ITraversal propertyTraversal) + { + return new GraphTraversal().Property(propertyTraversal); + } + /// /// Spawns a and adds the propertyMap step to that traversal. /// diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 8ac4ef7b25f..8881b5da07c 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -373,6 +373,23 @@ private static IDictionary, ITraversal>> {(g,p) =>g.Inject(7).Any(P.Eq(7))}}, {"g_injectXnull_nullX_anyXeqXnullXX", new List, ITraversal>> {(g,p) =>g.Inject(new List { null, null }).Any(P.Eq(null))}}, {"g_injectX3_threeX_anyXeqX3XX", new List, ITraversal>> {(g,p) =>g.Inject(new List { 3, "three" }).Any(P.Eq(3))}}, + {"g_V_hasXname_addVXxX_valuesXnameXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.AddV((string) "x").Values("name"))}}, + {"g_V_hasXname_V_drop_constantXxXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.V().Drop().Constant("x"))}}, + {"g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.V().Map(__.AddV((string) "x")).Values("name"))}}, + {"g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.AddV((string) "x").Values("name")))}}, + {"g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.AddV((string) "x").Values("name")))}}, + {"g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.AddV((string) "x").Values("age")))}}, + {"g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(__.AddV((string) "x").Values("age"))}}, + {"g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Gt(__.AddV((string) "x").Values("age")))}}, + {"g_V_VXaddVXxX_idX_rejected", new List, ITraversal>> {(g,p) =>g.V().V(__.AddV((string) "x").Id())}}, + {"g_V_EXaddVXxX_idX_rejected", new List, ITraversal>> {(g,p) =>g.V().E(__.AddV((string) "x").Id())}}, + {"g_VXaddVXxX_idX_rejected", new List, ITraversal>> {(g,p) =>g.V(__.AddV((string) "x").Id())}}, + {"g_EXaddVXxX_idX_rejected", new List, ITraversal>> {(g,p) =>g.E(__.AddV((string) "x").Id())}}, + {"g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Property((ITraversal) __.V().Map(__.Drop()).Project("x").By("name"))}}, + {"g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected", new List, ITraversal>> {(g,p) =>g.V().Property((ITraversal) __.AddV((string) "temp").Project("k").By("name"))}}, + {"g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values("name"))}}, + {"g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.V(p["vid1"]).Values("age")))}}, + {"g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Id()).Values("name")}}, {"g_V_coinX1_0X", new List, ITraversal>> {(g,p) =>g.V().Coin(1.0)}}, {"g_V_coinX1X", new List, ITraversal>> {(g,p) =>g.V().Coin(1)}}, {"g_V_coinX0X", new List, ITraversal>> {(g,p) =>g.V().Coin(0.0)}}, @@ -532,6 +549,28 @@ private static IDictionary, ITraversal>> {(g,p) =>g.E().Has(T.Label, (object) null)}}, {"g_V_properties_hasLabelXnullX", new List, ITraversal>> {(g,p) =>g.V().Properties().HasLabel((string) null)}}, {"g_V_hasNotXageX_name", new List, ITraversal>> {(g,p) =>g.V().HasNot("age").Values("name")}}, + {"g_V_hasXname_VXvid1X_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values("name"))}}, + {"g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Out("knows").Values("name"))}}, + {"g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", __.V(p["vid1"]).Out("knows").Values("age"))}}, + {"g_V_hasXname_VXvid1X_valuesXnonexistentXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.V(p["vid1"]).Values("nonexistent"))}}, + {"g_V_hasXname_notXidentityXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", __.Not(__.Identity()))}}, + {"g_V_hasXage_gtXVXvid1X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Gt(__.V(p["vid1"]).Values("age")))}}, + {"g_V_hasXage_lteXVXvid2X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Lte(__.V(p["vid2"]).Values("age")))}}, + {"g_V_hasXage_neqXVXvid3X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Neq(__.V(p["vid3"]).Values("age")))}}, + {"g_V_hasXname_eqXVXvid1X_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.V(p["vid1"]).Values("name")))}}, + {"g_V_hasXage_ltXVXvid1X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Lt(__.V(p["vid1"]).Values("age")))}}, + {"g_V_hasXage_gteXVXvid3X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Gte(__.V(p["vid3"]).Values("age")))}}, + {"g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX", new List, ITraversal>> {(g,p) =>g.V().Has("age", P.Eq(__.V(p["vid1"]).Values("nonexistent")))}}, + {"g_V_hasXlabel_VXvid1X_labelXX", new List, ITraversal>> {(g,p) =>g.V().Has(T.Label, __.V(p["vid1"]).Label())}}, + {"g_V_hasXperson_name_VXvid1X_valuesXnameXX_age", new List, ITraversal>> {(g,p) =>g.V().Has("person", "name", __.V(p["vid1"]).Values("name")).Values("age")}}, + {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values("name").Fold(), __.Constant("peter")))}}, + {"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Values("nonexistent"), __.Constant("marko")))}}, + {"g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Values("nonexistent"), __.V(p["vid1"]).Values("nonexistent")))}}, + {"g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Without(__.V(p["vid1"]).Values("name"), __.V(p["vid2"]).Values("name"), __.V(p["vid3"]).Values("name")))}}, + {"g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Within(__.V(p["vid1"]).Out("knows").Values("name").Fold(), __.V(p["vid3"]).Out("created").Values("name").Fold()))}}, + {"g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.V().HasLabel("software").Has("name", P.Without(__.V(p["vid1"]).Out("created").Values("name").Fold(), __.V(p["vid3"]).Out("created").Values("name").Fold()))}}, + {"g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values("age").Is(P.Within(__.V(p["vid1"]).Values("age").Fold(), __.V().Has("name", "lop").In("created").Values("age").Fold()))}}, + {"g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Filter(__.InV().Has("name", P.Within(__.V().Has("name", "lop").In("created").Values("name").Fold(), __.V().Has("name", "ripple").In("created").Values("name").Fold())))}}, {"g_V_properties_hasValueXnullX", new List, ITraversal>> {(g,p) =>g.V().Properties().HasValue((object) null)}}, {"g_V_properties_hasValueXnull_nullX", new List, ITraversal>> {(g,p) =>g.V().Properties().HasValue(null, null)}}, {"g_V_properties_hasValueXnull_joshX_value", new List, ITraversal>> {(g,p) =>g.V().Properties().HasValue(null, "josh").Value()}}, @@ -543,6 +582,26 @@ private static IDictionary, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Gte(p["xx1"])).Is(P.Lt(p["xx2"]))}}, {"g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX", new List, ITraversal>> {(g,p) =>g.V().Where(__.In("created").Count().Is(1)).Values("name")}}, {"g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX", new List, ITraversal>> {(g,p) =>g.V().Where(__.In("created").Count().Is(P.Gte(2))).Values("name")}}, + {"g_V_valuesXageX_isXVXvid1X_valuesXageXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(__.V(p["vid1"]).Values("age"))}}, + {"g_V_valuesXnameX_isXVXvid1X_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.V().Values("name").Is(__.V(p["vid1"]).Values("name"))}}, + {"g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Gt(__.V(p["vid1"]).Values("age")))}}, + {"g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Lt(__.V(p["vid3"]).Values("age")))}}, + {"g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Neq(__.V(p["vid4"]).Values("age")))}}, + {"g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Within(__.V(p["vid1"]).Out("knows").Values("age").Fold()))}}, + {"g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(__.V(p["vid1"]).Values("nonexistent"))}}, + {"g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX", new List, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values("age").Choose(__.Is(P.Gt(__.V(p["vid1"]).Values("age"))), __.Constant("older than marko"), __.Constant("not older"))}}, + {"g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX", new List, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values("age").Choose(__.Is(P.Gte(__.V().HasLabel("person").Values("age").Mean())), __.Constant("above average"), __.Constant("below average"))}}, + {"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values("age").Fold().All(P.Gte(__.V(p["vid2"]).Values("age")))}}, + {"g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values("age").Fold().All(P.Gt(__.V(p["vid2"]).Values("age")))}}, + {"g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values("age").Fold().Any(P.Eq(__.V(p["vid3"]).Values("age")))}}, + {"g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values("age").Fold().None(P.Eq(__.V(p["vid4"]).Values("age")))}}, + {"g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out("knows").Values("age").Fold().None(P.Eq(__.V(p["vid3"]).Values("age")))}}, + {"g_injectXnullX_isXeqXV9999_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.Inject(null).Is(P.Eq(__.V(9999).Values("name")))}}, + {"g_injectXmarkoX_isXV9999_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.Inject("marko").Is(__.V(9999).Values("name"))}}, + {"g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX", new List, ITraversal>> {(g,p) =>g.Inject("marko").Choose(__.Is(P.Eq(__.V(9999).Values("name"))), __.Constant("matched"), __.Constant("unmatched"))}}, + {"g_injectXlistX_noneXeqXV9999_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.Inject(new List { "marko", "josh" }).None(P.Eq(__.V(9999).Values("name")))}}, + {"g_V_hasXname_eqXV9999_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.V().Has("name", P.Eq(__.V(9999).Values("name")))}}, + {"g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Is(P.Without(__.V(p["vid1"]).Values("age"), __.V(p["vid2"]).Values("age")))}}, {"g_V_valuesXageX_noneXgtX32XX", new List, ITraversal>> {(g,p) =>g.V().Values("age").None(P.Gt(32))}}, {"g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Where(__.Is(P.Gt(33))).Fold().None(P.Lte(33))}}, {"g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Order().By(Order.Desc).Fold().None(P.Lt(10))}}, @@ -715,6 +774,13 @@ private static IDictionary, ITraversal>> {(g,p) =>g.V().Where(__.Values("age").Is(P.Gt(30)))}}, {"g_V_whereXlabel_isXsoftwareXX", new List, ITraversal>> {(g,p) =>g.V().Where(__.Label().Is("software"))}}, {"g_V_whereXlabel_isXpersonXX", new List, ITraversal>> {(g,p) =>g.V().Where(__.Label().Is("person"))}}, + {"g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Where(P.Gt(__.V(p["vid1"]).Values("age")))}}, + {"g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Where(P.Lt(__.V(p["vid3"]).Values("age")))}}, + {"g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Where(P.Eq(__.V(p["vid1"]).Values("age")))}}, + {"g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Where(P.Within(__.V(p["vid1"]).Out("knows").Values("age").Fold()))}}, + {"g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX", new List, ITraversal>> {(g,p) =>g.V().Values("name").Where(P.Neq(__.V(p["vid1"]).Values("name")))}}, + {"g_V_valuesXageX_whereXeqXV9999_valuesXageXXX", new List, ITraversal>> {(g,p) =>g.V().Values("age").Where(P.Eq(__.V(9999).Values("age")))}}, + {"g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX", new List, ITraversal>> {(g,p) =>g.V().Where(P.Gt(__.V(p["vid1"]).Values("age"))).By("age").Values("name")}}, {"g_withStrategiesXAdjacentToIncidentStrategyX_V", new List, ITraversal>> {(g,p) =>g.WithStrategies(new AdjacentToIncidentStrategy()).V()}}, {"g_withoutStrategiesXAdjacentToIncidentStrategyX_V", new List, ITraversal>> {(g,p) =>g.WithoutStrategies(typeof(AdjacentToIncidentStrategy)).V()}}, {"g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count", new List, ITraversal>> {(g,p) =>g.WithStrategies(new AdjacentToIncidentStrategy()).V().Out().Count()}}, @@ -946,9 +1012,9 @@ private static IDictionary, ITraversal>> {(g,p) =>g.AddV().Property(Cardinality.Single, new Dictionary {{ "name", "foo" }, { "age", 42 }}), (g,p) =>g.V().Has("name", "foo")}}, {"g_V_hasXname_fooX_propertyXname_setXbarX_age_43X", new List, ITraversal>> {(g,p) =>g.AddV().Property(Cardinality.Single, "name", "foo").Property("age", 42), (g,p) =>g.V().Has("name", "foo").Property(new Dictionary {{ "name", CardinalityValue.Set("bar") }, { "age", 43 }}), (g,p) =>g.V().Has("name", "foo"), (g,p) =>g.V().Has("name", "bar"), (g,p) =>g.V().Has("age", 43), (g,p) =>g.V().Has("age", 42)}}, {"g_V_hasXname_fooX_propertyXset_name_bar_age_singleX43XX", new List, ITraversal>> {(g,p) =>g.AddV().Property(Cardinality.Single, "name", "foo").Property("age", 42), (g,p) =>g.V().Has("name", "foo").Property(Cardinality.Set, new Dictionary {{ "name", "bar" }, { "age", CardinalityValue.Single(43) }}), (g,p) =>g.V().Has("name", "foo"), (g,p) =>g.V().Has("name", "bar"), (g,p) =>g.V().Has("age", 43), (g,p) =>g.V().Has("age", 42)}}, - {"g_addV_propertyXnullX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property(null), (g,p) =>g.V().HasLabel("person").Values()}}, + {"g_addV_propertyXnullX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property((IDictionary) null), (g,p) =>g.V().HasLabel("person").Values()}}, {"g_addV_propertyXemptyX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property(new Dictionary {}), (g,p) =>g.V().HasLabel("person").Values()}}, - {"g_addV_propertyXset_nullX", new List, ITraversal>> {(g,p) =>g.AddV((string) "foo").Property(Cardinality.Set, null), (g,p) =>g.V().HasLabel("foo").Values()}}, + {"g_addV_propertyXset_nullX", new List, ITraversal>> {(g,p) =>g.AddV((string) "foo").Property(Cardinality.Set, (IDictionary) null), (g,p) =>g.V().HasLabel("foo").Values()}}, {"g_addV_propertyXset_emptyX", new List, ITraversal>> {(g,p) =>g.AddV((string) "foo").Property(Cardinality.Set, new Dictionary {}), (g,p) =>g.V().HasLabel("person").Values()}}, {"g_addVXpersonX_propertyXname_joshX_propertyXage_nullX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "josh").Property("age", null), (g,p) =>g.V().Has("person", "age", (object) null)}}, {"g_addVXpersonX_propertyXname_markoX_propertyXfriendWeight_null_acl_nullX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("friendWeight", null, "acl", null), (g,p) =>g.V().Has("person", "name", "marko").Has("friendWeight", (object) null), (g,p) =>g.V().Has("person", "name", "marko").Properties("friendWeight").Has("acl", (object) null), (g,p) =>g.V().Has("person", "name", "marko").Properties("friendWeight").Count()}}, @@ -1779,6 +1845,16 @@ private static IDictionary, ITraversal>> {(g,p) =>g.V().Local(__.OutE().Fold()).Unfold()}}, {"g_V_valueMap_unfold_mapXselectXkeysXX", new List, ITraversal>> {(g,p) =>g.V().ValueMap().Unfold().Map(__.Select(Column.Keys))}}, {"g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Repeat(__.Both().SimplePath()).Until(__.HasId(p["vid6"])).Path().By("name").Unfold()}}, + {"g_VXvid1X_id_VXidentityX_name", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Id().V(__.Identity()).Values("name")}}, + {"g_VXvid1_vid2X_id_VXidentityX_name", new List, ITraversal>> {(g,p) =>g.V(p["vid1"], p["vid2"]).Id().V(__.Identity()).Values("name")}}, + {"g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).Id().As("bookmark").V().Has("name", "josh").V(__.Select("bookmark")).Values("name")}}, + {"g_VXvid1X_VXoutXknowsX_idX_name", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).V(__.Out("knows").Id()).Values("name")}}, + {"g_VXvid1X_EXoutE_idX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).E(__.OutE().Id())}}, + {"g_injectX9999X_VXidentityX", new List, ITraversal>> {(g,p) =>g.Inject(9999).V(__.Identity())}}, + {"g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX", new List, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE("knows").Filter(__.InV().Has("name", "vadas")).Id().E(__.Identity())}}, + {"g_injectX9999X_EXidentityX", new List, ITraversal>> {(g,p) =>g.Inject(9999).E(__.Identity())}}, + {"g_VXVXvid1X_idX_name", new List, ITraversal>> {(g,p) =>g.V(__.V(p["vid1"]).Id()).Values("name")}}, + {"g_EXVXvid1X_outE_idX", new List, ITraversal>> {(g,p) =>g.E(__.V(p["vid1"]).OutE().Id())}}, {"g_V_valueMap", new List, ITraversal>> {(g,p) =>g.V().ValueMap()}}, {"g_V_valueMapXtrueX", new List, ITraversal>> {(g,p) =>g.V().ValueMap(true)}}, {"g_V_valueMap_withXtokensX", new List, ITraversal>> {(g,p) =>g.V().ValueMap().With(WithOptions.Tokens)}}, @@ -2100,6 +2176,16 @@ private static IDictionary, ITraversal>> {(g,p) =>g.Inject(new List { 1, 3, 100, 300 })}}, {"g_injectX1_3_100_300X_set", new List, ITraversal>> {(g,p) =>g.Inject(new HashSet { 1, 3, 100, 300 })}}, {"g_injectX1_1X_set", new List, ITraversal>> {(g,p) =>g.Inject(new HashSet { 1, 1 })}}, + {"g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).AddV((string) "person").Property("name", "peter").Property("age", 35).AddV((string) "software").Property("name", "ripple").Property("lang", "java"), (g,p) =>g.V(p["vid2"]).Property("alias", __.V(p["vid1"]).Values("name")), (g,p) =>g.V().Has("alias", "marko")}}, + {"g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).As("peter").AddV((string) "software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE((string) "knows").From("marko").To(__.V().Has("name", "vadas")).AddE((string) "knows").From("marko").To("josh").AddE((string) "created").From("marko").To("lop").AddE((string) "created").From("josh").To("lop").AddE((string) "created").From("josh").To("ripple").AddE((string) "created").From("peter").To("lop"), (g,p) =>g.V(p["vid1"]).Property("creatorCount", __.V(p["vid1"]).In("created").Count()), (g,p) =>g.V().Has("creatorCount", 3l)}}, + {"g_VXvid1X_propertyXknownCount_outXknowsX_countX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).AddV((string) "software").Property("name", "ripple").Property("lang", "java").AddE((string) "knows").From("marko").To("vadas").AddE((string) "knows").From("marko").To("josh"), (g,p) =>g.V(p["vid1"]).Property("knownCount", __.Out("knows").Count()), (g,p) =>g.V().Has("knownCount", 2l)}}, + {"g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).As("peter").AddV((string) "software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE((string) "knows").From("marko").To(__.V().Has("name", "vadas")).AddE((string) "knows").From("marko").To("josh").AddE((string) "created").From("marko").To("lop").AddE((string) "created").From("josh").To("lop").AddE((string) "created").From("josh").To("ripple").AddE((string) "created").From("peter").To("lop"), (g,p) =>g.V(p["vid1"]).Property("creator", __.In("created").Values("name")), (g,p) =>g.V().Has("creator")}}, + {"g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).As("peter").AddV((string) "software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE((string) "knows").From("marko").To("vadas").AddE((string) "knows").From("marko").To("josh").AddE((string) "created").From("marko").To("lop").AddE((string) "created").From("josh").To("lop").AddE((string) "created").From("josh").To("ripple").AddE((string) "created").From("peter").To("lop"), (g,p) =>g.V(p["vid2"]).Property((ITraversal) __.V(p["vid1"]).Project("friendCount", "softwareCreated").By(__.Out("knows").Count()).By(__.Out("created").Values("name"))), (g,p) =>g.V().Has("friendCount", 2l), (g,p) =>g.V().Has("softwareCreated", "lop")}}, + {"g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).AddV((string) "person").Property("name", "peter").Property("age", 35).AddV((string) "software").Property("name", "ripple").Property("lang", "java"), (g,p) =>g.V(p["vid2"]).Property((ITraversal) __.V(p["vid1"]).Project("originalName", "originalLabel").By(__.Values("name")).By(__.Label())), (g,p) =>g.V(p["vid2"]).Has("originalName", "marko"), (g,p) =>g.V(p["vid2"]).Has("originalLabel", "person")}}, + {"g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).AddV((string) "software").Property("name", "ripple").Property("lang", "java").AddE((string) "knows").From("marko").To("vadas").AddE((string) "knows").From("marko").To("josh"), (g,p) =>g.V(p["vid1"]).Property(Cardinality.List, "friends", __.Out("knows").Values("name")), (g,p) =>g.V(p["vid1"]).Properties("friends")}}, + {"g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27).AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).AddV((string) "software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE((string) "created").From("josh").To("lop").AddE((string) "created").From("josh").To("ripple"), (g,p) =>g.V(p["vid1"]).Property(Cardinality.Set, "langs", __.Out("created").Values("lang")), (g,p) =>g.V(p["vid1"]).Properties("langs")}}, + {"g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "person").Property("name", "peter").Property("age", 35).AddV((string) "software").Property("name", "ripple").Property("lang", "java").AddE((string) "knows").From("marko").To("vadas").AddE((string) "knows").From("marko").To("josh"), (g,p) =>g.V(p["vid1"]).Property(Cardinality.Single, "friend", __.Out("knows").Values("name"))}}, + {"g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX", new List, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29), (g,p) =>g.V(p["vid1"]).Property((ITraversal) __.V(p["vid1"]).Group().By(__.Id()).By(__.Values("name")))}}, {"g_io_readXkryoX", new List, ITraversal>> {(g,p) =>g.Io("data/tinkerpop-modern.kryo").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, {"g_io_read_withXreader_gryoX", new List, ITraversal>> {(g,p) =>g.Io("data/tinkerpop-modern.kryo").With(IO.Reader, IO.Gryo).Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, {"g_io_readXgraphsonX", new List, ITraversal>> {(g,p) =>g.Io("data/tinkerpop-modern.json").Read(), (g,p) =>g.V(), (g,p) =>g.E()}}, diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go index 574fdb45fc3..21fdbd5b0a5 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -343,6 +343,23 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_injectX7X_anyXeqX7XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(7).Any(gremlingo.P.Eq(7))}}, "g_injectXnull_nullX_anyXeqXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{nil, nil}).Any(gremlingo.P.Eq(nil))}}, "g_injectX3_threeX_anyXeqX3XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{3, "three"}).Any(gremlingo.P.Eq(3))}}, + "g_V_hasXname_addVXxX_valuesXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.AddV("x").Values("name"))}}, + "g_V_hasXname_V_drop_constantXxXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V().Drop().Constant("x"))}}, + "g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V().Map(gremlingo.T__.AddV("x")).Values("name"))}}, + "g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.AddV("x").Values("name")))}}, + "g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.AddV("x").Values("name")))}}, + "g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.AddV("x").Values("age")))}}, + "g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.AddV("x").Values("age"))}}, + "g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gt(gremlingo.T__.AddV("x").Values("age")))}}, + "g_V_VXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().V(gremlingo.T__.AddV("x").Id())}}, + "g_V_EXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().E(gremlingo.T__.AddV("x").Id())}}, + "g_VXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(gremlingo.T__.AddV("x").Id())}}, + "g_EXaddVXxX_idX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(gremlingo.T__.AddV("x").Id())}}, + "g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Property(gremlingo.T__.V().Map(gremlingo.T__.Drop()).Project("x").By("name"))}}, + "g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Property(gremlingo.T__.AddV("temp").Project("k").By("name"))}}, + "g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("name"))}}, + "g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}}, + "g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Id()).Values("name")}}, "g_V_coinX1_0X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Coin(1.0)}}, "g_V_coinX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Coin(1)}}, "g_V_coinX0X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Coin(0.0)}}, @@ -502,6 +519,28 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_E_hasXlabel_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Has(gremlingo.T.Label, nil)}}, "g_V_properties_hasLabelXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasLabel(nil)}}, "g_V_hasNotXageX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasNot("age").Values("name")}}, + "g_V_hasXname_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("name"))}}, + "g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Out("knows").Values("name"))}}, + "g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.T__.V(p["vid1"]).Out("knows").Values("age"))}}, + "g_V_hasXname_VXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}}, + "g_V_hasXname_notXidentityXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.T__.Not(gremlingo.T__.Identity()))}}, + "g_V_hasXage_gtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}}, + "g_V_hasXage_lteXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Lte(gremlingo.T__.V(p["vid2"]).Values("age")))}}, + "g_V_hasXage_neqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Neq(gremlingo.T__.V(p["vid3"]).Values("age")))}}, + "g_V_hasXname_eqXVXvid1X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("name")))}}, + "g_V_hasXage_ltXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Lt(gremlingo.T__.V(p["vid1"]).Values("age")))}}, + "g_V_hasXage_gteXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Gte(gremlingo.T__.V(p["vid3"]).Values("age")))}}, + "g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("age", gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}}, + "g_V_hasXlabel_VXvid1X_labelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, gremlingo.T__.V(p["vid1"]).Label())}}, + "g_V_hasXperson_name_VXvid1X_valuesXnameXX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", gremlingo.T__.V(p["vid1"]).Values("name")).Values("age")}}, + "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name").Fold(), gremlingo.T__.Constant("peter")))}}, + "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("nonexistent"), gremlingo.T__.Constant("marko")))}}, + "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("nonexistent"), gremlingo.T__.V(p["vid1"]).Values("nonexistent")))}}, + "g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Values("name"), gremlingo.T__.V(p["vid2"]).Values("name"), gremlingo.T__.V(p["vid3"]).Values("name")))}}, + "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("name").Fold(), gremlingo.T__.V(p["vid3"]).Out("created").Values("name").Fold()))}}, + "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("software").Has("name", gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Out("created").Values("name").Fold(), gremlingo.T__.V(p["vid3"]).Out("created").Values("name").Fold()))}}, + "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Values("age").Fold(), gremlingo.T__.V().Has("name", "lop").In("created").Values("age").Fold()))}}, + "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE("knows").Filter(gremlingo.T__.InV().Has("name", gremlingo.P.Within(gremlingo.T__.V().Has("name", "lop").In("created").Values("name").Fold(), gremlingo.T__.V().Has("name", "ripple").In("created").Values("name").Fold())))}}, "g_V_properties_hasValueXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil)}}, "g_V_properties_hasValueXnull_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, nil)}}, "g_V_properties_hasValueXnull_joshX_value": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Properties().HasValue(nil, "josh").Value()}}, @@ -513,6 +552,26 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gte(p["xx1"])).Is(gremlingo.P.Lt(p["xx2"]))}}, "g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.In("created").Count().Is(1)).Values("name")}}, "g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.In("created").Count().Is(gremlingo.P.Gte(2))).Values("name")}}, + "g_V_valuesXageX_isXVXvid1X_valuesXageXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.V(p["vid1"]).Values("age"))}}, + "g_V_valuesXnameX_isXVXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Is(gremlingo.T__.V(p["vid1"]).Values("name"))}}, + "g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}}, + "g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Lt(gremlingo.T__.V(p["vid3"]).Values("age")))}}, + "g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Neq(gremlingo.T__.V(p["vid4"]).Values("age")))}}, + "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age").Fold()))}}, + "g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.T__.V(p["vid1"]).Values("nonexistent"))}}, + "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.T__.Is(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age"))), gremlingo.T__.Constant("older than marko"), gremlingo.T__.Constant("not older"))}}, + "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Values("age").Choose(gremlingo.T__.Is(gremlingo.P.Gte(gremlingo.T__.V().HasLabel("person").Values("age").Mean())), gremlingo.T__.Constant("above average"), gremlingo.T__.Constant("below average"))}}, + "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().All(gremlingo.P.Gte(gremlingo.T__.V(p["vid2"]).Values("age")))}}, + "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().All(gremlingo.P.Gt(gremlingo.T__.V(p["vid2"]).Values("age")))}}, + "g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().Any(gremlingo.P.Eq(gremlingo.T__.V(p["vid3"]).Values("age")))}}, + "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(p["vid4"]).Values("age")))}}, + "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out("knows").Values("age").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(p["vid3"]).Values("age")))}}, + "g_injectXnullX_isXeqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}}, + "g_injectXmarkoX_isXV9999_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Is(gremlingo.T__.V(9999).Values("name"))}}, + "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("marko").Choose(gremlingo.T__.Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name"))), gremlingo.T__.Constant("matched"), gremlingo.T__.Constant("unmatched"))}}, + "g_injectXlistX_noneXeqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{"marko", "josh"}).None(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}}, + "g_V_hasXname_eqXV9999_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", gremlingo.P.Eq(gremlingo.T__.V(9999).Values("name")))}}, + "g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Is(gremlingo.P.Without(gremlingo.T__.V(p["vid1"]).Values("age"), gremlingo.T__.V(p["vid2"]).Values("age")))}}, "g_V_valuesXageX_noneXgtX32XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").None(gremlingo.P.Gt(32))}}, "g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.T__.Is(gremlingo.P.Gt(33))).Fold().None(gremlingo.P.Lte(33))}}, "g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().By(gremlingo.Order.Desc).Fold().None(gremlingo.P.Lt(10))}}, @@ -685,6 +744,13 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "get_g_V_whereXage_isXgt_30XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.Values("age").Is(gremlingo.P.Gt(30)))}}, "g_V_whereXlabel_isXsoftwareXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.Label().Is("software"))}}, "g_V_whereXlabel_isXpersonXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.T__.Label().Is("person"))}}, + "g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age")))}}, + "g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Lt(gremlingo.T__.V(p["vid3"]).Values("age")))}}, + "g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Eq(gremlingo.T__.V(p["vid1"]).Values("age")))}}, + "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Within(gremlingo.T__.V(p["vid1"]).Out("knows").Values("age").Fold()))}}, + "g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Where(gremlingo.P.Neq(gremlingo.T__.V(p["vid1"]).Values("name")))}}, + "g_V_valuesXageX_whereXeqXV9999_valuesXageXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.P.Eq(gremlingo.T__.V(9999).Values("age")))}}, + "g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Where(gremlingo.P.Gt(gremlingo.T__.V(p["vid1"]).Values("age"))).By("age").Values("name")}}, "g_withStrategiesXAdjacentToIncidentStrategyX_V": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.AdjacentToIncidentStrategy()).V()}}, "g_withoutStrategiesXAdjacentToIncidentStrategyX_V": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithoutStrategies(gremlingo.AdjacentToIncidentStrategy()).V()}}, "g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.AdjacentToIncidentStrategy()).V().Out().Count()}}, @@ -1749,6 +1815,16 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_V_localXoutE_foldX_unfold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.OutE().Fold()).Unfold()}}, "g_V_valueMap_unfold_mapXselectXkeysXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap().Unfold().Map(gremlingo.T__.Select(gremlingo.Column.Keys))}}, "g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Repeat(gremlingo.T__.Both().SimplePath()).Until(gremlingo.T__.HasId(p["vid6"])).Path().By("name").Unfold()}}, + "g_VXvid1X_id_VXidentityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Id().V(gremlingo.T__.Identity()).Values("name")}}, + "g_VXvid1_vid2X_id_VXidentityX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Id().V(gremlingo.T__.Identity()).Values("name")}}, + "g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Id().As("bookmark").V().Has("name", "josh").V(gremlingo.T__.Select("bookmark")).Values("name")}}, + "g_VXvid1X_VXoutXknowsX_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).V(gremlingo.T__.Out("knows").Id()).Values("name")}}, + "g_VXvid1X_EXoutE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).E(gremlingo.T__.OutE().Id())}}, + "g_injectX9999X_VXidentityX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(9999).V(gremlingo.T__.Identity())}}, + "g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE("knows").Filter(gremlingo.T__.InV().Has("name", "vadas")).Id().E(gremlingo.T__.Identity())}}, + "g_injectX9999X_EXidentityX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(9999).E(gremlingo.T__.Identity())}}, + "g_VXVXvid1X_idX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(gremlingo.T__.V(p["vid1"]).Id()).Values("name")}}, + "g_EXVXvid1X_outE_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(gremlingo.T__.V(p["vid1"]).OutE().Id())}}, "g_V_valueMap": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap()}}, "g_V_valueMapXtrueX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap(true)}}, "g_V_valueMap_withXtokensX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap().With(gremlingo.WithOptions.Tokens)}}, @@ -2070,6 +2146,16 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_injectX1_3_100_300X_list": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 3, 100, 300})}}, "g_injectX1_3_100_300X_set": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(gremlingo.NewSimpleSet(1, 3, 100, 300))}}, "g_injectX1_1X_set": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(gremlingo.NewSimpleSet(1, 1))}}, + "g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").AddV("person").Property("name", "josh").Property("age", 32).AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property("name", "ripple").Property("lang", "java")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property("alias", gremlingo.T__.V(p["vid1"]).Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("alias", "marko")}}, + "g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE("knows").From("marko").To(gremlingo.T__.V().Has("name", "vadas")).AddE("knows").From("marko").To("josh").AddE("created").From("marko").To("lop").AddE("created").From("josh").To("lop").AddE("created").From("josh").To("ripple").AddE("created").From("peter").To("lop")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("creatorCount", gremlingo.T__.V(p["vid1"]).In("created").Count())}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("creatorCount", int64(3))}}, + "g_VXvid1X_propertyXknownCount_outXknowsX_countX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property("name", "ripple").Property("lang", "java").AddE("knows").From("marko").To("vadas").AddE("knows").From("marko").To("josh")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("knownCount", gremlingo.T__.Out("knows").Count())}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("knownCount", int64(2))}}, + "g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE("knows").From("marko").To(gremlingo.T__.V().Has("name", "vadas")).AddE("knows").From("marko").To("josh").AddE("created").From("marko").To("lop").AddE("created").From("josh").To("lop").AddE("created").From("josh").To("ripple").AddE("created").From("peter").To("lop")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property("creator", gremlingo.T__.In("created").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("creator")}}, + "g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE("knows").From("marko").To("vadas").AddE("knows").From("marko").To("josh").AddE("created").From("marko").To("lop").AddE("created").From("josh").To("lop").AddE("created").From("josh").To("ripple").AddE("created").From("peter").To("lop")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property(gremlingo.T__.V(p["vid1"]).Project("friendCount", "softwareCreated").By(gremlingo.T__.Out("knows").Count()).By(gremlingo.T__.Out("created").Values("name")))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("friendCount", int64(2))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("softwareCreated", "lop")}}, + "g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property("name", "ripple").Property("lang", "java")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Property(gremlingo.T__.V(p["vid1"]).Project("originalName", "originalLabel").By(gremlingo.T__.Values("name")).By(gremlingo.T__.Label()))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Has("originalName", "marko")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid2"]).Has("originalLabel", "person")}}, + "g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property("name", "ripple").Property("lang", "java").AddE("knows").From("marko").To("vadas").AddE("knows").From("marko").To("josh")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.List, "friends", gremlingo.T__.Out("knows").Values("name"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("friends")}}, + "g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27).AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddE("created").From("josh").To("lop").AddE("created").From("josh").To("ripple")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.Set, "langs", gremlingo.T__.Out("created").Values("lang"))}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Properties("langs")}}, + "g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("person").Property("name", "peter").Property("age", 35).AddV("software").Property("name", "ripple").Property("lang", "java").AddE("knows").From("marko").To("vadas").AddE("knows").From("marko").To("josh")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.Cardinality.Single, "friend", gremlingo.T__.Out("knows").Values("name"))}}, + "g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Property(gremlingo.T__.V(p["vid1"]).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values("name")))}}, "g_io_readXkryoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.kryo").Read()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}}, "g_io_read_withXreader_gryoX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.kryo").With(gremlingo.IO.Reader, gremlingo.IO.Gryo).Read()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}}, "g_io_readXgraphsonX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Io("data/tinkerpop-modern.json").Read()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}}, diff --git a/gremlin-go/driver/gremlinlang.go b/gremlin-go/driver/gremlinlang.go index a08c6a7d31c..f070e521cab 100644 --- a/gremlin-go/driver/gremlinlang.go +++ b/gremlin-go/driver/gremlinlang.go @@ -444,7 +444,22 @@ func (gl *GremlinLang) translatePValue(operator string, values []interface{}) (s sb := strings.Builder{} sb.WriteString(operator + "(") - if len(values) > 1 && operator != "between" && operator != "inside" { + // Check if all values are traversals - if so, serialize as comma-separated args (no brackets) + // This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs + allTraversals := len(values) > 1 + if allTraversals { + for _, v := range values { + switch v.(type) { + case *Traversal, Traversal, *GraphTraversal, GraphTraversal: + // ok, it's a traversal + default: + allTraversals = false + break + } + } + } + + if len(values) > 1 && !allTraversals && operator != "between" && operator != "inside" { sb.WriteString("[") } @@ -459,7 +474,7 @@ func (gl *GremlinLang) translatePValue(operator string, values []interface{}) (s } } - if len(values) > 1 && operator != "between" && operator != "inside" { + if len(values) > 1 && !allTraversals && operator != "between" && operator != "inside" { sb.WriteString("]") } sb.WriteString(")") diff --git a/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts b/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts index 8cb11b125b7..0fe3fc9f604 100644 --- a/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts +++ b/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts @@ -488,7 +488,7 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { this.sb.push(')'); } - // ─── Traversal method overrides — handleGenerics ───────────────────────── + // ─── Traversal method overrides - handleGenerics ───────────────────────── visitTraversalMethod_asString_Scope(ctx: any): void { this.handleGenerics(ctx); } visitTraversalMethod_branch(ctx: any): void { this.handleGenerics(ctx); } @@ -560,7 +560,7 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { visitTraversalMethod_valueMap_boolean_String(ctx: any): void { this.handleGenerics(ctx); } visitTraversalMethod_values(ctx: any): void { this.handleGenerics(ctx); } - // ─── Traversal method overrides — handleLongArguments ──────────────────── + // ─── Traversal method overrides - handleLongArguments ──────────────────── visitTraversalMethod_limit_long(ctx: any): void { this.handleLongArguments(ctx); } visitTraversalMethod_limit_Scope_long(ctx: any): void { this.handleLongArguments(ctx); } @@ -834,6 +834,45 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { // ─── property ──────────────────────────────────────────────────────────── + visitTraversalMethod_property_Object(ctx: any): void { + // Property(null) is ambiguous with Property(ITraversal) - cast null to IDictionary to disambiguate + if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null && + ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) { + this.visit(ctx.getChild(0)); + this.sb.push('('); + this.sb.push('(IDictionary) '); + this.visit(ctx.genericMapNullableArgument()); + this.sb.push(')'); + return; + } + this.visitChildren(ctx); + } + + visitTraversalMethod_property_Cardinality_Object(ctx: any): void { + // Property(Cardinality, null) - cast null to IDictionary to disambiguate + if (ctx.genericMapNullableArgument().genericMapNullableLiteral() != null && + ctx.genericMapNullableArgument().genericMapNullableLiteral().nullLiteral() != null) { + this.visit(ctx.getChild(0)); + this.sb.push('('); + this.visit(ctx.traversalCardinality()); + this.sb.push(', '); + this.sb.push('(IDictionary) '); + this.visit(ctx.genericMapNullableArgument()); + this.sb.push(')'); + return; + } + this.visitChildren(ctx); + } + + visitTraversalMethod_property_Traversal(ctx: any): void { + // Property(ITraversal) - cast to ITraversal to disambiguate + this.visit(ctx.getChild(0)); + this.sb.push('('); + this.sb.push('(ITraversal) '); + this.visit(ctx.nestedTraversal()); + this.sb.push(')'); + } + visitTraversalMethod_property_Cardinality_Object_Object_Object(ctx: any): void { if (ctx.genericArgumentVarargs() == null || ctx.genericArgumentVarargs().getChildCount() === 0) { this.sb.push(capitalize(ctx.getChild(0).getText())); diff --git a/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts b/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts index 070a88fceb6..17a3b5ad724 100644 --- a/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts +++ b/gremlin-js/gremlin-javascript/lib/process/gremlin-lang.ts @@ -58,7 +58,14 @@ export default class GremlinLang { let result = p.operator + '('; if (Array.isArray(p.value)) { - result += '[' + p.value.map(v => this._argAsString(v)).join(',') + ']'; + // If all elements are traversals, serialize as comma-separated args (no brackets) + // This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs + const allTraversals = p.value.length > 0 && p.value.every((v: any) => v != null && typeof v.getGremlinLang === 'function'); + if (allTraversals) { + result += p.value.map((v: any) => this._argAsString(v)).join(','); + } else { + result += '[' + p.value.map((v: any) => this._argAsString(v)).join(',') + ']'; + } } else { result += this._argAsString(p.value); if (p.other !== undefined && p.other !== null) { @@ -99,7 +106,7 @@ export default class GremlinLang { if (arg === -Infinity) return '-Infinity'; if (!Number.isInteger(arg)) return String(arg) + 'D'; if (arg >= INT32_MIN && arg <= INT32_MAX) return String(arg); - // Outside safe integer range, values have lost precision and may exceed Java Long — emit as Double. + // Outside safe integer range, values have lost precision and may exceed Java Long - emit as Double. if (arg > Number.MAX_SAFE_INTEGER || arg < -Number.MAX_SAFE_INTEGER) return String(arg) + 'D'; return String(arg) + 'L'; } diff --git a/gremlin-js/gremlin-javascript/lib/process/traversal.ts b/gremlin-js/gremlin-javascript/lib/process/traversal.ts index 12404b80b39..ff9932e46e6 100644 --- a/gremlin-js/gremlin-javascript/lib/process/traversal.ts +++ b/gremlin-js/gremlin-javascript/lib/process/traversal.ts @@ -347,6 +347,9 @@ export class P { if (args.length === 1 && Array.isArray(args[0])) { return new P('within', args[0], null); } + if (args.length === 1 && args[0] != null && typeof args[0].getGremlinLang === 'function') { + return new P('within', args[0], null); + } return new P('within', args, null); } @@ -354,6 +357,9 @@ export class P { if (args.length === 1 && Array.isArray(args[0])) { return new P('without', args[0], null); } + if (args.length === 1 && args[0] != null && typeof args[0].getGremlinLang === 'function') { + return new P('without', args[0], null); + } return new P('without', args, null); } diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js index aef279b28a8..dbdbb02d558 100644 --- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js +++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js @@ -374,6 +374,23 @@ const gremlins = { g_injectX7X_anyXeqX7XX: [function({g}) { return g.inject(7).any(P.eq(7)) }], g_injectXnull_nullX_anyXeqXnullXX: [function({g}) { return g.inject([null, null]).any(P.eq(null)) }], g_injectX3_threeX_anyXeqX3XX: [function({g}) { return g.inject([3, "three"]).any(P.eq(3)) }], + g_V_hasXname_addVXxX_valuesXnameXX_rejected: [function({g}) { return g.V().has("name", __.addV("x").values("name")) }], + g_V_hasXname_V_drop_constantXxXX_rejected: [function({g}) { return g.V().has("name", __.V().drop().constant("x")) }], + g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected: [function({g}) { return g.V().has("name", __.V().map(__.addV("x")).values("name")) }], + g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected: [function({g}) { return g.V().has("name", P.eq(__.addV("x").values("name"))) }], + g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected: [function({g}) { return g.V().has("name", P.within(__.addV("x").values("name"))) }], + g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected: [function({g}) { return g.V().has("age", P.gt(__.addV("x").values("age"))) }], + g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected: [function({g}) { return g.V().values("age").is(__.addV("x").values("age")) }], + g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected: [function({g}) { return g.V().values("age").is(P.gt(__.addV("x").values("age"))) }], + g_V_VXaddVXxX_idX_rejected: [function({g}) { return g.V().V(__.addV("x").id()) }], + g_V_EXaddVXxX_idX_rejected: [function({g}) { return g.V().E(__.addV("x").id()) }], + g_VXaddVXxX_idX_rejected: [function({g}) { return g.V(__.addV("x").id()) }], + g_EXaddVXxX_idX_rejected: [function({g}) { return g.E(__.addV("x").id()) }], + g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected: [function({g}) { return g.V().property(__.V().map(__.drop()).project("x").by("name")) }], + g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected: [function({g}) { return g.V().property(__.addV("temp").project("k").by("name")) }], + g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("name")) }], + g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification: [function({g, vid1}) { return g.V().has("age", P.gt(__.V(vid1).values("age"))) }], + g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").id()).values("name") }], g_V_coinX1_0X: [function({g}) { return g.V().coin(1.0) }], g_V_coinX1X: [function({g}) { return g.V().coin(1) }], g_V_coinX0X: [function({g}) { return g.V().coin(0.0) }], @@ -533,6 +550,28 @@ const gremlins = { 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_hasNotXageX_name: [function({g}) { return g.V().hasNot("age").values("name") }], + g_V_hasXname_VXvid1X_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("name")) }], + g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).out("knows").values("name")) }], + g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX: [function({g, vid1}) { return g.V().has("age", __.V(vid1).out("knows").values("age")) }], + g_V_hasXname_VXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().has("name", __.V(vid1).values("nonexistent")) }], + g_V_hasXname_notXidentityXX: [function({g}) { return g.V().has("name", __.not(__.identity())) }], + g_V_hasXage_gtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().has("age", P.gt(__.V(vid1).values("age"))) }], + g_V_hasXage_lteXVXvid2X_valuesXageXXX: [function({g, vid2}) { return g.V().has("age", P.lte(__.V(vid2).values("age"))) }], + g_V_hasXage_neqXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().has("age", P.neq(__.V(vid3).values("age"))) }], + g_V_hasXname_eqXVXvid1X_valuesXnameXXX: [function({g, vid1}) { return g.V().has("name", P.eq(__.V(vid1).values("name"))) }], + g_V_hasXage_ltXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().has("age", P.lt(__.V(vid1).values("age"))) }], + g_V_hasXage_gteXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().has("age", P.gte(__.V(vid3).values("age"))) }], + g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("age", P.eq(__.V(vid1).values("nonexistent"))) }], + g_V_hasXlabel_VXvid1X_labelXX: [function({g, vid1}) { return g.V().has(T.label, __.V(vid1).label()) }], + g_V_hasXperson_name_VXvid1X_valuesXnameXX_age: [function({g, vid1}) { return g.V().has("person", "name", __.V(vid1).values("name")).values("age") }], + g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.constant("peter"))) }], + g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.constant("marko"))) }], + g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX: [function({g, vid1}) { return g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.V(vid1).values("nonexistent"))) }], + g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX: [function({g, vid3, vid2, vid1}) { return g.V().has("name", P.without(__.V(vid1).values("name"), __.V(vid2).values("name"), __.V(vid3).values("name"))) }], + g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.V(vid3).out("created").values("name").fold())) }], + g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX: [function({g, vid3, vid1}) { return g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name").fold(), __.V(vid3).out("created").values("name").fold())) }], + g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age").fold(), __.V().has("name", "lop").in_("created").values("age").fold())) }], + g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX: [function({g, vid1}) { return g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name", "lop").in_("created").values("name").fold(), __.V().has("name", "ripple").in_("created").values("name").fold()))) }], g_V_properties_hasValueXnullX: [function({g}) { return g.V().properties().hasValue(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() }], @@ -544,6 +583,26 @@ const gremlins = { g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX: [function({g, xx1, xx2}) { return g.V().values("age").is(P.gte(xx1)).is(P.lt(xx2)) }], g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX: [function({g}) { return g.V().where(__.in_("created").count().is(1)).values("name") }], g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX: [function({g}) { return g.V().where(__.in_("created").count().is(P.gte(2))).values("name") }], + g_V_valuesXageX_isXVXvid1X_valuesXageXX: [function({g, vid1}) { return g.V().values("age").is(__.V(vid1).values("age")) }], + g_V_valuesXnameX_isXVXvid1X_valuesXnameXX: [function({g, vid1}) { return g.V().values("name").is(__.V(vid1).values("name")) }], + g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.gt(__.V(vid1).values("age"))) }], + g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().values("age").is(P.lt(__.V(vid3).values("age"))) }], + g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX: [function({g, vid4}) { return g.V().values("age").is(P.neq(__.V(vid4).values("age"))) }], + g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age").fold())) }], + g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX: [function({g, vid1}) { return g.V().values("age").is(__.V(vid1).values("nonexistent")) }], + g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX: [function({g, vid1}) { return g.V().hasLabel("person").values("age").choose(__.is(P.gt(__.V(vid1).values("age"))), __.constant("older than marko"), __.constant("not older")) }], + g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX: [function({g}) { return g.V().hasLabel("person").values("age").choose(__.is(P.gte(__.V().hasLabel("person").values("age").mean())), __.constant("above average"), __.constant("below average")) }], + g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V(vid1).out("knows").values("age").fold().all(P.gte(__.V(vid2).values("age"))) }], + g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V(vid1).out("knows").values("age").fold().all(P.gt(__.V(vid2).values("age"))) }], + g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX: [function({g, vid3, vid1}) { return g.V(vid1).out("knows").values("age").fold().any(P.eq(__.V(vid3).values("age"))) }], + g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX: [function({g, vid4, vid1}) { return g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid4).values("age"))) }], + g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX: [function({g, vid3, vid1}) { return g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid3).values("age"))) }], + g_injectXnullX_isXeqXV9999_valuesXnameXXX: [function({g}) { return g.inject(null).is(P.eq(__.V(9999).values("name"))) }], + g_injectXmarkoX_isXV9999_valuesXnameXX: [function({g}) { return g.inject("marko").is(__.V(9999).values("name")) }], + g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX: [function({g}) { return g.inject("marko").choose(__.is(P.eq(__.V(9999).values("name"))), __.constant("matched"), __.constant("unmatched")) }], + g_injectXlistX_noneXeqXV9999_valuesXnameXXX: [function({g}) { return g.inject(["marko", "josh"]).none(P.eq(__.V(9999).values("name"))) }], + g_V_hasXname_eqXV9999_valuesXnameXXX: [function({g}) { return g.V().has("name", P.eq(__.V(9999).values("name"))) }], + g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX: [function({g, vid2, vid1}) { return g.V().values("age").is(P.without(__.V(vid1).values("age"), __.V(vid2).values("age"))) }], g_V_valuesXageX_noneXgtX32XX: [function({g}) { return g.V().values("age").none(P.gt(32)) }], g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX: [function({g}) { return g.V().values("age").where(__.is(P.gt(33))).fold().none(P.lte(33)) }], g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX: [function({g}) { return g.V().values("age").order().by(Order.desc).fold().none(P.lt(10)) }], @@ -716,6 +775,13 @@ const gremlins = { get_g_V_whereXage_isXgt_30XX: [function({g}) { return g.V().where(__.values("age").is(P.gt(30))) }], g_V_whereXlabel_isXsoftwareXX: [function({g}) { return g.V().where(__.label().is("software")) }], g_V_whereXlabel_isXpersonXX: [function({g}) { return g.V().where(__.label().is("person")) }], + g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.gt(__.V(vid1).values("age"))) }], + g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX: [function({g, vid3}) { return g.V().values("age").where(P.lt(__.V(vid3).values("age"))) }], + g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.eq(__.V(vid1).values("age"))) }], + g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX: [function({g, vid1}) { return g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age").fold())) }], + g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX: [function({g, vid1}) { return g.V().values("name").where(P.neq(__.V(vid1).values("name"))) }], + g_V_valuesXageX_whereXeqXV9999_valuesXageXXX: [function({g}) { return g.V().values("age").where(P.eq(__.V(9999).values("age"))) }], + g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX: [function({g, vid1}) { return g.V().where(P.gt(__.V(vid1).values("age"))).by("age").values("name") }], g_withStrategiesXAdjacentToIncidentStrategyX_V: [function({g}) { return g.withStrategies(new AdjacentToIncidentStrategy()).V() }], g_withoutStrategiesXAdjacentToIncidentStrategyX_V: [function({g}) { return g.withoutStrategies(AdjacentToIncidentStrategy).V() }], g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count: [function({g}) { return g.withStrategies(new AdjacentToIncidentStrategy()).V().out().count() }], @@ -1780,6 +1846,16 @@ const gremlins = { g_V_localXoutE_foldX_unfold: [function({g}) { return g.V().local(__.outE().fold()).unfold() }], g_V_valueMap_unfold_mapXselectXkeysXX: [function({g}) { return g.V().valueMap().unfold().map(__.select(Column.keys)) }], g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold: [function({g, vid6, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by("name").unfold() }], + g_VXvid1X_id_VXidentityX_name: [function({g, vid1}) { return g.V(vid1).id().V(__.identity()).values("name") }], + g_VXvid1_vid2X_id_VXidentityX_name: [function({g, vid2, vid1}) { return g.V(vid1, vid2).id().V(__.identity()).values("name") }], + g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name: [function({g, vid1}) { return g.V(vid1).id().as("bookmark").V().has("name", "josh").V(__.select("bookmark")).values("name") }], + g_VXvid1X_VXoutXknowsX_idX_name: [function({g, vid1}) { return g.V(vid1).V(__.out("knows").id()).values("name") }], + g_VXvid1X_EXoutE_idX: [function({g, vid1}) { return g.V(vid1).E(__.outE().id()) }], + g_injectX9999X_VXidentityX: [function({g}) { return g.inject(9999).V(__.identity()) }], + g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX: [function({g, vid1}) { return g.V(vid1).outE("knows").filter(__.inV().has("name", "vadas")).id().E(__.identity()) }], + g_injectX9999X_EXidentityX: [function({g}) { return g.inject(9999).E(__.identity()) }], + g_VXVXvid1X_idX_name: [function({g, vid1}) { return g.V(__.V(vid1).id()).values("name") }], + g_EXVXvid1X_outE_idX: [function({g, vid1}) { return g.E(__.V(vid1).outE().id()) }], g_V_valueMap: [function({g}) { return g.V().valueMap() }], g_V_valueMapXtrueX: [function({g}) { return g.V().valueMap(true) }], g_V_valueMap_withXtokensX: [function({g}) { return g.V().valueMap().with_(WithOptions.tokens) }], @@ -2101,6 +2177,16 @@ const gremlins = { g_injectX1_3_100_300X_list: [function({g}) { return g.inject([1, 3, 100, 300]) }], g_injectX1_3_100_300X_set: [function({g}) { return g.inject(new Set([1, 3, 100, 300])) }], g_injectX1_1X_set: [function({g}) { return g.inject(new Set([1, 1])) }], + g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX: [function({g, vid2, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").addV("person").property("name", "josh").property("age", 32).addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java") }, function({g, vid2, vid1}) { return g.V(vid2).property("alias", __.V(vid1).values("name")) }, function({g, vid2, vid1}) { return g.V().has("alias", "marko") }], + g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).as("peter").addV("software").property("name", "ripple").property("lang", "java").as("ripple").addE("knows").from_("marko").to(__.V().has("name", "vadas")).addE("knows").from_("marko").to("josh").addE("created").from_("marko").to("lop").addE("created").from_("josh").to("lop").addE("created").from_("josh").to("ripple").addE("created").from_("peter").to("lop") }, function({g, vid1}) { return g.V(vid1).property("creatorCount", __.V(vid1).in_("created").count()) }, function({g, vid1}) { return g.V().has("creatorCount", 3) }], + g_VXvid1X_propertyXknownCount_outXknowsX_countX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java").addE("knows").from_("marko").to("vadas").addE("knows").from_("marko").to("josh") }, function({g, vid1}) { return g.V(vid1).property("knownCount", __.out("knows").count()) }, function({g, vid1}) { return g.V().has("knownCount", 2) }], + g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).as("peter").addV("software").property("name", "ripple").property("lang", "java").as("ripple").addE("knows").from_("marko").to(__.V().has("name", "vadas")).addE("knows").from_("marko").to("josh").addE("created").from_("marko").to("lop").addE("created").from_("josh").to("lop").addE("created").from_("josh").to("ripple").addE("created").from_("peter").to("lop") }, function({g, vid1}) { return g.V(vid1).property("creator", __.in_("created").values("name")) }, function({g, vid1}) { return g.V().has("creator") }], + g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX: [function({g, vid2, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).as("peter").addV("software").property("name", "ripple").property("lang", "java").as("ripple").addE("knows").from_("marko").to("vadas").addE("knows").from_("marko").to("josh").addE("created").from_("marko").to("lop").addE("created").from_("josh").to("lop").addE("created").from_("josh").to("ripple").addE("created").from_("peter").to("lop") }, function({g, vid2, vid1}) { return g.V(vid2).property(__.V(vid1).project("friendCount", "softwareCreated").by(__.out("knows").count()).by(__.out("created").values("name"))) }, function({g, vid2, vid1}) { return g.V().has("friendCount", 2) }, function({g, vid2, vid1}) { return g.V().has("softwareCreated", "lop") }], + g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX: [function({g, vid2, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java") }, function({g, vid2, vid1}) { return g.V(vid2).property(__.V(vid1).project("originalName", "originalLabel").by(__.values("name")).by(__.label())) }, function({g, vid2, vid1}) { return g.V(vid2).has("originalName", "marko") }, function({g, vid2, vid1}) { return g.V(vid2).has("originalLabel", "person") }], + g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java").addE("knows").from_("marko").to("vadas").addE("knows").from_("marko").to("josh") }, function({g, vid1}) { return g.V(vid1).property(Cardinality.list, "friends", __.out("knows").values("name")) }, function({g, vid1}) { return g.V(vid1).properties("friends") }], + g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27).addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java").as("ripple").addE("created").from_("josh").to("lop").addE("created").from_("josh").to("ripple") }, function({g, vid1}) { return g.V(vid1).property(Cardinality.set, "langs", __.out("created").values("lang")) }, function({g, vid1}) { return g.V(vid1).properties("langs") }], + g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").addV("person").property("name", "josh").property("age", 32).as("josh").addV("person").property("name", "peter").property("age", 35).addV("software").property("name", "ripple").property("lang", "java").addE("knows").from_("marko").to("vadas").addE("knows").from_("marko").to("josh") }, function({g, vid1}) { return g.V(vid1).property(Cardinality.single, "friend", __.out("knows").values("name")) }], + g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29) }, function({g, vid1}) { return g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values("name"))) }], g_io_readXkryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], g_io_read_withXreader_gryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").with_(IO.reader, IO.gryo).read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], g_io_readXgraphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index fbe8d414048..65969c5d1d4 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -123,10 +123,12 @@ traversalSourceSpawnMethod_addV traversalSourceSpawnMethod_E : K_E LPAREN genericArgumentVarargs RPAREN + | K_E LPAREN nestedTraversal RPAREN ; traversalSourceSpawnMethod_V : K_V LPAREN genericArgumentVarargs RPAREN + | K_V LPAREN nestedTraversal RPAREN ; traversalSourceSpawnMethod_inject @@ -313,10 +315,12 @@ traversalMethod traversalMethod_V : K_V LPAREN genericArgumentVarargs RPAREN + | K_V LPAREN nestedTraversal RPAREN ; traversalMethod_E : K_E LPAREN genericArgumentVarargs RPAREN + | K_E LPAREN nestedTraversal RPAREN ; traversalMethod_addE @@ -547,10 +551,13 @@ traversalMethod_has : K_HAS LPAREN stringNullableLiteral RPAREN #traversalMethod_has_String | K_HAS LPAREN stringNullableLiteral COMMA genericArgument RPAREN #traversalMethod_has_String_Object | K_HAS LPAREN stringNullableLiteral COMMA traversalPredicate RPAREN #traversalMethod_has_String_P + | K_HAS LPAREN stringNullableLiteral COMMA nestedTraversal RPAREN #traversalMethod_has_String_Traversal | K_HAS LPAREN stringNullableArgument COMMA stringNullableLiteral COMMA genericArgument RPAREN #traversalMethod_has_String_String_Object | K_HAS LPAREN stringNullableArgument COMMA stringNullableLiteral COMMA traversalPredicate RPAREN #traversalMethod_has_String_String_P + | K_HAS LPAREN stringNullableArgument COMMA stringNullableLiteral COMMA nestedTraversal RPAREN #traversalMethod_has_String_String_Traversal | K_HAS LPAREN traversalT COMMA genericArgument RPAREN #traversalMethod_has_T_Object | K_HAS LPAREN traversalT COMMA traversalPredicate RPAREN #traversalMethod_has_T_P + | K_HAS LPAREN traversalT COMMA nestedTraversal RPAREN #traversalMethod_has_T_Traversal ; traversalMethod_hasId @@ -566,6 +573,7 @@ traversalMethod_hasKey traversalMethod_hasLabel : K_HASLABEL LPAREN traversalPredicate RPAREN #traversalMethod_hasLabel_P | K_HASLABEL LPAREN stringNullableArgument (COMMA stringNullableArgumentVarargs)? RPAREN #traversalMethod_hasLabel_String_String + | K_HASLABEL LPAREN nestedTraversal RPAREN #traversalMethod_hasLabel_Traversal ; traversalMethod_hasNot @@ -767,9 +775,12 @@ traversalMethod_properties traversalMethod_property : K_PROPERTY LPAREN traversalCardinality COMMA genericLiteral COMMA genericArgument (COMMA genericArgumentVarargs)? RPAREN #traversalMethod_property_Cardinality_Object_Object_Object + | K_PROPERTY LPAREN traversalCardinality COMMA genericLiteral COMMA nestedTraversal RPAREN #traversalMethod_property_Cardinality_Object_Traversal | K_PROPERTY LPAREN traversalCardinality COMMA genericMapNullableArgument RPAREN # traversalMethod_property_Cardinality_Object | K_PROPERTY LPAREN genericLiteral COMMA genericArgument (COMMA genericArgumentVarargs)? RPAREN #traversalMethod_property_Object_Object_Object + | K_PROPERTY LPAREN genericLiteral COMMA nestedTraversal RPAREN #traversalMethod_property_Object_Traversal | K_PROPERTY LPAREN genericMapNullableArgument RPAREN # traversalMethod_property_Object + | K_PROPERTY LPAREN nestedTraversal RPAREN #traversalMethod_property_Traversal ; traversalMethod_propertyMap @@ -1187,10 +1198,12 @@ traversalBiFunction traversalPredicate_eq : (K_P DOT K_EQ | K_EQ) LPAREN genericArgument RPAREN + | (K_P DOT K_EQ | K_EQ) LPAREN nestedTraversal RPAREN ; traversalPredicate_neq : (K_P DOT K_NEQ | K_NEQ) LPAREN genericArgument RPAREN + | (K_P DOT K_NEQ | K_NEQ) LPAREN nestedTraversal RPAREN ; traversalPredicate_typeOf @@ -1200,40 +1213,49 @@ traversalPredicate_typeOf traversalPredicate_lt : (K_P DOT K_LT | K_LT) LPAREN genericArgument RPAREN + | (K_P DOT K_LT | K_LT) LPAREN nestedTraversal RPAREN ; traversalPredicate_lte : (K_P DOT K_LTE | K_LTE) LPAREN genericArgument RPAREN + | (K_P DOT K_LTE | K_LTE) LPAREN nestedTraversal RPAREN ; traversalPredicate_gt : (K_P DOT K_GT | K_GT) LPAREN genericArgument RPAREN + | (K_P DOT K_GT | K_GT) LPAREN nestedTraversal RPAREN ; traversalPredicate_gte : (K_P DOT K_GTE | K_GTE) LPAREN genericArgument RPAREN + | (K_P DOT K_GTE | K_GTE) LPAREN nestedTraversal RPAREN ; traversalPredicate_inside : (K_P DOT K_INSIDE | K_INSIDE) LPAREN genericArgument COMMA genericArgument RPAREN + | (K_P DOT K_INSIDE | K_INSIDE) LPAREN nestedTraversal COMMA nestedTraversal RPAREN ; traversalPredicate_outside : (K_P DOT K_OUTSIDE | K_OUTSIDE) LPAREN genericArgument COMMA genericArgument RPAREN + | (K_P DOT K_OUTSIDE | K_OUTSIDE) LPAREN nestedTraversal COMMA nestedTraversal RPAREN ; traversalPredicate_between : (K_P DOT K_BETWEEN | K_BETWEEN) LPAREN genericArgument COMMA genericArgument RPAREN + | (K_P DOT K_BETWEEN | K_BETWEEN) LPAREN nestedTraversal COMMA nestedTraversal RPAREN ; traversalPredicate_within : (K_P DOT K_WITHIN | K_WITHIN) LPAREN RPAREN | (K_P DOT K_WITHIN | K_WITHIN) LPAREN genericArgumentVarargs RPAREN + | (K_P DOT K_WITHIN | K_WITHIN) LPAREN nestedTraversal RPAREN ; traversalPredicate_without : (K_P DOT K_WITHOUT | K_WITHOUT) LPAREN RPAREN | (K_P DOT K_WITHOUT | K_WITHOUT) LPAREN genericArgumentVarargs RPAREN + | (K_P DOT K_WITHOUT | K_WITHOUT) LPAREN nestedTraversal RPAREN ; traversalPredicate_not @@ -1242,26 +1264,32 @@ traversalPredicate_not traversalPredicate_containing : (K_TEXTP DOT K_CONTAINING | K_CONTAINING) LPAREN stringArgument RPAREN + | (K_TEXTP DOT K_CONTAINING | K_CONTAINING) LPAREN nestedTraversal RPAREN ; traversalPredicate_notContaining : (K_TEXTP DOT K_NOTCONTAINING | K_NOTCONTAINING) LPAREN stringArgument RPAREN + | (K_TEXTP DOT K_NOTCONTAINING | K_NOTCONTAINING) LPAREN nestedTraversal RPAREN ; traversalPredicate_startingWith : (K_TEXTP DOT K_STARTINGWITH | K_STARTINGWITH) LPAREN stringArgument RPAREN + | (K_TEXTP DOT K_STARTINGWITH | K_STARTINGWITH) LPAREN nestedTraversal RPAREN ; traversalPredicate_notStartingWith : (K_TEXTP DOT K_NOTSTARTINGWITH | K_NOTSTARTINGWITH) LPAREN stringArgument RPAREN + | (K_TEXTP DOT K_NOTSTARTINGWITH | K_NOTSTARTINGWITH) LPAREN nestedTraversal RPAREN ; traversalPredicate_endingWith : (K_TEXTP DOT K_ENDINGWITH | K_ENDINGWITH) LPAREN stringArgument RPAREN + | (K_TEXTP DOT K_ENDINGWITH | K_ENDINGWITH) LPAREN nestedTraversal RPAREN ; traversalPredicate_notEndingWith : (K_TEXTP DOT K_NOTENDINGWITH | K_NOTENDINGWITH) LPAREN stringArgument RPAREN + | (K_TEXTP DOT K_NOTENDINGWITH | K_NOTENDINGWITH) LPAREN nestedTraversal RPAREN ; traversalPredicate_regex diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py index cbc035ee2c8..a8d5465d397 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py @@ -359,6 +359,8 @@ def within(*args): return P("within", args[0]) elif len(args) == 1 and type(args[0]) == set: return P("within", list(args[0])) + elif len(args) == 1 and isinstance(args[0], Traversal): + return P("within", args[0]) else: return P("within", list(args)) @@ -368,6 +370,8 @@ def without(*args): return P("without", args[0]) elif len(args) == 1 and type(args[0]) == set: return P("without", list(args[0])) + elif len(args) == 1 and isinstance(args[0], Traversal): + return P("without", args[0]) else: return P("without", list(args)) @@ -990,13 +994,22 @@ def _process_p_value(self, p): c = 0 res = [str(p).split('(')[0] + '('] if isinstance(p.value, list): - res.append('[') - for v in p.value: - if c > 0: - res.append(',') - res.append(self._arg_as_string(v)) - c += 1 - res.append(']') + # If all elements are Traversals, serialize as comma-separated args (no brackets) + # This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs + if len(p.value) > 0 and all(isinstance(v, Traversal) for v in p.value): + for v in p.value: + if c > 0: + res.append(',') + res.append(self._arg_as_string(v)) + c += 1 + else: + res.append('[') + for v in p.value: + if c > 0: + res.append(',') + res.append(self._arg_as_string(v)) + c += 1 + res.append(']') else: res.append(self._arg_as_string(p.value)) if p.other is not None: diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py index 8dd5394e02f..b7057b9ebce 100644 --- a/gremlin-python/src/main/python/tests/feature/gremlin.py +++ b/gremlin-python/src/main/python/tests/feature/gremlin.py @@ -348,6 +348,23 @@ 'g_injectX7X_anyXeqX7XX': [(lambda g:g.inject(7).any_(P.eq(7)))], 'g_injectXnull_nullX_anyXeqXnullXX': [(lambda g:g.inject([None, None]).any_(P.eq(None)))], 'g_injectX3_threeX_anyXeqX3XX': [(lambda g:g.inject([3, 'three']).any_(P.eq(3)))], + 'g_V_hasXname_addVXxX_valuesXnameXX_rejected': [(lambda g:g.V().has('name', __.add_v('x').values('name')))], + 'g_V_hasXname_V_drop_constantXxXX_rejected': [(lambda g:g.V().has('name', __.V().drop().constant('x')))], + 'g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected': [(lambda g:g.V().has('name', __.V().map(__.add_v('x')).values('name')))], + 'g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected': [(lambda g:g.V().has('name', P.eq(__.add_v('x').values('name'))))], + 'g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected': [(lambda g:g.V().has('name', P.within(__.add_v('x').values('name'))))], + 'g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected': [(lambda g:g.V().has('age', P.gt(__.add_v('x').values('age'))))], + 'g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected': [(lambda g:g.V().values('age').is_(__.add_v('x').values('age')))], + 'g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected': [(lambda g:g.V().values('age').is_(P.gt(__.add_v('x').values('age'))))], + 'g_V_VXaddVXxX_idX_rejected': [(lambda g:g.V().V(__.add_v('x').id_()))], + 'g_V_EXaddVXxX_idX_rejected': [(lambda g:g.V().E(__.add_v('x').id_()))], + 'g_VXaddVXxX_idX_rejected': [(lambda g:g.V(__.add_v('x').id_()))], + 'g_EXaddVXxX_idX_rejected': [(lambda g:g.E(__.add_v('x').id_()))], + 'g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected': [(lambda g:g.V().property(__.V().map(__.drop()).project('x').by('name')))], + 'g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected': [(lambda g:g.V().property(__.add_v('temp').project('k').by('name')))], + 'g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('name')))], + 'g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification': [(lambda g, vid1=None:g.V().has('age', P.gt(__.V(vid1).values('age'))))], + 'g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').id_()).values('name'))], 'g_V_coinX1_0X': [(lambda g:g.V().coin(1.0))], 'g_V_coinX1X': [(lambda g:g.V().coin(1))], 'g_V_coinX0X': [(lambda g:g.V().coin(0.0))], @@ -507,6 +524,28 @@ 'g_E_hasXlabel_nullX': [(lambda g:g.E().has(T.label, None))], 'g_V_properties_hasLabelXnullX': [(lambda g:g.V().properties().has_label(None))], 'g_V_hasNotXageX_name': [(lambda g:g.V().has_not('age').values('name'))], + 'g_V_hasXname_VXvid1X_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('name')))], + 'g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).out('knows').values('name')))], + 'g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX': [(lambda g, vid1=None:g.V().has('age', __.V(vid1).out('knows').values('age')))], + 'g_V_hasXname_VXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().has('name', __.V(vid1).values('nonexistent')))], + 'g_V_hasXname_notXidentityXX': [(lambda g:g.V().has('name', __.not_(__.identity())))], + 'g_V_hasXage_gtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().has('age', P.gt(__.V(vid1).values('age'))))], + 'g_V_hasXage_lteXVXvid2X_valuesXageXXX': [(lambda g, vid2=None:g.V().has('age', P.lte(__.V(vid2).values('age'))))], + 'g_V_hasXage_neqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().has('age', P.neq(__.V(vid3).values('age'))))], + 'g_V_hasXname_eqXVXvid1X_valuesXnameXXX': [(lambda g, vid1=None:g.V().has('name', P.eq(__.V(vid1).values('name'))))], + 'g_V_hasXage_ltXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().has('age', P.lt(__.V(vid1).values('age'))))], + 'g_V_hasXage_gteXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().has('age', P.gte(__.V(vid3).values('age'))))], + 'g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('age', P.eq(__.V(vid1).values('nonexistent'))))], + 'g_V_hasXlabel_VXvid1X_labelXX': [(lambda g, vid1=None:g.V().has(T.label, __.V(vid1).label()))], + 'g_V_hasXperson_name_VXvid1X_valuesXnameXX_age': [(lambda g, vid1=None:g.V().has('person', 'name', __.V(vid1).values('name')).values('age'))], + 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.constant('peter'))))], + 'g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.constant('marko'))))], + 'g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX': [(lambda g, vid1=None:g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.V(vid1).values('nonexistent'))))], + 'g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX': [(lambda g, vid3=None,vid2=None,vid1=None:g.V().has('name', P.without(__.V(vid1).values('name'), __.V(vid2).values('name'), __.V(vid3).values('name'))))], + 'g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.V(vid3).out('created').values('name').fold())))], + 'g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX': [(lambda g, vid3=None,vid1=None:g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name').fold(), __.V(vid3).out('created').values('name').fold())))], + 'g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX': [(lambda g, vid1=None:g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age').fold(), __.V().has('name', 'lop').in_('created').values('age').fold())))], + 'g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX': [(lambda g, vid1=None:g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name').fold(), __.V().has('name', 'ripple').in_('created').values('name').fold()))))], 'g_V_properties_hasValueXnullX': [(lambda g:g.V().properties().has_value(None))], 'g_V_properties_hasValueXnull_nullX': [(lambda g:g.V().properties().has_value(None, None))], 'g_V_properties_hasValueXnull_joshX_value': [(lambda g:g.V().properties().has_value(None, 'josh').value())], @@ -518,6 +557,26 @@ 'g_V_valuesXageX_isXgte_29vaarX_isXlt_34varX': [(lambda g, xx1=None,xx2=None:g.V().values('age').is_(P.gte(xx1)).is_(P.lt(xx2)))], 'g_V_whereXinXcreatedX_count_isX1XX_valuesXnameX': [(lambda g:g.V().where(__.in_('created').count().is_(1)).values('name'))], 'g_V_whereXinXcreatedX_count_isXgte_2XX_valuesXnameX': [(lambda g:g.V().where(__.in_('created').count().is_(P.gte(2))).values('name'))], + 'g_V_valuesXageX_isXVXvid1X_valuesXageXX': [(lambda g, vid1=None:g.V().values('age').is_(__.V(vid1).values('age')))], + 'g_V_valuesXnameX_isXVXvid1X_valuesXnameXX': [(lambda g, vid1=None:g.V().values('name').is_(__.V(vid1).values('name')))], + 'g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.gt(__.V(vid1).values('age'))))], + 'g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().values('age').is_(P.lt(__.V(vid3).values('age'))))], + 'g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX': [(lambda g, vid4=None:g.V().values('age').is_(P.neq(__.V(vid4).values('age'))))], + 'g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age').fold())))], + 'g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX': [(lambda g, vid1=None:g.V().values('age').is_(__.V(vid1).values('nonexistent')))], + 'g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX': [(lambda g, vid1=None:g.V().has_label('person').values('age').choose(__.is_(P.gt(__.V(vid1).values('age'))), __.constant('older than marko'), __.constant('not older')))], + 'g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX': [(lambda g:g.V().has_label('person').values('age').choose(__.is_(P.gte(__.V().has_label('person').values('age').mean())), __.constant('above average'), __.constant('below average')))], + 'g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out('knows').values('age').fold().all_(P.gte(__.V(vid2).values('age'))))], + 'g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V(vid1).out('knows').values('age').fold().all_(P.gt(__.V(vid2).values('age'))))], + 'g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None,vid1=None:g.V(vid1).out('knows').values('age').fold().any_(P.eq(__.V(vid3).values('age'))))], + 'g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX': [(lambda g, vid4=None,vid1=None:g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid4).values('age'))))], + 'g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX': [(lambda g, vid3=None,vid1=None:g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid3).values('age'))))], + 'g_injectXnullX_isXeqXV9999_valuesXnameXXX': [(lambda g:g.inject(None).is_(P.eq(__.V(9999).values('name'))))], + 'g_injectXmarkoX_isXV9999_valuesXnameXX': [(lambda g:g.inject('marko').is_(__.V(9999).values('name')))], + 'g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX': [(lambda g:g.inject('marko').choose(__.is_(P.eq(__.V(9999).values('name'))), __.constant('matched'), __.constant('unmatched')))], + 'g_injectXlistX_noneXeqXV9999_valuesXnameXXX': [(lambda g:g.inject(['marko', 'josh']).none(P.eq(__.V(9999).values('name'))))], + 'g_V_hasXname_eqXV9999_valuesXnameXXX': [(lambda g:g.V().has('name', P.eq(__.V(9999).values('name'))))], + 'g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX': [(lambda g, vid2=None,vid1=None:g.V().values('age').is_(P.without(__.V(vid1).values('age'), __.V(vid2).values('age'))))], 'g_V_valuesXageX_noneXgtX32XX': [(lambda g:g.V().values('age').none(P.gt(32)))], 'g_V_valuesXageX_whereXisXP_gtX33XXX_fold_noneXlteX33XX': [(lambda g:g.V().values('age').where(__.is_(P.gt(33))).fold().none(P.lte(33)))], 'g_V_valuesXageX_order_byXdescX_fold_noneXltX10XX': [(lambda g:g.V().values('age').order().by(Order.desc).fold().none(P.lt(10)))], @@ -690,6 +749,13 @@ 'get_g_V_whereXage_isXgt_30XX': [(lambda g:g.V().where(__.values('age').is_(P.gt(30))))], 'g_V_whereXlabel_isXsoftwareXX': [(lambda g:g.V().where(__.label().is_('software')))], 'g_V_whereXlabel_isXpersonXX': [(lambda g:g.V().where(__.label().is_('person')))], + 'g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.gt(__.V(vid1).values('age'))))], + 'g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX': [(lambda g, vid3=None:g.V().values('age').where(P.lt(__.V(vid3).values('age'))))], + 'g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.eq(__.V(vid1).values('age'))))], + 'g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX': [(lambda g, vid1=None:g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age').fold())))], + 'g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX': [(lambda g, vid1=None:g.V().values('name').where(P.neq(__.V(vid1).values('name'))))], + 'g_V_valuesXageX_whereXeqXV9999_valuesXageXXX': [(lambda g:g.V().values('age').where(P.eq(__.V(9999).values('age'))))], + 'g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX': [(lambda g, vid1=None:g.V().where(P.gt(__.V(vid1).values('age'))).by('age').values('name'))], 'g_withStrategiesXAdjacentToIncidentStrategyX_V': [(lambda g:g.with_strategies(AdjacentToIncidentStrategy()).V())], 'g_withoutStrategiesXAdjacentToIncidentStrategyX_V': [(lambda g:g.without_strategies(AdjacentToIncidentStrategy).V())], 'g_withStrategiesXAdjacentToIncidentStrategyX_V_out_count': [(lambda g:g.with_strategies(AdjacentToIncidentStrategy()).V().out().count())], @@ -1754,6 +1820,16 @@ 'g_V_localXoutE_foldX_unfold': [(lambda g:g.V().local(__.out_e().fold()).unfold())], 'g_V_valueMap_unfold_mapXselectXkeysXX': [(lambda g:g.V().value_map().unfold().map(__.select(Column.keys)))], 'g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold': [(lambda g, vid6=None,vid1=None:g.V(vid1).repeat(__.both().simple_path()).until(__.has_id(vid6)).path().by('name').unfold())], + 'g_VXvid1X_id_VXidentityX_name': [(lambda g, vid1=None:g.V(vid1).id_().V(__.identity()).values('name'))], + 'g_VXvid1_vid2X_id_VXidentityX_name': [(lambda g, vid2=None,vid1=None:g.V(vid1, vid2).id_().V(__.identity()).values('name'))], + 'g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name': [(lambda g, vid1=None:g.V(vid1).id_().as_('bookmark').V().has('name', 'josh').V(__.select('bookmark')).values('name'))], + 'g_VXvid1X_VXoutXknowsX_idX_name': [(lambda g, vid1=None:g.V(vid1).V(__.out('knows').id_()).values('name'))], + 'g_VXvid1X_EXoutE_idX': [(lambda g, vid1=None:g.V(vid1).E(__.out_e().id_()))], + 'g_injectX9999X_VXidentityX': [(lambda g:g.inject(9999).V(__.identity()))], + 'g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX': [(lambda g, vid1=None:g.V(vid1).out_e('knows').filter_(__.in_v().has('name', 'vadas')).id_().E(__.identity()))], + 'g_injectX9999X_EXidentityX': [(lambda g:g.inject(9999).E(__.identity()))], + 'g_VXVXvid1X_idX_name': [(lambda g, vid1=None:g.V(__.V(vid1).id_()).values('name'))], + 'g_EXVXvid1X_outE_idX': [(lambda g, vid1=None:g.E(__.V(vid1).out_e().id_()))], 'g_V_valueMap': [(lambda g:g.V().value_map())], 'g_V_valueMapXtrueX': [(lambda g:g.V().value_map(True))], 'g_V_valueMap_withXtokensX': [(lambda g:g.V().value_map().with_(WithOptions.tokens))], @@ -2075,6 +2151,16 @@ 'g_injectX1_3_100_300X_list': [(lambda g:g.inject([1, 3, 100, 300]))], 'g_injectX1_3_100_300X_set': [(lambda g:g.inject({1, 3, 100, 300}))], 'g_injectX1_1X_set': [(lambda g:g.inject({1, 1}))], + 'g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX': [(lambda g, vid2=None,vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')), (lambda g, vid2=None,vid1=None:g.V(vid2).property('alias', __.V(vid1).values('name'))), (lambda g, vid2=None,vid1=None:g.V().has('alias', 'marko'))], + 'g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').from_('marko').to(__.V().has('name', 'vadas')).add_e('knows').from_('marko').to('josh').add_e('created').from_('marko').to('lop').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple').add_e('created').from_('peter').to('lop')), (lambda g, vid1=None:g.V(vid1).property('creatorCount', __.V(vid1).in_('created').count())), (lambda g, vid1=None:g.V().has('creatorCount', long(3)))], + 'g_VXvid1X_propertyXknownCount_outXknowsX_countX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh')), (lambda g, vid1=None:g.V(vid1).property('knownCount', __.out('knows').count())), (lambda g, vid1=None:g.V().has('knownCount', long(2)))], + 'g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').from_('marko').to(__.V().has('name', 'vadas')).add_e('knows').from_('marko').to('josh').add_e('created').from_('marko').to('lop').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple').add_e('created').from_('peter').to('lop')), (lambda g, vid1=None:g.V(vid1).property('creator', __.in_('created').values('name'))), (lambda g, vid1=None:g.V().has('creator'))], + 'g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX': [(lambda g, vid2=None,vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh').add_e('created').from_('marko').to('lop').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple').add_e('created').from_('peter').to('lop')), (lambda g, vid2=None,vid1=None:g.V(vid2).property(__.V(vid1).project('friendCount', 'softwareCreated').by(__.out('knows').count()).by(__.out('created').values('name')))), (lambda g, vid2=None,vid1=None:g.V().has('friendCount', long(2))), (lambda g, vid2=None,vid1=None:g.V().has('softwareCreated', 'lop'))], + 'g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX': [(lambda g, vid2=None,vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')), (lambda g, vid2=None,vid1=None:g.V(vid2).property(__.V(vid1).project('originalName', 'originalLabel').by(__.values('name')).by(__.label()))), (lambda g, vid2=None,vid1=None:g.V(vid2).has('originalName', 'marko')), (lambda g, vid2=None,vid1=None:g.V(vid2).has('originalLabel', 'person'))], + 'g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh')), (lambda g, vid1=None:g.V(vid1).property(Cardinality.list_, 'friends', __.out('knows').values('name'))), (lambda g, vid1=None:g.V(vid1).properties('friends'))], + 'g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple')), (lambda g, vid1=None:g.V(vid1).property(Cardinality.set_, 'langs', __.out('created').values('lang'))), (lambda g, vid1=None:g.V(vid1).properties('langs'))], + 'g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh')), (lambda g, vid1=None:g.V(vid1).property(Cardinality.single, 'friend', __.out('knows').values('name')))], + 'g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29)), (lambda g, vid1=None:g.V(vid1).property(__.V(vid1).group().by(__.id_()).by(__.values('name'))))], 'g_io_readXkryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').read()), (lambda g:g.V()), (lambda g:g.E())], 'g_io_read_withXreader_gryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').with_(IO.reader, IO.gryo).read()), (lambda g:g.V()), (lambda g:g.E())], 'g_io_readXgraphsonX': [(lambda g:g.io('data/tinkerpop-modern.json').read()), (lambda g:g.V()), (lambda g:g.E())], diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json index 3c9c17c495a..64e585b07c2 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json @@ -6295,6 +6295,295 @@ } ] }, + { + "scenario": "g_V_hasXname_addVXxX_valuesXnameXX_rejected", + "traversals": [ + { + "original": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))", + "language": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))", + "canonical": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))", + "anonymized": "g.V().has(string0, __.addV(string1).values(string0))", + "dotnet": "g.V().Has(\"name\", __.AddV((string) \"x\").Values(\"name\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.AddV(\"x\").Values(\"name\"))", + "groovy": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))", + "java": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))", + "javascript": "g.V().has(\"name\", __.addV(\"x\").values(\"name\"))", + "python": "g.V().has('name', __.add_v('x').values('name'))" + } + ] + }, + { + "scenario": "g_V_hasXname_V_drop_constantXxXX_rejected", + "traversals": [ + { + "original": "g.V().has(\"name\", __.V().drop().constant(\"x\"))", + "language": "g.V().has(\"name\", __.V().drop().constant(\"x\"))", + "canonical": "g.V().has(\"name\", __.V().drop().constant(\"x\"))", + "anonymized": "g.V().has(string0, __.V().drop().constant(string1))", + "dotnet": "g.V().Has(\"name\", __.V().Drop().Constant(\"x\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.V().Drop().Constant(\"x\"))", + "groovy": "g.V().has(\"name\", __.V().drop().constant(\"x\"))", + "java": "g.V().has(\"name\", __.V().drop().constant(\"x\"))", + "javascript": "g.V().has(\"name\", __.V().drop().constant(\"x\"))", + "python": "g.V().has('name', __.V().drop().constant('x'))" + } + ] + }, + { + "scenario": "g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected", + "traversals": [ + { + "original": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))", + "language": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))", + "canonical": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))", + "anonymized": "g.V().has(string0, __.V().map(__.addV(string1)).values(string0))", + "dotnet": "g.V().Has(\"name\", __.V().Map(__.AddV((string) \"x\")).Values(\"name\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.V().Map(gremlingo.T__.AddV(\"x\")).Values(\"name\"))", + "groovy": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))", + "java": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))", + "javascript": "g.V().has(\"name\", __.V().map(__.addV(\"x\")).values(\"name\"))", + "python": "g.V().has('name', __.V().map(__.add_v('x')).values('name'))" + } + ] + }, + { + "scenario": "g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected", + "traversals": [ + { + "original": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))", + "language": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))", + "canonical": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))", + "anonymized": "g.V().has(string0, P.eq(__.addV(string1).values(string0)))", + "dotnet": "g.V().Has(\"name\", P.Eq(__.AddV((string) \"x\").Values(\"name\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Eq(gremlingo.T__.AddV(\"x\").Values(\"name\")))", + "groovy": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))", + "java": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))", + "javascript": "g.V().has(\"name\", P.eq(__.addV(\"x\").values(\"name\")))", + "python": "g.V().has('name', P.eq(__.add_v('x').values('name')))" + } + ] + }, + { + "scenario": "g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected", + "traversals": [ + { + "original": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))", + "language": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))", + "canonical": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))", + "anonymized": "g.V().has(string0, P.within(__.addV(string1).values(string0)))", + "dotnet": "g.V().Has(\"name\", P.Within(__.AddV((string) \"x\").Values(\"name\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.AddV(\"x\").Values(\"name\")))", + "groovy": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))", + "java": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))", + "javascript": "g.V().has(\"name\", P.within(__.addV(\"x\").values(\"name\")))", + "python": "g.V().has('name', P.within(__.add_v('x').values('name')))" + } + ] + }, + { + "scenario": "g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected", + "traversals": [ + { + "original": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))", + "language": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))", + "canonical": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))", + "anonymized": "g.V().has(string0, P.gt(__.addV(string1).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Gt(__.AddV((string) \"x\").Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Gt(gremlingo.T__.AddV(\"x\").Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))", + "java": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))", + "javascript": "g.V().has(\"age\", P.gt(__.addV(\"x\").values(\"age\")))", + "python": "g.V().has('age', P.gt(__.add_v('x').values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected", + "traversals": [ + { + "original": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))", + "language": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))", + "canonical": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))", + "anonymized": "g.V().values(string0).is(__.addV(string1).values(string0))", + "dotnet": "g.V().Values(\"age\").Is(__.AddV((string) \"x\").Values(\"age\"))", + "go": "g.V().Values(\"age\").Is(gremlingo.T__.AddV(\"x\").Values(\"age\"))", + "groovy": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))", + "java": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))", + "javascript": "g.V().values(\"age\").is(__.addV(\"x\").values(\"age\"))", + "python": "g.V().values('age').is_(__.add_v('x').values('age'))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected", + "traversals": [ + { + "original": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))", + "language": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))", + "canonical": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))", + "anonymized": "g.V().values(string0).is(P.gt(__.addV(string1).values(string0)))", + "dotnet": "g.V().Values(\"age\").Is(P.Gt(__.AddV((string) \"x\").Values(\"age\")))", + "go": "g.V().Values(\"age\").Is(gremlingo.P.Gt(gremlingo.T__.AddV(\"x\").Values(\"age\")))", + "groovy": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))", + "java": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))", + "javascript": "g.V().values(\"age\").is(P.gt(__.addV(\"x\").values(\"age\")))", + "python": "g.V().values('age').is_(P.gt(__.add_v('x').values('age')))" + } + ] + }, + { + "scenario": "g_V_VXaddVXxX_idX_rejected", + "traversals": [ + { + "original": "g.V().V(__.addV(\"x\").id())", + "language": "g.V().V(__.addV(\"x\").id())", + "canonical": "g.V().V(__.addV(\"x\").id())", + "anonymized": "g.V().V(__.addV(string0).id())", + "dotnet": "g.V().V(__.AddV((string) \"x\").Id())", + "go": "g.V().V(gremlingo.T__.AddV(\"x\").Id())", + "groovy": "g.V().V(__.addV(\"x\").id())", + "java": "g.V().V(__.addV(\"x\").id())", + "javascript": "g.V().V(__.addV(\"x\").id())", + "python": "g.V().V(__.add_v('x').id_())" + } + ] + }, + { + "scenario": "g_V_EXaddVXxX_idX_rejected", + "traversals": [ + { + "original": "g.V().E(__.addV(\"x\").id())", + "language": "g.V().E(__.addV(\"x\").id())", + "canonical": "g.V().E(__.addV(\"x\").id())", + "anonymized": "g.V().E(__.addV(string0).id())", + "dotnet": "g.V().E(__.AddV((string) \"x\").Id())", + "go": "g.V().E(gremlingo.T__.AddV(\"x\").Id())", + "groovy": "g.V().E(__.addV(\"x\").id())", + "java": "g.V().E(__.addV(\"x\").id())", + "javascript": "g.V().E(__.addV(\"x\").id())", + "python": "g.V().E(__.add_v('x').id_())" + } + ] + }, + { + "scenario": "g_VXaddVXxX_idX_rejected", + "traversals": [ + { + "original": "g.V(__.addV(\"x\").id())", + "language": "g.V(__.addV(\"x\").id())", + "canonical": "g.V(__.addV(\"x\").id())", + "anonymized": "g.V(__.addV(string0).id())", + "dotnet": "g.V(__.AddV((string) \"x\").Id())", + "go": "g.V(gremlingo.T__.AddV(\"x\").Id())", + "groovy": "g.V(__.addV(\"x\").id())", + "java": "g.V(__.addV(\"x\").id())", + "javascript": "g.V(__.addV(\"x\").id())", + "python": "g.V(__.add_v('x').id_())" + } + ] + }, + { + "scenario": "g_EXaddVXxX_idX_rejected", + "traversals": [ + { + "original": "g.E(__.addV(\"x\").id())", + "language": "g.E(__.addV(\"x\").id())", + "canonical": "g.E(__.addV(\"x\").id())", + "anonymized": "g.E(__.addV(string0).id())", + "dotnet": "g.E(__.AddV((string) \"x\").Id())", + "go": "g.E(gremlingo.T__.AddV(\"x\").Id())", + "groovy": "g.E(__.addV(\"x\").id())", + "java": "g.E(__.addV(\"x\").id())", + "javascript": "g.E(__.addV(\"x\").id())", + "python": "g.E(__.add_v('x').id_())" + } + ] + }, + { + "scenario": "g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected", + "traversals": [ + { + "original": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))", + "language": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))", + "canonical": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))", + "anonymized": "g.V().property(__.V().map(__.drop()).project(string0).by(string1))", + "dotnet": "g.V().Property((ITraversal) __.V().Map(__.Drop()).Project(\"x\").By(\"name\"))", + "go": "g.V().Property(gremlingo.T__.V().Map(gremlingo.T__.Drop()).Project(\"x\").By(\"name\"))", + "groovy": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))", + "java": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))", + "javascript": "g.V().property(__.V().map(__.drop()).project(\"x\").by(\"name\"))", + "python": "g.V().property(__.V().map(__.drop()).project('x').by('name'))" + } + ] + }, + { + "scenario": "g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected", + "traversals": [ + { + "original": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))", + "language": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))", + "canonical": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))", + "anonymized": "g.V().property(__.addV(string0).project(string1).by(string2))", + "dotnet": "g.V().Property((ITraversal) __.AddV((string) \"temp\").Project(\"k\").By(\"name\"))", + "go": "g.V().Property(gremlingo.T__.AddV(\"temp\").Project(\"k\").By(\"name\"))", + "groovy": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))", + "java": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))", + "javascript": "g.V().property(__.addV(\"temp\").project(\"k\").by(\"name\"))", + "python": "g.V().property(__.add_v('temp').project('k').by('name'))" + } + ] + }, + { + "scenario": "g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification", + "traversals": [ + { + "original": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "language": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "canonical": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "anonymized": "g.V().has(string0, __.V(vid1).values(string0))", + "dotnet": "g.V().Has(\"name\", __.V(vid1).Values(\"name\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Values(\"name\"))", + "groovy": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "java": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "javascript": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "python": "g.V().has('name', __.V(vid1).values('name'))" + } + ] + }, + { + "scenario": "g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification", + "traversals": [ + { + "original": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "language": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "canonical": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "anonymized": "g.V().has(string0, P.gt(__.V(vid1).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Gt(__.V(vid1).Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "java": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "javascript": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "python": "g.V().has('age', P.gt(__.V(vid1).values('age')))" + } + ] + }, + { + "scenario": "g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification", + "traversals": [ + { + "original": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "language": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "canonical": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "anonymized": "g.V(vid1).V(__.out(string0).id()).values(string1)", + "dotnet": "g.V(vid1).V(__.Out(\"knows\").Id()).Values(\"name\")", + "go": "g.V(vid1).V(gremlingo.T__.Out(\"knows\").Id()).Values(\"name\")", + "groovy": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "java": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "javascript": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "python": "g.V(vid1).V(__.out('knows').id_()).values('name')" + } + ] + }, { "scenario": "g_V_coinX1_0X", "traversals": [ @@ -9262,6 +9551,380 @@ } ] }, + { + "scenario": "g_V_hasXname_VXvid1X_valuesXnameXX", + "traversals": [ + { + "original": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "language": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "canonical": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "anonymized": "g.V().has(string0, __.V(vid1).values(string0))", + "dotnet": "g.V().Has(\"name\", __.V(vid1).Values(\"name\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Values(\"name\"))", + "groovy": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "java": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "javascript": "g.V().has(\"name\", __.V(vid1).values(\"name\"))", + "python": "g.V().has('name', __.V(vid1).values('name'))" + } + ] + }, + { + "scenario": "g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX", + "traversals": [ + { + "original": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))", + "language": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))", + "canonical": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))", + "anonymized": "g.V().has(string0, __.V(vid1).out(string1).values(string0))", + "dotnet": "g.V().Has(\"name\", __.V(vid1).Out(\"knows\").Values(\"name\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\"))", + "groovy": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))", + "java": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))", + "javascript": "g.V().has(\"name\", __.V(vid1).out(\"knows\").values(\"name\"))", + "python": "g.V().has('name', __.V(vid1).out('knows').values('name'))" + } + ] + }, + { + "scenario": "g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX", + "traversals": [ + { + "original": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))", + "language": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))", + "canonical": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))", + "anonymized": "g.V().has(string0, __.V(vid1).out(string1).values(string0))", + "dotnet": "g.V().Has(\"age\", __.V(vid1).Out(\"knows\").Values(\"age\"))", + "go": "g.V().Has(\"age\", gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\"))", + "groovy": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))", + "java": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))", + "javascript": "g.V().has(\"age\", __.V(vid1).out(\"knows\").values(\"age\"))", + "python": "g.V().has('age', __.V(vid1).out('knows').values('age'))" + } + ] + }, + { + "scenario": "g_V_hasXname_VXvid1X_valuesXnonexistentXX", + "traversals": [ + { + "original": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))", + "language": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))", + "canonical": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))", + "anonymized": "g.V().has(string0, __.V(vid1).values(string1))", + "dotnet": "g.V().Has(\"name\", __.V(vid1).Values(\"nonexistent\"))", + "go": "g.V().Has(\"name\", gremlingo.T__.V(vid1).Values(\"nonexistent\"))", + "groovy": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))", + "java": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))", + "javascript": "g.V().has(\"name\", __.V(vid1).values(\"nonexistent\"))", + "python": "g.V().has('name', __.V(vid1).values('nonexistent'))" + } + ] + }, + { + "scenario": "g_V_hasXname_notXidentityXX", + "traversals": [ + { + "original": "g.V().has(\"name\", __.not(__.identity()))", + "language": "g.V().has(\"name\", __.not(__.identity()))", + "canonical": "g.V().has(\"name\", __.not(__.identity()))", + "anonymized": "g.V().has(string0, __.not(__.identity()))", + "dotnet": "g.V().Has(\"name\", __.Not(__.Identity()))", + "go": "g.V().Has(\"name\", gremlingo.T__.Not(gremlingo.T__.Identity()))", + "groovy": "g.V().has(\"name\", __.not(__.identity()))", + "java": "g.V().has(\"name\", __.not(__.identity()))", + "javascript": "g.V().has(\"name\", __.not(__.identity()))", + "python": "g.V().has('name', __.not_(__.identity()))" + } + ] + }, + { + "scenario": "g_V_hasXage_gtXVXvid1X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "language": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "canonical": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "anonymized": "g.V().has(string0, P.gt(__.V(vid1).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Gt(__.V(vid1).Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "java": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "javascript": "g.V().has(\"age\", P.gt(__.V(vid1).values(\"age\")))", + "python": "g.V().has('age', P.gt(__.V(vid1).values('age')))" + } + ] + }, + { + "scenario": "g_V_hasXage_lteXVXvid2X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))", + "language": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))", + "canonical": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))", + "anonymized": "g.V().has(string0, P.lte(__.V(vid2).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Lte(__.V(vid2).Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Lte(gremlingo.T__.V(vid2).Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))", + "java": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))", + "javascript": "g.V().has(\"age\", P.lte(__.V(vid2).values(\"age\")))", + "python": "g.V().has('age', P.lte(__.V(vid2).values('age')))" + } + ] + }, + { + "scenario": "g_V_hasXage_neqXVXvid3X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))", + "language": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))", + "canonical": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))", + "anonymized": "g.V().has(string0, P.neq(__.V(vid3).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Neq(__.V(vid3).Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Neq(gremlingo.T__.V(vid3).Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))", + "java": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))", + "javascript": "g.V().has(\"age\", P.neq(__.V(vid3).values(\"age\")))", + "python": "g.V().has('age', P.neq(__.V(vid3).values('age')))" + } + ] + }, + { + "scenario": "g_V_hasXname_eqXVXvid1X_valuesXnameXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))", + "language": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))", + "canonical": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))", + "anonymized": "g.V().has(string0, P.eq(__.V(vid1).values(string0)))", + "dotnet": "g.V().Has(\"name\", P.Eq(__.V(vid1).Values(\"name\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Eq(gremlingo.T__.V(vid1).Values(\"name\")))", + "groovy": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))", + "java": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))", + "javascript": "g.V().has(\"name\", P.eq(__.V(vid1).values(\"name\")))", + "python": "g.V().has('name', P.eq(__.V(vid1).values('name')))" + } + ] + }, + { + "scenario": "g_V_hasXage_ltXVXvid1X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))", + "language": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))", + "canonical": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))", + "anonymized": "g.V().has(string0, P.lt(__.V(vid1).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Lt(__.V(vid1).Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Lt(gremlingo.T__.V(vid1).Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))", + "java": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))", + "javascript": "g.V().has(\"age\", P.lt(__.V(vid1).values(\"age\")))", + "python": "g.V().has('age', P.lt(__.V(vid1).values('age')))" + } + ] + }, + { + "scenario": "g_V_hasXage_gteXVXvid3X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))", + "language": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))", + "canonical": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))", + "anonymized": "g.V().has(string0, P.gte(__.V(vid3).values(string0)))", + "dotnet": "g.V().Has(\"age\", P.Gte(__.V(vid3).Values(\"age\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Gte(gremlingo.T__.V(vid3).Values(\"age\")))", + "groovy": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))", + "java": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))", + "javascript": "g.V().has(\"age\", P.gte(__.V(vid3).values(\"age\")))", + "python": "g.V().has('age', P.gte(__.V(vid3).values('age')))" + } + ] + }, + { + "scenario": "g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX", + "traversals": [ + { + "original": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))", + "language": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))", + "canonical": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))", + "anonymized": "g.V().has(string0, P.eq(__.V(vid1).values(string1)))", + "dotnet": "g.V().Has(\"age\", P.Eq(__.V(vid1).Values(\"nonexistent\")))", + "go": "g.V().Has(\"age\", gremlingo.P.Eq(gremlingo.T__.V(vid1).Values(\"nonexistent\")))", + "groovy": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))", + "java": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))", + "javascript": "g.V().has(\"age\", P.eq(__.V(vid1).values(\"nonexistent\")))", + "python": "g.V().has('age', P.eq(__.V(vid1).values('nonexistent')))" + } + ] + }, + { + "scenario": "g_V_hasXlabel_VXvid1X_labelXX", + "traversals": [ + { + "original": "g.V().has(T.label, __.V(vid1).label())", + "language": "g.V().has(T.label, __.V(vid1).label())", + "canonical": "g.V().has(T.label, __.V(vid1).label())", + "anonymized": "g.V().has(T.label, __.V(vid1).label())", + "dotnet": "g.V().Has(T.Label, __.V(vid1).Label())", + "go": "g.V().Has(gremlingo.T.Label, gremlingo.T__.V(vid1).Label())", + "groovy": "g.V().has(T.label, __.V(vid1).label())", + "java": "g.V().has(T.label, __.V(vid1).label())", + "javascript": "g.V().has(T.label, __.V(vid1).label())", + "python": "g.V().has(T.label, __.V(vid1).label())" + } + ] + }, + { + "scenario": "g_V_hasXperson_name_VXvid1X_valuesXnameXX_age", + "traversals": [ + { + "original": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")", + "language": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")", + "canonical": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")", + "anonymized": "g.V().has(string0, string1, __.V(vid1).values(string1)).values(string2)", + "dotnet": "g.V().Has(\"person\", \"name\", __.V(vid1).Values(\"name\")).Values(\"age\")", + "go": "g.V().Has(\"person\", \"name\", gremlingo.T__.V(vid1).Values(\"name\")).Values(\"age\")", + "groovy": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")", + "java": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")", + "javascript": "g.V().has(\"person\", \"name\", __.V(vid1).values(\"name\")).values(\"age\")", + "python": "g.V().has('person', 'name', __.V(vid1).values('name')).values('age')" + } + ] + }, + { + "scenario": "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))", + "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))", + "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))", + "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0).fold(), __.constant(string2)))", + "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values(\"name\").Fold(), __.Constant(\"peter\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\").Fold(), gremlingo.T__.Constant(\"peter\")))", + "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))", + "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))", + "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.constant(\"peter\")))", + "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.constant('peter')))" + } + ] + }, + { + "scenario": "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))", + "language": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))", + "canonical": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))", + "anonymized": "g.V().has(string0, P.within(__.V(vid1).values(string1), __.constant(string2)))", + "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Values(\"nonexistent\"), __.Constant(\"marko\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"nonexistent\"), gremlingo.T__.Constant(\"marko\")))", + "groovy": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))", + "java": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))", + "javascript": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.constant(\"marko\")))", + "python": "g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.constant('marko')))" + } + ] + }, + { + "scenario": "g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))", + "language": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))", + "canonical": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))", + "anonymized": "g.V().has(string0, P.within(__.V(vid1).values(string1), __.V(vid1).values(string1)))", + "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Values(\"nonexistent\"), __.V(vid1).Values(\"nonexistent\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"nonexistent\"), gremlingo.T__.V(vid1).Values(\"nonexistent\")))", + "groovy": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))", + "java": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))", + "javascript": "g.V().has(\"name\", P.within(__.V(vid1).values(\"nonexistent\"), __.V(vid1).values(\"nonexistent\")))", + "python": "g.V().has('name', P.within(__.V(vid1).values('nonexistent'), __.V(vid1).values('nonexistent')))" + } + ] + }, + { + "scenario": "g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))", + "language": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))", + "canonical": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))", + "anonymized": "g.V().has(string0, P.without(__.V(vid1).values(string0), __.V(vid2).values(string0), __.V(vid3).values(string0)))", + "dotnet": "g.V().Has(\"name\", P.Without(__.V(vid1).Values(\"name\"), __.V(vid2).Values(\"name\"), __.V(vid3).Values(\"name\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Without(gremlingo.T__.V(vid1).Values(\"name\"), gremlingo.T__.V(vid2).Values(\"name\"), gremlingo.T__.V(vid3).Values(\"name\")))", + "groovy": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))", + "java": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))", + "javascript": "g.V().has(\"name\", P.without(__.V(vid1).values(\"name\"), __.V(vid2).values(\"name\"), __.V(vid3).values(\"name\")))", + "python": "g.V().has('name', P.without(__.V(vid1).values('name'), __.V(vid2).values('name'), __.V(vid3).values('name')))" + } + ] + }, + { + "scenario": "g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "language": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "canonical": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "anonymized": "g.V().has(string0, P.within(__.V(vid1).out(string1).values(string0).fold(), __.V(vid3).out(string2).values(string0).fold()))", + "dotnet": "g.V().Has(\"name\", P.Within(__.V(vid1).Out(\"knows\").Values(\"name\").Fold(), __.V(vid3).Out(\"created\").Values(\"name\").Fold()))", + "go": "g.V().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"name\").Fold(), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\").Fold()))", + "groovy": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "java": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "javascript": "g.V().has(\"name\", P.within(__.V(vid1).out(\"knows\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "python": "g.V().has('name', P.within(__.V(vid1).out('knows').values('name').fold(), __.V(vid3).out('created').values('name').fold()))" + } + ] + }, + { + "scenario": "g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX", + "traversals": [ + { + "original": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "language": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "canonical": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "anonymized": "g.V().hasLabel(string0).has(string1, P.without(__.V(vid1).out(string2).values(string1).fold(), __.V(vid3).out(string2).values(string1).fold()))", + "dotnet": "g.V().HasLabel(\"software\").Has(\"name\", P.Without(__.V(vid1).Out(\"created\").Values(\"name\").Fold(), __.V(vid3).Out(\"created\").Values(\"name\").Fold()))", + "go": "g.V().HasLabel(\"software\").Has(\"name\", gremlingo.P.Without(gremlingo.T__.V(vid1).Out(\"created\").Values(\"name\").Fold(), gremlingo.T__.V(vid3).Out(\"created\").Values(\"name\").Fold()))", + "groovy": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "java": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "javascript": "g.V().hasLabel(\"software\").has(\"name\", P.without(__.V(vid1).out(\"created\").values(\"name\").fold(), __.V(vid3).out(\"created\").values(\"name\").fold()))", + "python": "g.V().has_label('software').has('name', P.without(__.V(vid1).out('created').values('name').fold(), __.V(vid3).out('created').values('name').fold()))" + } + ] + }, + { + "scenario": "g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX", + "traversals": [ + { + "original": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\",\"lop\").in(\"created\").values(\"age\").fold()))", + "language": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))", + "canonical": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))", + "anonymized": "g.V().hasLabel(string0).values(string1).is(P.within(__.V(vid1).values(string1).fold(), __.V().has(string2, string3).in(string4).values(string1).fold()))", + "dotnet": "g.V().HasLabel(\"person\").Values(\"age\").Is(P.Within(__.V(vid1).Values(\"age\").Fold(), __.V().Has(\"name\", \"lop\").In(\"created\").Values(\"age\").Fold()))", + "go": "g.V().HasLabel(\"person\").Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Values(\"age\").Fold(), gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"age\").Fold()))", + "groovy": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))", + "java": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in(\"created\").values(\"age\").fold()))", + "javascript": "g.V().hasLabel(\"person\").values(\"age\").is(P.within(__.V(vid1).values(\"age\").fold(), __.V().has(\"name\", \"lop\").in_(\"created\").values(\"age\").fold()))", + "python": "g.V().has_label('person').values('age').is_(P.within(__.V(vid1).values('age').fold(), __.V().has('name', 'lop').in_('created').values('age').fold()))" + } + ] + }, + { + "scenario": "g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX", + "traversals": [ + { + "original": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\",\"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\",\"ripple\").in(\"created\").values(\"name\").fold())))", + "language": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))", + "canonical": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))", + "anonymized": "g.V(vid1).outE(string0).filter(__.inV().has(string1, P.within(__.V().has(string1, string2).in(string3).values(string1).fold(), __.V().has(string1, string4).in(string3).values(string1).fold())))", + "dotnet": "g.V(vid1).OutE(\"knows\").Filter(__.InV().Has(\"name\", P.Within(__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"name\").Fold(), __.V().Has(\"name\", \"ripple\").In(\"created\").Values(\"name\").Fold())))", + "go": "g.V(vid1).OutE(\"knows\").Filter(gremlingo.T__.InV().Has(\"name\", gremlingo.P.Within(gremlingo.T__.V().Has(\"name\", \"lop\").In(\"created\").Values(\"name\").Fold(), gremlingo.T__.V().Has(\"name\", \"ripple\").In(\"created\").Values(\"name\").Fold())))", + "groovy": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))", + "java": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in(\"created\").values(\"name\").fold())))", + "javascript": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", P.within(__.V().has(\"name\", \"lop\").in_(\"created\").values(\"name\").fold(), __.V().has(\"name\", \"ripple\").in_(\"created\").values(\"name\").fold())))", + "python": "g.V(vid1).out_e('knows').filter_(__.in_v().has('name', P.within(__.V().has('name', 'lop').in_('created').values('name').fold(), __.V().has('name', 'ripple').in_('created').values('name').fold())))" + } + ] + }, { "scenario": "g_V_properties_hasValueXnullX", "traversals": [ @@ -9449,6 +10112,346 @@ } ] }, + { + "scenario": "g_V_valuesXageX_isXVXvid1X_valuesXageXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))", + "language": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))", + "canonical": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))", + "anonymized": "g.V().values(string0).is(__.V(vid1).values(string0))", + "dotnet": "g.V().Values(\"age\").Is(__.V(vid1).Values(\"age\"))", + "go": "g.V().Values(\"age\").Is(gremlingo.T__.V(vid1).Values(\"age\"))", + "groovy": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))", + "java": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))", + "javascript": "g.V().values(\"age\").is(__.V(vid1).values(\"age\"))", + "python": "g.V().values('age').is_(__.V(vid1).values('age'))" + } + ] + }, + { + "scenario": "g_V_valuesXnameX_isXVXvid1X_valuesXnameXX", + "traversals": [ + { + "original": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))", + "language": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))", + "canonical": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))", + "anonymized": "g.V().values(string0).is(__.V(vid1).values(string0))", + "dotnet": "g.V().Values(\"name\").Is(__.V(vid1).Values(\"name\"))", + "go": "g.V().Values(\"name\").Is(gremlingo.T__.V(vid1).Values(\"name\"))", + "groovy": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))", + "java": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))", + "javascript": "g.V().values(\"name\").is(__.V(vid1).values(\"name\"))", + "python": "g.V().values('name').is_(__.V(vid1).values('name'))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))", + "language": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))", + "canonical": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))", + "anonymized": "g.V().values(string0).is(P.gt(__.V(vid1).values(string0)))", + "dotnet": "g.V().Values(\"age\").Is(P.Gt(__.V(vid1).Values(\"age\")))", + "go": "g.V().Values(\"age\").Is(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))", + "groovy": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))", + "java": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))", + "javascript": "g.V().values(\"age\").is(P.gt(__.V(vid1).values(\"age\")))", + "python": "g.V().values('age').is_(P.gt(__.V(vid1).values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))", + "language": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))", + "canonical": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))", + "anonymized": "g.V().values(string0).is(P.lt(__.V(vid3).values(string0)))", + "dotnet": "g.V().Values(\"age\").Is(P.Lt(__.V(vid3).Values(\"age\")))", + "go": "g.V().Values(\"age\").Is(gremlingo.P.Lt(gremlingo.T__.V(vid3).Values(\"age\")))", + "groovy": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))", + "java": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))", + "javascript": "g.V().values(\"age\").is(P.lt(__.V(vid3).values(\"age\")))", + "python": "g.V().values('age').is_(P.lt(__.V(vid3).values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))", + "language": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))", + "canonical": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))", + "anonymized": "g.V().values(string0).is(P.neq(__.V(vid4).values(string0)))", + "dotnet": "g.V().Values(\"age\").Is(P.Neq(__.V(vid4).Values(\"age\")))", + "go": "g.V().Values(\"age\").Is(gremlingo.P.Neq(gremlingo.T__.V(vid4).Values(\"age\")))", + "groovy": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))", + "java": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))", + "javascript": "g.V().values(\"age\").is(P.neq(__.V(vid4).values(\"age\")))", + "python": "g.V().values('age').is_(P.neq(__.V(vid4).values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "language": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "canonical": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "anonymized": "g.V().values(string0).is(P.within(__.V(vid1).out(string1).values(string0).fold()))", + "dotnet": "g.V().Values(\"age\").Is(P.Within(__.V(vid1).Out(\"knows\").Values(\"age\").Fold()))", + "go": "g.V().Values(\"age\").Is(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\").Fold()))", + "groovy": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "java": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "javascript": "g.V().values(\"age\").is(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "python": "g.V().values('age').is_(P.within(__.V(vid1).out('knows').values('age').fold()))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))", + "language": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))", + "canonical": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))", + "anonymized": "g.V().values(string0).is(__.V(vid1).values(string1))", + "dotnet": "g.V().Values(\"age\").Is(__.V(vid1).Values(\"nonexistent\"))", + "go": "g.V().Values(\"age\").Is(gremlingo.T__.V(vid1).Values(\"nonexistent\"))", + "groovy": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))", + "java": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))", + "javascript": "g.V().values(\"age\").is(__.V(vid1).values(\"nonexistent\"))", + "python": "g.V().values('age').is_(__.V(vid1).values('nonexistent'))" + } + ] + }, + { + "scenario": "g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX", + "traversals": [ + { + "original": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))", + "language": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))", + "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))", + "anonymized": "g.V().hasLabel(string0).values(string1).choose(__.is(P.gt(__.V(vid1).values(string1))), __.constant(string2), __.constant(string3))", + "dotnet": "g.V().HasLabel(\"person\").Values(\"age\").Choose(__.Is(P.Gt(__.V(vid1).Values(\"age\"))), __.Constant(\"older than marko\"), __.Constant(\"not older\"))", + "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.T__.Is(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\"))), gremlingo.T__.Constant(\"older than marko\"), gremlingo.T__.Constant(\"not older\"))", + "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))", + "java": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))", + "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gt(__.V(vid1).values(\"age\"))), __.constant(\"older than marko\"), __.constant(\"not older\"))", + "python": "g.V().has_label('person').values('age').choose(__.is_(P.gt(__.V(vid1).values('age'))), __.constant('older than marko'), __.constant('not older'))" + } + ] + }, + { + "scenario": "g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX", + "traversals": [ + { + "original": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))", + "language": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))", + "canonical": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))", + "anonymized": "g.V().hasLabel(string0).values(string1).choose(__.is(P.gte(__.V().hasLabel(string0).values(string1).mean())), __.constant(string2), __.constant(string3))", + "dotnet": "g.V().HasLabel(\"person\").Values(\"age\").Choose(__.Is(P.Gte(__.V().HasLabel(\"person\").Values(\"age\").Mean())), __.Constant(\"above average\"), __.Constant(\"below average\"))", + "go": "g.V().HasLabel(\"person\").Values(\"age\").Choose(gremlingo.T__.Is(gremlingo.P.Gte(gremlingo.T__.V().HasLabel(\"person\").Values(\"age\").Mean())), gremlingo.T__.Constant(\"above average\"), gremlingo.T__.Constant(\"below average\"))", + "groovy": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))", + "java": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))", + "javascript": "g.V().hasLabel(\"person\").values(\"age\").choose(__.is(P.gte(__.V().hasLabel(\"person\").values(\"age\").mean())), __.constant(\"above average\"), __.constant(\"below average\"))", + "python": "g.V().has_label('person').values('age').choose(__.is_(P.gte(__.V().has_label('person').values('age').mean())), __.constant('above average'), __.constant('below average'))" + } + ] + }, + { + "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX", + "traversals": [ + { + "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))", + "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))", + "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))", + "anonymized": "g.V(vid1).out(string0).values(string1).fold().all(P.gte(__.V(vid2).values(string1)))", + "dotnet": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().All(P.Gte(__.V(vid2).Values(\"age\")))", + "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().All(gremlingo.P.Gte(gremlingo.T__.V(vid2).Values(\"age\")))", + "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))", + "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))", + "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gte(__.V(vid2).values(\"age\")))", + "python": "g.V(vid1).out('knows').values('age').fold().all_(P.gte(__.V(vid2).values('age')))" + } + ] + }, + { + "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX", + "traversals": [ + { + "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))", + "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))", + "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))", + "anonymized": "g.V(vid1).out(string0).values(string1).fold().all(P.gt(__.V(vid2).values(string1)))", + "dotnet": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().All(P.Gt(__.V(vid2).Values(\"age\")))", + "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().All(gremlingo.P.Gt(gremlingo.T__.V(vid2).Values(\"age\")))", + "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))", + "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))", + "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().all(P.gt(__.V(vid2).values(\"age\")))", + "python": "g.V(vid1).out('knows').values('age').fold().all_(P.gt(__.V(vid2).values('age')))" + } + ] + }, + { + "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX", + "traversals": [ + { + "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))", + "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))", + "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))", + "anonymized": "g.V(vid1).out(string0).values(string1).fold().any(P.eq(__.V(vid3).values(string1)))", + "dotnet": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().Any(P.Eq(__.V(vid3).Values(\"age\")))", + "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().Any(gremlingo.P.Eq(gremlingo.T__.V(vid3).Values(\"age\")))", + "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))", + "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))", + "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().any(P.eq(__.V(vid3).values(\"age\")))", + "python": "g.V(vid1).out('knows').values('age').fold().any_(P.eq(__.V(vid3).values('age')))" + } + ] + }, + { + "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX", + "traversals": [ + { + "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))", + "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))", + "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))", + "anonymized": "g.V(vid1).out(string0).values(string1).fold().none(P.eq(__.V(vid4).values(string1)))", + "dotnet": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().None(P.Eq(__.V(vid4).Values(\"age\")))", + "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(vid4).Values(\"age\")))", + "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))", + "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))", + "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid4).values(\"age\")))", + "python": "g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid4).values('age')))" + } + ] + }, + { + "scenario": "g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX", + "traversals": [ + { + "original": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))", + "language": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))", + "canonical": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))", + "anonymized": "g.V(vid1).out(string0).values(string1).fold().none(P.eq(__.V(vid3).values(string1)))", + "dotnet": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().None(P.Eq(__.V(vid3).Values(\"age\")))", + "go": "g.V(vid1).Out(\"knows\").Values(\"age\").Fold().None(gremlingo.P.Eq(gremlingo.T__.V(vid3).Values(\"age\")))", + "groovy": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))", + "java": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))", + "javascript": "g.V(vid1).out(\"knows\").values(\"age\").fold().none(P.eq(__.V(vid3).values(\"age\")))", + "python": "g.V(vid1).out('knows').values('age').fold().none(P.eq(__.V(vid3).values('age')))" + } + ] + }, + { + "scenario": "g_injectXnullX_isXeqXV9999_valuesXnameXXX", + "traversals": [ + { + "original": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))", + "language": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))", + "canonical": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))", + "anonymized": "g.inject(object0).is(P.eq(__.V(number0).values(string0)))", + "dotnet": "g.Inject(null).Is(P.Eq(__.V(9999).Values(\"name\")))", + "go": "g.Inject(nil).Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")))", + "groovy": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))", + "java": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))", + "javascript": "g.inject(null).is(P.eq(__.V(9999).values(\"name\")))", + "python": "g.inject(None).is_(P.eq(__.V(9999).values('name')))" + } + ] + }, + { + "scenario": "g_injectXmarkoX_isXV9999_valuesXnameXX", + "traversals": [ + { + "original": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))", + "language": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))", + "canonical": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))", + "anonymized": "g.inject(string0).is(__.V(number0).values(string1))", + "dotnet": "g.Inject(\"marko\").Is(__.V(9999).Values(\"name\"))", + "go": "g.Inject(\"marko\").Is(gremlingo.T__.V(9999).Values(\"name\"))", + "groovy": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))", + "java": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))", + "javascript": "g.inject(\"marko\").is(__.V(9999).values(\"name\"))", + "python": "g.inject('marko').is_(__.V(9999).values('name'))" + } + ] + }, + { + "scenario": "g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX", + "traversals": [ + { + "original": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))", + "language": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))", + "canonical": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))", + "anonymized": "g.inject(string0).choose(__.is(P.eq(__.V(number0).values(string1))), __.constant(string2), __.constant(string3))", + "dotnet": "g.Inject(\"marko\").Choose(__.Is(P.Eq(__.V(9999).Values(\"name\"))), __.Constant(\"matched\"), __.Constant(\"unmatched\"))", + "go": "g.Inject(\"marko\").Choose(gremlingo.T__.Is(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\"))), gremlingo.T__.Constant(\"matched\"), gremlingo.T__.Constant(\"unmatched\"))", + "groovy": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))", + "java": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))", + "javascript": "g.inject(\"marko\").choose(__.is(P.eq(__.V(9999).values(\"name\"))), __.constant(\"matched\"), __.constant(\"unmatched\"))", + "python": "g.inject('marko').choose(__.is_(P.eq(__.V(9999).values('name'))), __.constant('matched'), __.constant('unmatched'))" + } + ] + }, + { + "scenario": "g_injectXlistX_noneXeqXV9999_valuesXnameXXX", + "traversals": [ + { + "original": "g.inject([\"marko\",\"josh\"]).none(P.eq(__.V(9999).values(\"name\")))", + "language": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))", + "canonical": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))", + "anonymized": "g.inject(list0).none(P.eq(__.V(number0).values(string0)))", + "dotnet": "g.Inject(new List { \"marko\", \"josh\" }).None(P.Eq(__.V(9999).Values(\"name\")))", + "go": "g.Inject([]interface{}{\"marko\", \"josh\"}).None(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")))", + "groovy": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))", + "java": "g.inject(new ArrayList() {{ add(\"marko\"); add(\"josh\"); }}).none(P.eq(__.V(9999).values(\"name\")))", + "javascript": "g.inject([\"marko\", \"josh\"]).none(P.eq(__.V(9999).values(\"name\")))", + "python": "g.inject(['marko', 'josh']).none(P.eq(__.V(9999).values('name')))" + } + ] + }, + { + "scenario": "g_V_hasXname_eqXV9999_valuesXnameXXX", + "traversals": [ + { + "original": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))", + "language": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))", + "canonical": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))", + "anonymized": "g.V().has(string0, P.eq(__.V(number0).values(string0)))", + "dotnet": "g.V().Has(\"name\", P.Eq(__.V(9999).Values(\"name\")))", + "go": "g.V().Has(\"name\", gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"name\")))", + "groovy": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))", + "java": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))", + "javascript": "g.V().has(\"name\", P.eq(__.V(9999).values(\"name\")))", + "python": "g.V().has('name', P.eq(__.V(9999).values('name')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))", + "language": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))", + "canonical": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))", + "anonymized": "g.V().values(string0).is(P.without(__.V(vid1).values(string0), __.V(vid2).values(string0)))", + "dotnet": "g.V().Values(\"age\").Is(P.Without(__.V(vid1).Values(\"age\"), __.V(vid2).Values(\"age\")))", + "go": "g.V().Values(\"age\").Is(gremlingo.P.Without(gremlingo.T__.V(vid1).Values(\"age\"), gremlingo.T__.V(vid2).Values(\"age\")))", + "groovy": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))", + "java": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))", + "javascript": "g.V().values(\"age\").is(P.without(__.V(vid1).values(\"age\"), __.V(vid2).values(\"age\")))", + "python": "g.V().values('age').is_(P.without(__.V(vid1).values('age'), __.V(vid2).values('age')))" + } + ] + }, { "scenario": "g_V_valuesXageX_noneXgtX32XX", "traversals": [ @@ -12373,6 +13376,125 @@ } ] }, + { + "scenario": "g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))", + "language": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))", + "canonical": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))", + "anonymized": "g.V().values(string0).where(P.gt(__.V(vid1).values(string0)))", + "dotnet": "g.V().Values(\"age\").Where(P.Gt(__.V(vid1).Values(\"age\")))", + "go": "g.V().Values(\"age\").Where(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\")))", + "groovy": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))", + "java": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))", + "javascript": "g.V().values(\"age\").where(P.gt(__.V(vid1).values(\"age\")))", + "python": "g.V().values('age').where(P.gt(__.V(vid1).values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))", + "language": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))", + "canonical": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))", + "anonymized": "g.V().values(string0).where(P.lt(__.V(vid3).values(string0)))", + "dotnet": "g.V().Values(\"age\").Where(P.Lt(__.V(vid3).Values(\"age\")))", + "go": "g.V().Values(\"age\").Where(gremlingo.P.Lt(gremlingo.T__.V(vid3).Values(\"age\")))", + "groovy": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))", + "java": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))", + "javascript": "g.V().values(\"age\").where(P.lt(__.V(vid3).values(\"age\")))", + "python": "g.V().values('age').where(P.lt(__.V(vid3).values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))", + "language": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))", + "canonical": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))", + "anonymized": "g.V().values(string0).where(P.eq(__.V(vid1).values(string0)))", + "dotnet": "g.V().Values(\"age\").Where(P.Eq(__.V(vid1).Values(\"age\")))", + "go": "g.V().Values(\"age\").Where(gremlingo.P.Eq(gremlingo.T__.V(vid1).Values(\"age\")))", + "groovy": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))", + "java": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))", + "javascript": "g.V().values(\"age\").where(P.eq(__.V(vid1).values(\"age\")))", + "python": "g.V().values('age').where(P.eq(__.V(vid1).values('age')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "language": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "canonical": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "anonymized": "g.V().values(string0).where(P.within(__.V(vid1).out(string1).values(string0).fold()))", + "dotnet": "g.V().Values(\"age\").Where(P.Within(__.V(vid1).Out(\"knows\").Values(\"age\").Fold()))", + "go": "g.V().Values(\"age\").Where(gremlingo.P.Within(gremlingo.T__.V(vid1).Out(\"knows\").Values(\"age\").Fold()))", + "groovy": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "java": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "javascript": "g.V().values(\"age\").where(P.within(__.V(vid1).out(\"knows\").values(\"age\").fold()))", + "python": "g.V().values('age').where(P.within(__.V(vid1).out('knows').values('age').fold()))" + } + ] + }, + { + "scenario": "g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX", + "traversals": [ + { + "original": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))", + "language": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))", + "canonical": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))", + "anonymized": "g.V().values(string0).where(P.neq(__.V(vid1).values(string0)))", + "dotnet": "g.V().Values(\"name\").Where(P.Neq(__.V(vid1).Values(\"name\")))", + "go": "g.V().Values(\"name\").Where(gremlingo.P.Neq(gremlingo.T__.V(vid1).Values(\"name\")))", + "groovy": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))", + "java": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))", + "javascript": "g.V().values(\"name\").where(P.neq(__.V(vid1).values(\"name\")))", + "python": "g.V().values('name').where(P.neq(__.V(vid1).values('name')))" + } + ] + }, + { + "scenario": "g_V_valuesXageX_whereXeqXV9999_valuesXageXXX", + "traversals": [ + { + "original": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))", + "language": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))", + "canonical": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))", + "anonymized": "g.V().values(string0).where(P.eq(__.V(number0).values(string0)))", + "dotnet": "g.V().Values(\"age\").Where(P.Eq(__.V(9999).Values(\"age\")))", + "go": "g.V().Values(\"age\").Where(gremlingo.P.Eq(gremlingo.T__.V(9999).Values(\"age\")))", + "groovy": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))", + "java": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))", + "javascript": "g.V().values(\"age\").where(P.eq(__.V(9999).values(\"age\")))", + "python": "g.V().values('age').where(P.eq(__.V(9999).values('age')))" + } + ] + }, + { + "scenario": "g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX", + "traversals": [ + { + "original": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")", + "language": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")", + "canonical": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")", + "anonymized": "g.V().where(P.gt(__.V(vid1).values(string0))).by(string0).values(string1)", + "dotnet": "g.V().Where(P.Gt(__.V(vid1).Values(\"age\"))).By(\"age\").Values(\"name\")", + "go": "g.V().Where(gremlingo.P.Gt(gremlingo.T__.V(vid1).Values(\"age\"))).By(\"age\").Values(\"name\")", + "groovy": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")", + "java": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")", + "javascript": "g.V().where(P.gt(__.V(vid1).values(\"age\"))).by(\"age\").values(\"name\")", + "python": "g.V().where(P.gt(__.V(vid1).values('age'))).by('age').values('name')" + } + ] + }, { "scenario": "g_withStrategiesXAdjacentToIncidentStrategyX_V", "traversals": [ @@ -18984,7 +20106,7 @@ "language": "g.addV(\"person\").property(null)", "canonical": "g.addV(\"person\").property(null)", "anonymized": "g.addV(string0).property(map0)", - "dotnet": "g.AddV((string) \"person\").Property(null)", + "dotnet": "g.AddV((string) \"person\").Property((IDictionary) null)", "go": "g.AddV(\"person\").Property(nil)", "groovy": "g.addV(\"person\").property(null)", "java": "g.addV(\"person\").property(null)", @@ -19042,7 +20164,7 @@ "language": "g.addV(\"foo\").property(Cardinality.set, null)", "canonical": "g.addV(\"foo\").property(Cardinality.set, null)", "anonymized": "g.addV(string0).property(Cardinality.set, map0)", - "dotnet": "g.AddV((string) \"foo\").Property(Cardinality.Set, null)", + "dotnet": "g.AddV((string) \"foo\").Property(Cardinality.Set, (IDictionary) null)", "go": "g.AddV(\"foo\").Property(gremlingo.Cardinality.Set, nil)", "groovy": "g.addV(\"foo\").property(Cardinality.set, null)", "java": "g.addV(\"foo\").property(Cardinality.set, null)", @@ -37289,6 +38411,176 @@ } ] }, + { + "scenario": "g_VXvid1X_id_VXidentityX_name", + "traversals": [ + { + "original": "g.V(vid1).id().V(__.identity()).values(\"name\")", + "language": "g.V(vid1).id().V(__.identity()).values(\"name\")", + "canonical": "g.V(vid1).id().V(__.identity()).values(\"name\")", + "anonymized": "g.V(vid1).id().V(__.identity()).values(string0)", + "dotnet": "g.V(vid1).Id().V(__.Identity()).Values(\"name\")", + "go": "g.V(vid1).Id().V(gremlingo.T__.Identity()).Values(\"name\")", + "groovy": "g.V(vid1).id().V(__.identity()).values(\"name\")", + "java": "g.V(vid1).id().V(__.identity()).values(\"name\")", + "javascript": "g.V(vid1).id().V(__.identity()).values(\"name\")", + "python": "g.V(vid1).id_().V(__.identity()).values('name')" + } + ] + }, + { + "scenario": "g_VXvid1_vid2X_id_VXidentityX_name", + "traversals": [ + { + "original": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")", + "language": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")", + "canonical": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")", + "anonymized": "g.V(vid1, vid2).id().V(__.identity()).values(string0)", + "dotnet": "g.V(vid1, vid2).Id().V(__.Identity()).Values(\"name\")", + "go": "g.V(vid1, vid2).Id().V(gremlingo.T__.Identity()).Values(\"name\")", + "groovy": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")", + "java": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")", + "javascript": "g.V(vid1, vid2).id().V(__.identity()).values(\"name\")", + "python": "g.V(vid1, vid2).id_().V(__.identity()).values('name')" + } + ] + }, + { + "scenario": "g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name", + "traversals": [ + { + "original": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\",\"josh\").V(__.select(\"bookmark\")).values(\"name\")", + "language": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")", + "canonical": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")", + "anonymized": "g.V(vid1).id().as(string0).V().has(string1, string2).V(__.select(string0)).values(string1)", + "dotnet": "g.V(vid1).Id().As(\"bookmark\").V().Has(\"name\", \"josh\").V(__.Select(\"bookmark\")).Values(\"name\")", + "go": "g.V(vid1).Id().As(\"bookmark\").V().Has(\"name\", \"josh\").V(gremlingo.T__.Select(\"bookmark\")).Values(\"name\")", + "groovy": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")", + "java": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")", + "javascript": "g.V(vid1).id().as(\"bookmark\").V().has(\"name\", \"josh\").V(__.select(\"bookmark\")).values(\"name\")", + "python": "g.V(vid1).id_().as_('bookmark').V().has('name', 'josh').V(__.select('bookmark')).values('name')" + } + ] + }, + { + "scenario": "g_VXvid1X_VXoutXknowsX_idX_name", + "traversals": [ + { + "original": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "language": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "canonical": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "anonymized": "g.V(vid1).V(__.out(string0).id()).values(string1)", + "dotnet": "g.V(vid1).V(__.Out(\"knows\").Id()).Values(\"name\")", + "go": "g.V(vid1).V(gremlingo.T__.Out(\"knows\").Id()).Values(\"name\")", + "groovy": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "java": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "javascript": "g.V(vid1).V(__.out(\"knows\").id()).values(\"name\")", + "python": "g.V(vid1).V(__.out('knows').id_()).values('name')" + } + ] + }, + { + "scenario": "g_VXvid1X_EXoutE_idX", + "traversals": [ + { + "original": "g.V(vid1).E(__.outE().id())", + "language": "g.V(vid1).E(__.outE().id())", + "canonical": "g.V(vid1).E(__.outE().id())", + "anonymized": "g.V(vid1).E(__.outE().id())", + "dotnet": "g.V(vid1).E(__.OutE().Id())", + "go": "g.V(vid1).E(gremlingo.T__.OutE().Id())", + "groovy": "g.V(vid1).E(__.outE().id())", + "java": "g.V(vid1).E(__.outE().id())", + "javascript": "g.V(vid1).E(__.outE().id())", + "python": "g.V(vid1).E(__.out_e().id_())" + } + ] + }, + { + "scenario": "g_injectX9999X_VXidentityX", + "traversals": [ + { + "original": "g.inject(9999).V(__.identity())", + "language": "g.inject(9999).V(__.identity())", + "canonical": "g.inject(9999).V(__.identity())", + "anonymized": "g.inject(number0).V(__.identity())", + "dotnet": "g.Inject(9999).V(__.Identity())", + "go": "g.Inject(9999).V(gremlingo.T__.Identity())", + "groovy": "g.inject(9999).V(__.identity())", + "java": "g.inject(9999).V(__.identity())", + "javascript": "g.inject(9999).V(__.identity())", + "python": "g.inject(9999).V(__.identity())" + } + ] + }, + { + "scenario": "g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX", + "traversals": [ + { + "original": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\",\"vadas\")).id().E(__.identity())", + "language": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())", + "canonical": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())", + "anonymized": "g.V(vid1).outE(string0).filter(__.inV().has(string1, string2)).id().E(__.identity())", + "dotnet": "g.V(vid1).OutE(\"knows\").Filter(__.InV().Has(\"name\", \"vadas\")).Id().E(__.Identity())", + "go": "g.V(vid1).OutE(\"knows\").Filter(gremlingo.T__.InV().Has(\"name\", \"vadas\")).Id().E(gremlingo.T__.Identity())", + "groovy": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())", + "java": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())", + "javascript": "g.V(vid1).outE(\"knows\").filter(__.inV().has(\"name\", \"vadas\")).id().E(__.identity())", + "python": "g.V(vid1).out_e('knows').filter_(__.in_v().has('name', 'vadas')).id_().E(__.identity())" + } + ] + }, + { + "scenario": "g_injectX9999X_EXidentityX", + "traversals": [ + { + "original": "g.inject(9999).E(__.identity())", + "language": "g.inject(9999).E(__.identity())", + "canonical": "g.inject(9999).E(__.identity())", + "anonymized": "g.inject(number0).E(__.identity())", + "dotnet": "g.Inject(9999).E(__.Identity())", + "go": "g.Inject(9999).E(gremlingo.T__.Identity())", + "groovy": "g.inject(9999).E(__.identity())", + "java": "g.inject(9999).E(__.identity())", + "javascript": "g.inject(9999).E(__.identity())", + "python": "g.inject(9999).E(__.identity())" + } + ] + }, + { + "scenario": "g_VXVXvid1X_idX_name", + "traversals": [ + { + "original": "g.V(__.V(vid1).id()).values(\"name\")", + "language": "g.V(__.V(vid1).id()).values(\"name\")", + "canonical": "g.V(__.V(vid1).id()).values(\"name\")", + "anonymized": "g.V(__.V(vid1).id()).values(string0)", + "dotnet": "g.V(__.V(vid1).Id()).Values(\"name\")", + "go": "g.V(gremlingo.T__.V(vid1).Id()).Values(\"name\")", + "groovy": "g.V(__.V(vid1).id()).values(\"name\")", + "java": "g.V(__.V(vid1).id()).values(\"name\")", + "javascript": "g.V(__.V(vid1).id()).values(\"name\")", + "python": "g.V(__.V(vid1).id_()).values('name')" + } + ] + }, + { + "scenario": "g_EXVXvid1X_outE_idX", + "traversals": [ + { + "original": "g.E(__.V(vid1).outE().id())", + "language": "g.E(__.V(vid1).outE().id())", + "canonical": "g.E(__.V(vid1).outE().id())", + "anonymized": "g.E(__.V(vid1).outE().id())", + "dotnet": "g.E(__.V(vid1).OutE().Id())", + "go": "g.E(gremlingo.T__.V(vid1).OutE().Id())", + "groovy": "g.E(__.V(vid1).outE().id())", + "java": "g.E(__.V(vid1).outE().id())", + "javascript": "g.E(__.V(vid1).outE().id())", + "python": "g.E(__.V(vid1).out_e().id_())" + } + ] + }, { "scenario": "g_V_valueMap", "traversals": [ @@ -42914,6 +44206,416 @@ } ] }, + { + "scenario": "g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')" + }, + { + "original": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))", + "language": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))", + "canonical": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))", + "anonymized": "g.V(vid2).property(string0, __.V(vid1).values(string1))", + "dotnet": "g.V(vid2).Property(\"alias\", __.V(vid1).Values(\"name\"))", + "go": "g.V(vid2).Property(\"alias\", gremlingo.T__.V(vid1).Values(\"name\"))", + "groovy": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))", + "java": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))", + "javascript": "g.V(vid2).property(\"alias\", __.V(vid1).values(\"name\"))", + "python": "g.V(vid2).property('alias', __.V(vid1).values('name'))" + }, + { + "original": "g.V().has(\"alias\", \"marko\")", + "language": "g.V().has(\"alias\", \"marko\")", + "canonical": "g.V().has(\"alias\", \"marko\")", + "anonymized": "g.V().has(string0, string1)", + "dotnet": "g.V().Has(\"alias\", \"marko\")", + "go": "g.V().Has(\"alias\", \"marko\")", + "groovy": "g.V().has(\"alias\", \"marko\")", + "java": "g.V().has(\"alias\", \"marko\")", + "javascript": "g.V().has(\"alias\", \"marko\")", + "python": "g.V().has('alias', 'marko')" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).as(\"peter\").addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\",\"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).as(string10).addV(string5).property(string1, string11).property(string7, string8).as(string11).addE(string12).from(string2).to(__.V().has(string1, string4)).addE(string12).from(string2).to(string9).addE(string13).from(string2).to(string6).addE(string13).from(string9).to(string6).addE(string13).from(string9).to(string11).addE(string13).from(string10).to(string6)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE((string) \"knows\").From(\"marko\").To(__.V().Has(\"name\", \"vadas\")).AddE((string) \"knows\").From(\"marko\").To(\"josh\").AddE((string) \"created\").From(\"marko\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"ripple\").AddE((string) \"created\").From(\"peter\").To(\"lop\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE(\"knows\").From(\"marko\").To(gremlingo.T__.V().Has(\"name\", \"vadas\")).AddE(\"knows\").From(\"marko\").To(\"josh\").AddE(\"created\").From(\"marko\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"ripple\").AddE(\"created\").From(\"peter\").To(\"lop\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from_(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from_(\"marko\").to(\"josh\").addE(\"created\").from_(\"marko\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"ripple\").addE(\"created\").from_(\"peter\").to(\"lop\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').from_('marko').to(__.V().has('name', 'vadas')).add_e('knows').from_('marko').to('josh').add_e('created').from_('marko').to('lop').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple').add_e('created').from_('peter').to('lop')" + }, + { + "original": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())", + "language": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())", + "canonical": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())", + "anonymized": "g.V(vid1).property(string0, __.V(vid1).in(string1).count())", + "dotnet": "g.V(vid1).Property(\"creatorCount\", __.V(vid1).In(\"created\").Count())", + "go": "g.V(vid1).Property(\"creatorCount\", gremlingo.T__.V(vid1).In(\"created\").Count())", + "groovy": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())", + "java": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in(\"created\").count())", + "javascript": "g.V(vid1).property(\"creatorCount\", __.V(vid1).in_(\"created\").count())", + "python": "g.V(vid1).property('creatorCount', __.V(vid1).in_('created').count())" + }, + { + "original": "g.V().has(\"creatorCount\", 3L)", + "language": "g.V().has(\"creatorCount\", 3l)", + "canonical": "g.V().has(\"creatorCount\", 3l)", + "anonymized": "g.V().has(string0, long0)", + "dotnet": "g.V().Has(\"creatorCount\", 3l)", + "go": "g.V().Has(\"creatorCount\", int64(3))", + "groovy": "g.V().has(\"creatorCount\", 3l)", + "java": "g.V().has(\"creatorCount\", 3l)", + "javascript": "g.V().has(\"creatorCount\", 3)", + "python": "g.V().has('creatorCount', long(3))" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXknownCount_outXknowsX_countX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).as(\"vadas\").addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).addE(string12).from(string2).to(string4).addE(string12).from(string2).to(string9)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").AddE((string) \"knows\").From(\"marko\").To(\"vadas\").AddE((string) \"knows\").From(\"marko\").To(\"josh\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").AddE(\"knows\").From(\"marko\").To(\"vadas\").AddE(\"knows\").From(\"marko\").To(\"josh\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from_(\"marko\").to(\"vadas\").addE(\"knows\").from_(\"marko\").to(\"josh\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh')" + }, + { + "original": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())", + "language": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())", + "canonical": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())", + "anonymized": "g.V(vid1).property(string0, __.out(string1).count())", + "dotnet": "g.V(vid1).Property(\"knownCount\", __.Out(\"knows\").Count())", + "go": "g.V(vid1).Property(\"knownCount\", gremlingo.T__.Out(\"knows\").Count())", + "groovy": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())", + "java": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())", + "javascript": "g.V(vid1).property(\"knownCount\", __.out(\"knows\").count())", + "python": "g.V(vid1).property('knownCount', __.out('knows').count())" + }, + { + "original": "g.V().has(\"knownCount\", 2L)", + "language": "g.V().has(\"knownCount\", 2l)", + "canonical": "g.V().has(\"knownCount\", 2l)", + "anonymized": "g.V().has(string0, long0)", + "dotnet": "g.V().Has(\"knownCount\", 2l)", + "go": "g.V().Has(\"knownCount\", int64(2))", + "groovy": "g.V().has(\"knownCount\", 2l)", + "java": "g.V().has(\"knownCount\", 2l)", + "javascript": "g.V().has(\"knownCount\", 2)", + "python": "g.V().has('knownCount', long(2))" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).as(\"peter\").addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\",\"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).as(string10).addV(string5).property(string1, string11).property(string7, string8).as(string11).addE(string12).from(string2).to(__.V().has(string1, string4)).addE(string12).from(string2).to(string9).addE(string13).from(string2).to(string6).addE(string13).from(string9).to(string6).addE(string13).from(string9).to(string11).addE(string13).from(string10).to(string6)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE((string) \"knows\").From(\"marko\").To(__.V().Has(\"name\", \"vadas\")).AddE((string) \"knows\").From(\"marko\").To(\"josh\").AddE((string) \"created\").From(\"marko\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"ripple\").AddE((string) \"created\").From(\"peter\").To(\"lop\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE(\"knows\").From(\"marko\").To(gremlingo.T__.V().Has(\"name\", \"vadas\")).AddE(\"knows\").From(\"marko\").To(\"josh\").AddE(\"created\").From(\"marko\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"ripple\").AddE(\"created\").From(\"peter\").To(\"lop\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from_(\"marko\").to(__.V().has(\"name\", \"vadas\")).addE(\"knows\").from_(\"marko\").to(\"josh\").addE(\"created\").from_(\"marko\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"ripple\").addE(\"created\").from_(\"peter\").to(\"lop\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').from_('marko').to(__.V().has('name', 'vadas')).add_e('knows').from_('marko').to('josh').add_e('created').from_('marko').to('lop').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple').add_e('created').from_('peter').to('lop')" + }, + { + "original": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))", + "language": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))", + "canonical": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))", + "anonymized": "g.V(vid1).property(string0, __.in(string1).values(string2))", + "dotnet": "g.V(vid1).Property(\"creator\", __.In(\"created\").Values(\"name\"))", + "go": "g.V(vid1).Property(\"creator\", gremlingo.T__.In(\"created\").Values(\"name\"))", + "groovy": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))", + "java": "g.V(vid1).property(\"creator\", __.in(\"created\").values(\"name\"))", + "javascript": "g.V(vid1).property(\"creator\", __.in_(\"created\").values(\"name\"))", + "python": "g.V(vid1).property('creator', __.in_('created').values('name'))" + }, + { + "original": "g.V().has(\"creator\")", + "language": "g.V().has(\"creator\")", + "canonical": "g.V().has(\"creator\")", + "anonymized": "g.V().has(string0)", + "dotnet": "g.V().Has(\"creator\")", + "go": "g.V().Has(\"creator\")", + "groovy": "g.V().has(\"creator\")", + "java": "g.V().has(\"creator\")", + "javascript": "g.V().has(\"creator\")", + "python": "g.V().has('creator')" + } + ] + }, + { + "scenario": "g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).as(\"vadas\").addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).as(\"peter\").addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).as(string10).addV(string5).property(string1, string11).property(string7, string8).as(string11).addE(string12).from(string2).to(string4).addE(string12).from(string2).to(string9).addE(string13).from(string2).to(string6).addE(string13).from(string9).to(string6).addE(string13).from(string9).to(string11).addE(string13).from(string10).to(string6)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE((string) \"knows\").From(\"marko\").To(\"vadas\").AddE((string) \"knows\").From(\"marko\").To(\"josh\").AddE((string) \"created\").From(\"marko\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"ripple\").AddE((string) \"created\").From(\"peter\").To(\"lop\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).As(\"peter\").AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE(\"knows\").From(\"marko\").To(\"vadas\").AddE(\"knows\").From(\"marko\").To(\"josh\").AddE(\"created\").From(\"marko\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"ripple\").AddE(\"created\").From(\"peter\").To(\"lop\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\").addE(\"created\").from(\"marko\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\").addE(\"created\").from(\"peter\").to(\"lop\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).as(\"peter\").addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"knows\").from_(\"marko\").to(\"vadas\").addE(\"knows\").from_(\"marko\").to(\"josh\").addE(\"created\").from_(\"marko\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"ripple\").addE(\"created\").from_(\"peter\").to(\"lop\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).as_('peter').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh').add_e('created').from_('marko').to('lop').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple').add_e('created').from_('peter').to('lop')" + }, + { + "original": "g.V(vid2).property(__.V(vid1).project(\"friendCount\",\"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))", + "language": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))", + "canonical": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))", + "anonymized": "g.V(vid2).property(__.V(vid1).project(string0, string1).by(__.out(string2).count()).by(__.out(string3).values(string4)))", + "dotnet": "g.V(vid2).Property((ITraversal) __.V(vid1).Project(\"friendCount\", \"softwareCreated\").By(__.Out(\"knows\").Count()).By(__.Out(\"created\").Values(\"name\")))", + "go": "g.V(vid2).Property(gremlingo.T__.V(vid1).Project(\"friendCount\", \"softwareCreated\").By(gremlingo.T__.Out(\"knows\").Count()).By(gremlingo.T__.Out(\"created\").Values(\"name\")))", + "groovy": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))", + "java": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))", + "javascript": "g.V(vid2).property(__.V(vid1).project(\"friendCount\", \"softwareCreated\").by(__.out(\"knows\").count()).by(__.out(\"created\").values(\"name\")))", + "python": "g.V(vid2).property(__.V(vid1).project('friendCount', 'softwareCreated').by(__.out('knows').count()).by(__.out('created').values('name')))" + }, + { + "original": "g.V().has(\"friendCount\", 2L)", + "language": "g.V().has(\"friendCount\", 2l)", + "canonical": "g.V().has(\"friendCount\", 2l)", + "anonymized": "g.V().has(string0, long0)", + "dotnet": "g.V().Has(\"friendCount\", 2l)", + "go": "g.V().Has(\"friendCount\", int64(2))", + "groovy": "g.V().has(\"friendCount\", 2l)", + "java": "g.V().has(\"friendCount\", 2l)", + "javascript": "g.V().has(\"friendCount\", 2)", + "python": "g.V().has('friendCount', long(2))" + }, + { + "original": "g.V().has(\"softwareCreated\", \"lop\")", + "language": "g.V().has(\"softwareCreated\", \"lop\")", + "canonical": "g.V().has(\"softwareCreated\", \"lop\")", + "anonymized": "g.V().has(string0, string1)", + "dotnet": "g.V().Has(\"softwareCreated\", \"lop\")", + "go": "g.V().Has(\"softwareCreated\", \"lop\")", + "groovy": "g.V().has(\"softwareCreated\", \"lop\")", + "java": "g.V().has(\"softwareCreated\", \"lop\")", + "javascript": "g.V().has(\"softwareCreated\", \"lop\")", + "python": "g.V().has('softwareCreated', 'lop')" + } + ] + }, + { + "scenario": "g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java')" + }, + { + "original": "g.V(vid2).property(__.V(vid1).project(\"originalName\",\"originalLabel\").by(__.values(\"name\")).by(__.label()))", + "language": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))", + "canonical": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))", + "anonymized": "g.V(vid2).property(__.V(vid1).project(string0, string1).by(__.values(string2)).by(__.label()))", + "dotnet": "g.V(vid2).Property((ITraversal) __.V(vid1).Project(\"originalName\", \"originalLabel\").By(__.Values(\"name\")).By(__.Label()))", + "go": "g.V(vid2).Property(gremlingo.T__.V(vid1).Project(\"originalName\", \"originalLabel\").By(gremlingo.T__.Values(\"name\")).By(gremlingo.T__.Label()))", + "groovy": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))", + "java": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))", + "javascript": "g.V(vid2).property(__.V(vid1).project(\"originalName\", \"originalLabel\").by(__.values(\"name\")).by(__.label()))", + "python": "g.V(vid2).property(__.V(vid1).project('originalName', 'originalLabel').by(__.values('name')).by(__.label()))" + }, + { + "original": "g.V(vid2).has(\"originalName\", \"marko\")", + "language": "g.V(vid2).has(\"originalName\", \"marko\")", + "canonical": "g.V(vid2).has(\"originalName\", \"marko\")", + "anonymized": "g.V(vid2).has(string0, string1)", + "dotnet": "g.V(vid2).Has(\"originalName\", \"marko\")", + "go": "g.V(vid2).Has(\"originalName\", \"marko\")", + "groovy": "g.V(vid2).has(\"originalName\", \"marko\")", + "java": "g.V(vid2).has(\"originalName\", \"marko\")", + "javascript": "g.V(vid2).has(\"originalName\", \"marko\")", + "python": "g.V(vid2).has('originalName', 'marko')" + }, + { + "original": "g.V(vid2).has(\"originalLabel\", \"person\")", + "language": "g.V(vid2).has(\"originalLabel\", \"person\")", + "canonical": "g.V(vid2).has(\"originalLabel\", \"person\")", + "anonymized": "g.V(vid2).has(string0, string1)", + "dotnet": "g.V(vid2).Has(\"originalLabel\", \"person\")", + "go": "g.V(vid2).Has(\"originalLabel\", \"person\")", + "groovy": "g.V(vid2).has(\"originalLabel\", \"person\")", + "java": "g.V(vid2).has(\"originalLabel\", \"person\")", + "javascript": "g.V(vid2).has(\"originalLabel\", \"person\")", + "python": "g.V(vid2).has('originalLabel', 'person')" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).as(\"vadas\").addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).addE(string12).from(string2).to(string4).addE(string12).from(string2).to(string9)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").AddE((string) \"knows\").From(\"marko\").To(\"vadas\").AddE((string) \"knows\").From(\"marko\").To(\"josh\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").AddE(\"knows\").From(\"marko\").To(\"vadas\").AddE(\"knows\").From(\"marko\").To(\"josh\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from_(\"marko\").to(\"vadas\").addE(\"knows\").from_(\"marko\").to(\"josh\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh')" + }, + { + "original": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))", + "language": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))", + "canonical": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))", + "anonymized": "g.V(vid1).property(Cardinality.list, string0, __.out(string1).values(string2))", + "dotnet": "g.V(vid1).Property(Cardinality.List, \"friends\", __.Out(\"knows\").Values(\"name\"))", + "go": "g.V(vid1).Property(gremlingo.Cardinality.List, \"friends\", gremlingo.T__.Out(\"knows\").Values(\"name\"))", + "groovy": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))", + "java": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))", + "javascript": "g.V(vid1).property(Cardinality.list, \"friends\", __.out(\"knows\").values(\"name\"))", + "python": "g.V(vid1).property(Cardinality.list_, 'friends', __.out('knows').values('name'))" + }, + { + "original": "g.V(vid1).properties(\"friends\")", + "language": "g.V(vid1).properties(\"friends\")", + "canonical": "g.V(vid1).properties(\"friends\")", + "anonymized": "g.V(vid1).properties(string0)", + "dotnet": "g.V(vid1).Properties(\"friends\")", + "go": "g.V(vid1).Properties(\"friends\")", + "groovy": "g.V(vid1).properties(\"friends\")", + "java": "g.V(vid1).properties(\"friends\")", + "javascript": "g.V(vid1).properties(\"friends\")", + "python": "g.V(vid1).properties('friends')" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").as(\"lop\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").as(\"ripple\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).addV(string0).property(string1, string4).property(string3, number1).addV(string5).property(string1, string6).property(string7, string8).as(string6).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).as(string11).addE(string12).from(string9).to(string6).addE(string12).from(string9).to(string11)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE((string) \"created\").From(\"josh\").To(\"lop\").AddE((string) \"created\").From(\"josh\").To(\"ripple\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").As(\"lop\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").As(\"ripple\").AddE(\"created\").From(\"josh\").To(\"lop\").AddE(\"created\").From(\"josh\").To(\"ripple\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"created\").from(\"josh\").to(\"lop\").addE(\"created\").from(\"josh\").to(\"ripple\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").as(\"lop\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").as(\"ripple\").addE(\"created\").from_(\"josh\").to(\"lop\").addE(\"created\").from_(\"josh\").to(\"ripple\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27).add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_e('created').from_('josh').to('lop').add_e('created').from_('josh').to('ripple')" + }, + { + "original": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))", + "language": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))", + "canonical": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))", + "anonymized": "g.V(vid1).property(Cardinality.set, string0, __.out(string1).values(string2))", + "dotnet": "g.V(vid1).Property(Cardinality.Set, \"langs\", __.Out(\"created\").Values(\"lang\"))", + "go": "g.V(vid1).Property(gremlingo.Cardinality.Set, \"langs\", gremlingo.T__.Out(\"created\").Values(\"lang\"))", + "groovy": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))", + "java": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))", + "javascript": "g.V(vid1).property(Cardinality.set, \"langs\", __.out(\"created\").values(\"lang\"))", + "python": "g.V(vid1).property(Cardinality.set_, 'langs', __.out('created').values('lang'))" + }, + { + "original": "g.V(vid1).properties(\"langs\")", + "language": "g.V(vid1).properties(\"langs\")", + "canonical": "g.V(vid1).properties(\"langs\")", + "anonymized": "g.V(vid1).properties(string0)", + "dotnet": "g.V(vid1).Properties(\"langs\")", + "go": "g.V(vid1).Properties(\"langs\")", + "groovy": "g.V(vid1).properties(\"langs\")", + "java": "g.V(vid1).properties(\"langs\")", + "javascript": "g.V(vid1).properties(\"langs\")", + "python": "g.V(vid1).properties('langs')" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29).as(\"marko\").addV(\"person\").property(\"name\",\"vadas\").property(\"age\",27).as(\"vadas\").addV(\"software\").property(\"name\",\"lop\").property(\"lang\",\"java\").addV(\"person\").property(\"name\",\"josh\").property(\"age\",32).as(\"josh\").addV(\"person\").property(\"name\",\"peter\").property(\"age\",35).addV(\"software\").property(\"name\",\"ripple\").property(\"lang\",\"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0).as(string2).addV(string0).property(string1, string4).property(string3, number1).as(string4).addV(string5).property(string1, string6).property(string7, string8).addV(string0).property(string1, string9).property(string3, number2).as(string9).addV(string0).property(string1, string10).property(string3, number3).addV(string5).property(string1, string11).property(string7, string8).addE(string12).from(string2).to(string4).addE(string12).from(string2).to(string9)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV((string) \"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV((string) \"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV((string) \"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV((string) \"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV((string) \"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").AddE((string) \"knows\").From(\"marko\").To(\"vadas\").AddE((string) \"knows\").From(\"marko\").To(\"josh\")", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29).As(\"marko\").AddV(\"person\").Property(\"name\", \"vadas\").Property(\"age\", 27).As(\"vadas\").AddV(\"software\").Property(\"name\", \"lop\").Property(\"lang\", \"java\").AddV(\"person\").Property(\"name\", \"josh\").Property(\"age\", 32).As(\"josh\").AddV(\"person\").Property(\"name\", \"peter\").Property(\"age\", 35).AddV(\"software\").Property(\"name\", \"ripple\").Property(\"lang\", \"java\").AddE(\"knows\").From(\"marko\").To(\"vadas\").AddE(\"knows\").From(\"marko\").To(\"josh\")", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from(\"marko\").to(\"vadas\").addE(\"knows\").from(\"marko\").to(\"josh\")", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29).as(\"marko\").addV(\"person\").property(\"name\", \"vadas\").property(\"age\", 27).as(\"vadas\").addV(\"software\").property(\"name\", \"lop\").property(\"lang\", \"java\").addV(\"person\").property(\"name\", \"josh\").property(\"age\", 32).as(\"josh\").addV(\"person\").property(\"name\", \"peter\").property(\"age\", 35).addV(\"software\").property(\"name\", \"ripple\").property(\"lang\", \"java\").addE(\"knows\").from_(\"marko\").to(\"vadas\").addE(\"knows\").from_(\"marko\").to(\"josh\")", + "python": "g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('person').property('name', 'peter').property('age', 35).add_v('software').property('name', 'ripple').property('lang', 'java').add_e('knows').from_('marko').to('vadas').add_e('knows').from_('marko').to('josh')" + }, + { + "original": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))", + "language": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))", + "canonical": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))", + "anonymized": "g.V(vid1).property(Cardinality.single, string0, __.out(string1).values(string2))", + "dotnet": "g.V(vid1).Property(Cardinality.Single, \"friend\", __.Out(\"knows\").Values(\"name\"))", + "go": "g.V(vid1).Property(gremlingo.Cardinality.Single, \"friend\", gremlingo.T__.Out(\"knows\").Values(\"name\"))", + "groovy": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))", + "java": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))", + "javascript": "g.V(vid1).property(Cardinality.single, \"friend\", __.out(\"knows\").values(\"name\"))", + "python": "g.V(vid1).property(Cardinality.single, 'friend', __.out('knows').values('name'))" + } + ] + }, + { + "scenario": "g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX", + "traversals": [ + { + "original": "g.addV(\"person\").property(\"name\",\"marko\").property(\"age\",29)", + "language": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)", + "canonical": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)", + "anonymized": "g.addV(string0).property(string1, string2).property(string3, number0)", + "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").Property(\"age\", 29)", + "go": "g.AddV(\"person\").Property(\"name\", \"marko\").Property(\"age\", 29)", + "groovy": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)", + "java": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)", + "javascript": "g.addV(\"person\").property(\"name\", \"marko\").property(\"age\", 29)", + "python": "g.add_v('person').property('name', 'marko').property('age', 29)" + }, + { + "original": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))", + "language": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))", + "canonical": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))", + "anonymized": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(string0)))", + "dotnet": "g.V(vid1).Property((ITraversal) __.V(vid1).Group().By(__.Id()).By(__.Values(\"name\")))", + "go": "g.V(vid1).Property(gremlingo.T__.V(vid1).Group().By(gremlingo.T__.Id()).By(gremlingo.T__.Values(\"name\")))", + "groovy": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))", + "java": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))", + "javascript": "g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values(\"name\")))", + "python": "g.V(vid1).property(__.V(vid1).group().by(__.id_()).by(__.values('name')))" + } + ] + }, { "scenario": "g_io_readXkryoX", "traversals": [ diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature new file mode 100644 index 00000000000..eacf7a972a2 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/ChildTraversalVerification.feature @@ -0,0 +1,212 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassFilter @StepHas +Feature: Child Traversal Verification - mutating steps blocked in filter/lookup contexts + + # ===== FILTER CONTEXT: has() with mutating child traversals ===== + # All error scenarios use addV()/drop() which ComputerVerificationStrategy also rejects on OLAP + # with a different message, so we exclude them from GraphComputer runs. + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_addVXxX_valuesXnameXX_rejected + Given the modern graph + And the traversal of + """ + g.V().has("name", __.addV("x").values("name")) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_V_drop_constantXxXX_rejected + Given the modern graph + And the traversal of + """ + g.V().has("name", __.V().drop().constant("x")) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_V_mapXaddVXxXX_valuesXnameXX_rejected + Given the modern graph + And the traversal of + """ + g.V().has("name", __.V().map(__.addV("x")).values("name")) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_eqXaddVXxX_valuesXnameXXX_rejected + Given the modern graph + And the traversal of + """ + g.V().has("name", P.eq(__.addV("x").values("name"))) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_withinXaddVXxX_valuesXnameXXX_rejected + Given the modern graph + And the traversal of + """ + g.V().has("name", P.within(__.addV("x").values("name"))) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_gtXaddVXxX_valuesXageXXX_rejected + Given the modern graph + And the traversal of + """ + g.V().has("age", P.gt(__.addV("x").values("age"))) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + # ===== FILTER CONTEXT: is() with mutating child traversals ===== + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXaddVXxX_valuesXageXX_rejected + Given the modern graph + And the traversal of + """ + g.V().values("age").is(__.addV("x").values("age")) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXgtXaddVXxX_valuesXageXXX_rejected + Given the modern graph + And the traversal of + """ + g.V().values("age").is(P.gt(__.addV("x").values("age"))) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + # ===== LOOKUP CONTEXT: V()/E() with mutating child traversals ===== + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_VXaddVXxX_idX_rejected + Given the modern graph + And the traversal of + """ + g.V().V(__.addV("x").id()) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidENotSupported + Scenario: g_V_EXaddVXxX_idX_rejected + Given the modern graph + And the traversal of + """ + g.V().E(__.addV("x").id()) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXaddVXxX_idX_rejected + Given the modern graph + And the traversal of + """ + g.V(__.addV("x").id()) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_EXaddVXxX_idX_rejected + Given the modern graph + And the traversal of + """ + g.E(__.addV("x").id()) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + # ===== MUTATION CONTEXT: property(traversal) blocks ALL mutating steps ===== + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_propertyXV_mapXdropX_projectXxX_byXnameXX_rejected + Given the modern graph + And the traversal of + """ + g.V().property(__.V().map(__.drop()).project("x").by("name")) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_propertyXaddVXtempX_projectXkX_byXnameXX_rejected + Given the modern graph + And the traversal of + """ + g.V().property(__.addV("temp").project("k").by("name")) + """ + When iterated to list + Then the traversal will raise an error with message containing text of "mutating step" + + # ===== VALID TRAVERSALS: should NOT be rejected ===== + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_VXvid1X_valuesXnameXX_passes_verification + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", __.V(vid1).values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_gtXVXvid1X_valuesXageXXX_passes_verification + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("age", P.gt(__.V(vid1).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[josh] | + | v[peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_VXoutXknowsX_idX_valuesXnameX_passes_verification + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).V(__.out("knows").id()).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | vadas | + | josh | diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature new file mode 100644 index 00000000000..74e194ba656 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasTraversal.feature @@ -0,0 +1,326 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassFilter @StepHas +Feature: Step - has() with traversal arguments + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_VXvid1X_valuesXnameXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", __.V(vid1).values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + + @GraphComputerVerificationMidVNotSupported + # has(key, traversal) with multi-result child traversal - takes first result (order-dependent) + @InsertionOrderingRequired + Scenario: g_V_hasXname_VXvid1X_outXknowsX_valuesXnameXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", __.V(vid1).out("knows").values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + + # has(key, traversal) with multi-result child traversal (age) - takes first result (order-dependent) + @GraphComputerVerificationMidVNotSupported + @InsertionOrderingRequired + Scenario: g_V_hasXage_VXvid1X_outXknowsX_valuesXageXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("age", __.V(vid1).out("knows").values("age")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_VXvid1X_valuesXnonexistentXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", __.V(vid1).values("nonexistent")) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_notXidentityXX + Given the modern graph + And the traversal of + """ + g.V().has("name", __.not(__.identity())) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_gtXVXvid1X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("age", P.gt(__.V(vid1).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[josh] | + | v[peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_lteXVXvid2X_valuesXageXXX + Given the modern graph + And using the parameter vid2 defined as "v[vadas].id" + And the traversal of + """ + g.V().has("age", P.lte(__.V(vid2).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_neqXVXvid3X_valuesXageXXX + Given the modern graph + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V().has("age", P.neq(__.V(vid3).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + | v[vadas] | + | v[peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_eqXVXvid1X_valuesXnameXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", P.eq(__.V(vid1).values("name"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_ltXVXvid1X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("age", P.lt(__.V(vid1).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_gteXVXvid3X_valuesXageXXX + Given the modern graph + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V().has("age", P.gte(__.V(vid3).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[josh] | + | v[peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXage_eqXVXvid1X_valuesXnonexistentXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("age", P.eq(__.V(vid1).values("nonexistent"))) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXlabel_VXvid1X_labelXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has(T.label, __.V(vid1).label()) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + | v[vadas] | + | v[josh] | + | v[peter] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXperson_name_VXvid1X_valuesXnameXX_age + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("person", "name", __.V(vid1).values("name")).values("age") + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + + # Multi-traversal within() where one traversal produces multiple results - use fold() to collect + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_constantXpeterXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.constant("peter"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + | v[josh] | + | v[peter] | + + # Multi-traversal within() where one traversal produces no results - still matches on the other + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_constantXmarkoXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.constant("marko"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + + # Multi-traversal within() where all traversals produce no results - filters everything + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_withinXVXvid1X_valuesXnonexistentX_VXvid1X_valuesXnonexistentXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().has("name", P.within(__.V(vid1).values("nonexistent"), __.V(vid1).values("nonexistent"))) + """ + When iterated to list + Then the result should be empty + + # Multi-traversal without() with three traversals + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_withoutXVXvid1X_valuesXnameX_VXvid2X_valuesXnameX_VXvid3X_valuesXnameXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[vadas].id" + And using the parameter vid3 defined as "v[peter].id" + And the traversal of + """ + g.V().has("name", P.without(__.V(vid1).values("name"), __.V(vid2).values("name"), __.V(vid3).values("name"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[josh] | + | v[lop] | + | v[ripple] | + + # Multi-traversal within() - union of relationship traversals from different sources + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_withinXVXvid1X_outXknowsX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V().has("name", P.within(__.V(vid1).out("knows").values("name").fold(), __.V(vid3).out("created").values("name").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + | v[josh] | + | v[ripple] | + | v[lop] | + + # Multi-traversal without() - exclusion from multiple relationship sources + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasLabelXsoftwareX_hasXname_withoutXVXvid1X_outXcreatedX_valuesXnameX_VXvid3X_outXcreatedX_valuesXnameXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V().hasLabel("software").has("name", P.without(__.V(vid1).out("created").values("name").fold(), __.V(vid3).out("created").values("name").fold())) + """ + When iterated to list + Then the result should be empty + + # Multi-traversal within() with is() - cross-label dynamic filtering, use fold() for multi-result + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasLabelXpersonX_valuesXageX_isXwithinXVXvid1X_valuesXageX_V_hasXname_lopX_inXcreatedX_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().hasLabel("person").values("age").is(P.within(__.V(vid1).values("age").fold(), __.V().has("name","lop").in("created").values("age").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + | d[32].i | + | d[35].i | + + # Multi-traversal within() - dynamic edge filtering via inV property check + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_outEXknowsX_filterXinV_hasXname_withinXV_hasXname_lopX_inXcreatedX_valuesXnameX_V_hasXname_rippleX_inXcreatedX_valuesXnameXXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).outE("knows").filter(__.inV().has("name", P.within(__.V().has("name","lop").in("created").values("name").fold(), __.V().has("name","ripple").in("created").values("name").fold()))) + """ + When iterated to list + Then the result should be unordered + | result | + | e[marko-knows->josh] | diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature new file mode 100644 index 00000000000..6872769c9b6 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/IsTraversal.feature @@ -0,0 +1,273 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassFilter @StepIs +Feature: Step - is() with traversal-bearing predicates + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXVXvid1X_valuesXageXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").is(__.V(vid1).values("age")) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXnameX_isXVXvid1X_valuesXnameXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("name").is(__.V(vid1).values("name")) + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXgtXVXvid1X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").is(P.gt(__.V(vid1).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[32].i | + | d[35].i | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXltXVXvid3X_valuesXageXXX + Given the modern graph + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V().values("age").is(P.lt(__.V(vid3).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + | d[27].i | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXneqXVXvid4X_valuesXageXXX + Given the modern graph + And using the parameter vid4 defined as "v[peter].id" + And the traversal of + """ + g.V().values("age").is(P.neq(__.V(vid4).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + | d[27].i | + | d[32].i | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXwithinXVXvid1X_outXknowsX_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").is(P.within(__.V(vid1).out("knows").values("age").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | d[27].i | + | d[32].i | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXVXvid1X_valuesXnonexistentXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").is(__.V(vid1).values("nonexistent")) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasLabelXpersonX_valuesXageX_chooseXgtXVXvid1X_valuesXageXX_olderX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().hasLabel("person").values("age").choose(__.is(P.gt(__.V(vid1).values("age"))), __.constant("older than marko"), __.constant("not older")) + """ + When iterated to list + Then the result should be unordered + | result | + | not older | + | not older | + | older than marko | + | older than marko | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasLabelXpersonX_valuesXageX_chooseXgteXmeanAgeX_aboveX + Given the modern graph + And the traversal of + """ + g.V().hasLabel("person").values("age").choose(__.is(P.gte(__.V().hasLabel("person").values("age").mean())), __.constant("above average"), __.constant("below average")) + """ + When iterated to list + Then the result should be unordered + | result | + | below average | + | below average | + | above average | + | above average | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_allXgteXVXvid2X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[vadas].id" + And the traversal of + """ + g.V(vid1).out("knows").values("age").fold().all(P.gte(__.V(vid2).values("age"))) + """ + When iterated to list + Then the result should have a count of 1 + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_allXgtXVXvid2X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[vadas].id" + And the traversal of + """ + g.V(vid1).out("knows").values("age").fold().all(P.gt(__.V(vid2).values("age"))) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_anyXeqXVXvid3X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V(vid1).out("knows").values("age").fold().any(P.eq(__.V(vid3).values("age"))) + """ + When iterated to list + Then the result should have a count of 1 + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid4X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid4 defined as "v[peter].id" + And the traversal of + """ + g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid4).values("age"))) + """ + When iterated to list + Then the result should have a count of 1 + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_outXknowsX_valuesXageX_fold_noneXeqXVXvid3X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V(vid1).out("knows").values("age").fold().none(P.eq(__.V(vid3).values("age"))) + """ + When iterated to list + Then the result should be empty + + # Empty-result handling: predicate should treat "no results" as "no match", not null. + @GraphComputerVerificationMidVNotSupported + Scenario: g_injectXnullX_isXeqXV9999_valuesXnameXXX + Given the modern graph + And the traversal of + """ + g.inject(null).is(P.eq(__.V(9999).values("name"))) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_injectXmarkoX_isXV9999_valuesXnameXX + Given the modern graph + And the traversal of + """ + g.inject("marko").is(__.V(9999).values("name")) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidVNotSupported + Scenario: g_injectXmarkoX_chooseXeqXV9999_valuesXnameXX_matched_unmatchedX + Given the modern graph + And the traversal of + """ + g.inject("marko").choose(__.is(P.eq(__.V(9999).values("name"))), __.constant("matched"), __.constant("unmatched")) + """ + When iterated to list + Then the result should be unordered + | result | + | unmatched | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_injectXlistX_noneXeqXV9999_valuesXnameXXX + Given the modern graph + And the traversal of + """ + g.inject(["marko","josh"]).none(P.eq(__.V(9999).values("name"))) + """ + When iterated to list + Then the result should have a count of 1 + + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_hasXname_eqXV9999_valuesXnameXXX + Given the modern graph + And the traversal of + """ + g.V().has("name", P.eq(__.V(9999).values("name"))) + """ + When iterated to list + Then the result should be empty + + # Multi-traversal without() in is() context + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_isXwithoutXVXvid1X_valuesXageX_VXvid2X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[josh].id" + And the traversal of + """ + g.V().values("age").is(P.without(__.V(vid1).values("age"), __.V(vid2).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[27].i | + | d[35].i | diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature new file mode 100644 index 00000000000..d9529d6be8b --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/WhereTraversal.feature @@ -0,0 +1,122 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassFilter @StepWhere +Feature: Step - where(P) with traversal-bearing predicates + + # where(P.gt(traversal)) - compare current traverser value against resolved traversal result + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_whereXgtXVXvid1X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").where(P.gt(__.V(vid1).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[32].i | + | d[35].i | + + # where(P.lt(traversal)) - filter ages less than josh's age + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_whereXltXVXvid3X_valuesXageXXX + Given the modern graph + And using the parameter vid3 defined as "v[josh].id" + And the traversal of + """ + g.V().values("age").where(P.lt(__.V(vid3).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + | d[27].i | + + # where(P.eq(traversal)) - exact match against resolved value + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_whereXeqXVXvid1X_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").where(P.eq(__.V(vid1).values("age"))) + """ + When iterated to list + Then the result should be unordered + | result | + | d[29].i | + + # where(P.within(traversal)) - collection membership against resolved traversal results + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_whereXwithinXVXvid1X_outXknowsX_valuesXageXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("age").where(P.within(__.V(vid1).out("knows").values("age").fold())) + """ + When iterated to list + Then the result should be unordered + | result | + | d[27].i | + | d[32].i | + + # where(P.neq(traversal)) - not equal to resolved value + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXnameX_whereXneqXVXvid1X_valuesXnameXXX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().values("name").where(P.neq(__.V(vid1).values("name"))) + """ + When iterated to list + Then the result should be unordered + | result | + | vadas | + | lop | + | josh | + | ripple | + | peter | + + # Empty traversal result - filters out (no match) + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_valuesXageX_whereXeqXV9999_valuesXageXXX + Given the modern graph + And the traversal of + """ + g.V().values("age").where(P.eq(__.V(9999).values("age"))) + """ + When iterated to list + Then the result should be empty + + # where(P.gt(traversal)) with by() modulator - compare property values + @GraphComputerVerificationMidVNotSupported + Scenario: g_V_whereXgtXVXvid1X_valuesXageXXX_byXageX_valuesXnameX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V().where(P.gt(__.V(vid1).values("age"))).by("age").values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | josh | + | peter | diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature new file mode 100644 index 00000000000..c8535d6a744 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/VETraversal.feature @@ -0,0 +1,149 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassMap @StepVertex @StepE +Feature: Step - V(traversal) and E(traversal) + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_id_VXidentityX_name + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).id().V(__.identity()).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1_vid2X_id_VXidentityX_name + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[josh].id" + And the traversal of + """ + g.V(vid1, vid2).id().V(__.identity()).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + | josh | + + # Use as()/select() to bookmark a vertex ID and return to it later via V(select()). + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_id_asXbookmarkX_V_hasXname_joshX_VXselectXbookmarkXX_name + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).id().as("bookmark").V().has("name","josh").V(__.select("bookmark")).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_VXoutXknowsX_idX_name + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).V(__.out("knows").id()).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | vadas | + | josh | + + @GraphComputerVerificationMidENotSupported + Scenario: g_VXvid1X_EXoutE_idX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).E(__.outE().id()) + """ + When iterated to list + Then the result should be unordered + | result | + | e[marko-created->lop] | + | e[marko-knows->josh] | + | e[marko-knows->vadas] | + + @GraphComputerVerificationMidVNotSupported + Scenario: g_injectX9999X_VXidentityX + Given the modern graph + And the traversal of + """ + g.inject(9999).V(__.identity()) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationMidENotSupported + Scenario: g_VXvid1X_outEXknowsX_hasXinV_name_vadasX_id_EXidentityX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).outE("knows").filter(__.inV().has("name","vadas")).id().E(__.identity()) + """ + When iterated to list + Then the result should be unordered + | result | + | e[marko-knows->vadas] | + + @GraphComputerVerificationMidENotSupported + Scenario: g_injectX9999X_EXidentityX + Given the modern graph + And the traversal of + """ + g.inject(9999).E(__.identity()) + """ + When iterated to list + Then the result should be empty + + Scenario: g_VXVXvid1X_idX_name + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(__.V(vid1).id()).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: g_EXVXvid1X_outE_idX + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.E(__.V(vid1).outE().id()) + """ + When iterated to list + Then the result should be unordered + | result | + | e[marko-created->lop] | + | e[marko-knows->josh] | + | e[marko-knows->vadas] | diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/PropertyTraversal.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/PropertyTraversal.feature new file mode 100644 index 00000000000..8c420205bf0 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/PropertyTraversal.feature @@ -0,0 +1,253 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassSideEffect @StepAddProperty +Feature: Step - property() with traversal arguments + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid2X_propertyXalias_VXvid1X_valuesXnameXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29). + addV("person").property("name","vadas").property("age",27). + addV("software").property("name","lop").property("lang","java"). + addV("person").property("name","josh").property("age",32). + addV("person").property("name","peter").property("age",35). + addV("software").property("name","ripple").property("lang","java") + """ + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[josh].id" + And the traversal of + """ + g.V(vid2).property("alias", __.V(vid1).values("name")) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V().has(\"alias\", \"marko\")" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXcreatorCount_VXvid1X_inXcreatedX_countX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27). + addV("software").property("name","lop").property("lang","java").as("lop"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35).as("peter"). + addV("software").property("name","ripple").property("lang","java").as("ripple"). + addE("knows").from("marko").to(__.V().has("name","vadas")). + addE("knows").from("marko").to("josh"). + addE("created").from("marko").to("lop"). + addE("created").from("josh").to("lop"). + addE("created").from("josh").to("ripple"). + addE("created").from("peter").to("lop") + """ + And using the parameter vid1 defined as "v[lop].id" + And the traversal of + """ + g.V(vid1).property("creatorCount", __.V(vid1).in("created").count()) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V().has(\"creatorCount\", 3L)" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXknownCount_outXknowsX_countX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27).as("vadas"). + addV("software").property("name","lop").property("lang","java"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35). + addV("software").property("name","ripple").property("lang","java"). + addE("knows").from("marko").to("vadas"). + addE("knows").from("marko").to("josh") + """ + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).property("knownCount", __.out("knows").count()) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V().has(\"knownCount\", 2L)" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXcreator_inXcreatedX_valuesXnameXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27). + addV("software").property("name","lop").property("lang","java").as("lop"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35).as("peter"). + addV("software").property("name","ripple").property("lang","java").as("ripple"). + addE("knows").from("marko").to(__.V().has("name","vadas")). + addE("knows").from("marko").to("josh"). + addE("created").from("marko").to("lop"). + addE("created").from("josh").to("lop"). + addE("created").from("josh").to("ripple"). + addE("created").from("peter").to("lop") + """ + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).property("creator", __.in("created").values("name")) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 0 for count of "g.V().has(\"creator\")" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid2X_propertyXVXvid1X_projectXfriendCount_softwareCreatedXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27).as("vadas"). + addV("software").property("name","lop").property("lang","java").as("lop"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35).as("peter"). + addV("software").property("name","ripple").property("lang","java").as("ripple"). + addE("knows").from("marko").to("vadas"). + addE("knows").from("marko").to("josh"). + addE("created").from("marko").to("lop"). + addE("created").from("josh").to("lop"). + addE("created").from("josh").to("ripple"). + addE("created").from("peter").to("lop") + """ + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[josh].id" + And the traversal of + """ + g.V(vid2).property(__.V(vid1).project("friendCount","softwareCreated").by(__.out("knows").count()).by(__.out("created").values("name"))) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V().has(\"friendCount\", 2L)" + And the graph should return 1 for count of "g.V().has(\"softwareCreated\", \"lop\")" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid2X_propertyXVXvid1X_projectXoriginalName_originalLabelX_byXnameX_byXlabelXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27). + addV("software").property("name","lop").property("lang","java").as("lop"). + addV("person").property("name","josh").property("age",32). + addV("person").property("name","peter").property("age",35). + addV("software").property("name","ripple").property("lang","java") + """ + And using the parameter vid1 defined as "v[marko].id" + And using the parameter vid2 defined as "v[lop].id" + And the traversal of + """ + g.V(vid2).property(__.V(vid1).project("originalName","originalLabel").by(__.values("name")).by(__.label())) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V(vid2).has(\"originalName\", \"marko\")" + And the graph should return 1 for count of "g.V(vid2).has(\"originalLabel\", \"person\")" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXlist_friends_outXknowsX_valuesXnameXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27).as("vadas"). + addV("software").property("name","lop").property("lang","java"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35). + addV("software").property("name","ripple").property("lang","java"). + addE("knows").from("marko").to("vadas"). + addE("knows").from("marko").to("josh") + """ + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).property(Cardinality.list, "friends", __.out("knows").values("name")) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 2 for count of "g.V(vid1).properties(\"friends\")" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXset_langs_outXcreatedX_valuesXlangXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29). + addV("person").property("name","vadas").property("age",27). + addV("software").property("name","lop").property("lang","java").as("lop"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35). + addV("software").property("name","ripple").property("lang","java").as("ripple"). + addE("created").from("josh").to("lop"). + addE("created").from("josh").to("ripple") + """ + And using the parameter vid1 defined as "v[josh].id" + And the traversal of + """ + g.V(vid1).property(Cardinality.set, "langs", __.out("created").values("lang")) + """ + When iterated to list + Then the result should have a count of 1 + And the graph should return 1 for count of "g.V(vid1).properties(\"langs\")" + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXsingle_friend_outXknowsX_valuesXnameXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29).as("marko"). + addV("person").property("name","vadas").property("age",27).as("vadas"). + addV("software").property("name","lop").property("lang","java"). + addV("person").property("name","josh").property("age",32).as("josh"). + addV("person").property("name","peter").property("age",35). + addV("software").property("name","ripple").property("lang","java"). + addE("knows").from("marko").to("vadas"). + addE("knows").from("marko").to("josh") + """ + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).property(Cardinality.single, "friend", __.out("knows").values("name")) + """ + When iterated to list + Then the traversal will raise an error + + @GraphComputerVerificationMidVNotSupported + Scenario: g_VXvid1X_propertyXVXvid1X_groupX_byXidX_byXvaluesXnameXXX + Given the empty graph + And the graph initializer of + """ + g.addV("person").property("name","marko").property("age",29) + """ + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.V(vid1).property(__.V(vid1).group().by(__.id()).by(__.values("name"))) + """ + When iterated to list + Then the traversal will raise an error diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java index a950daeefed..fc7c64b0609 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java @@ -59,6 +59,14 @@ public TinkerGraphStep(final GraphStepContract originalGraphStep) { super(originalGraphStep.getTraversal(), originalGraphStep.getReturnClass(), originalGraphStep.isStartStep(), originalGraphStep.getIds()); originalGraphStep.getLabels().forEach(this::addLabel); + // preserve the idTraversal if the original GraphStep had one + if (originalGraphStep instanceof GraphStep) { + final GraphStep gs = (GraphStep) originalGraphStep; + if (gs.getIdTraversal() != null) { + this.setIdTraversal(gs.getIdTraversal()); + } + } + // we used to only setIteratorSupplier() if there were no ids OR the first id was instanceof Element, // but that allowed the filter in g.V(v).has('k','v') to be ignored. this created problems for // PartitionStrategy which wants to prevent someone from passing "v" from one TraversalSource to diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java index c9e19593a77..947cdcefa38 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategy.java @@ -54,8 +54,18 @@ public void apply(final Traversal.Admin traversal) { Step currentStep = tinkerGraphStep.getNextStep(); while (currentStep instanceof HasStep || currentStep instanceof NoOpBarrierStep) { if (currentStep instanceof HasStep) { - List hasContainers = ((HasContainerHolder) currentStep).getHasContainers(); - for (HasContainer hasContainer : hasContainers) { + final List hasContainers = ((HasContainerHolder) currentStep).getHasContainers(); + + // skip folding this HasStep if any HasContainer holds a child traversal - + // its value is dynamic (resolved per-traverser) and cannot be pushed into + // TinkerGraphStep. Continue to the next step so that subsequent literal + // HasSteps can still be folded. + if (hasContainers.stream().anyMatch(HasContainer::hasTraversal)) { + currentStep = currentStep.getNextStep(); + continue; + } + + for (final HasContainer hasContainer : hasContainers) { if (!GraphStep.processHasContainerIds(tinkerGraphStep, hasContainer)) tinkerGraphStep.addHasContainer(hasContainer); } diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java new file mode 100644 index 00000000000..a91e89ea52c --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTraversalTest.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.optimization; + +import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer; +import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.step.sideEffect.TinkerGraphStep; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasSize; + +/** + * Property 9: Traversal-bearing HasContainers are not folded into GraphStep. + *

+ * For any traversal of the form {@code g.V().has(key, traversal)} or {@code g.V().has(key, P.eq(traversal))}, + * after applying {@link TinkerGraphStepStrategy}, the {@link HasStep} SHALL remain as a separate step in the + * traversal plan and SHALL NOT be folded into the {@link TinkerGraphStep}. + *

+ * Validates: Requirements 8.1, 8.2, 8.3 + */ +public class TinkerGraphStepStrategyTraversalTest { + + private Graph graph; + private GraphTraversalSource g; + + @Before + public void setup() { + graph = TinkerGraph.open(); + g = graph.traversal(); + } + + @After + public void teardown() throws Exception { + graph.close(); + } + + /** + * Applies TinkerGraphStepStrategy to the given traversal and returns the step list. + */ + private List applyStrategy(final Traversal.Admin traversal) { + final TraversalStrategies strategies = new DefaultTraversalStrategies(); + strategies.addStrategies(TinkerGraphStepStrategy.instance()); + traversal.setStrategies(strategies); + traversal.applyStrategies(); + return traversal.getSteps(); + } + + @Test + public void shouldNotFoldTraversalBearingHasContainerIntoGraphStep() { + // g.V().has("name", __.constant("marko")) - traversal-bearing HasContainer + final GraphTraversal traversal = g.V().has("name", __.constant("marko")); + final List steps = applyStrategy(traversal.asAdmin()); + + // The traversal plan should contain at least 2 steps: + // TinkerGraphStep (replacing GraphStep) and HasStep (not folded) + assertThat(steps, hasSize(greaterThanOrEqualTo(2))); + assertThat(steps.get(0), instanceOf(TinkerGraphStep.class)); + + // The HasStep should remain as a separate step + final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep); + assertThat("HasStep with traversal-bearing HasContainer should NOT be folded into TinkerGraphStep", + hasStepPresent, is(true)); + + // The TinkerGraphStep should have no folded HasContainers + final TinkerGraphStep tinkerGraphStep = (TinkerGraphStep) steps.get(0); + assertThat("TinkerGraphStep should have no folded HasContainers for traversal-bearing has()", + tinkerGraphStep.getHasContainers(), hasSize(0)); + } + + @Test + public void shouldStillFoldLiteralHasContainerIntoGraphStep() { + // g.V().has("name", "marko") - literal HasContainer should still be folded + final GraphTraversal traversal = g.V().has("name", "marko"); + final List steps = applyStrategy(traversal.asAdmin()); + + // After folding, the HasStep should be absorbed into TinkerGraphStep + assertThat(steps, hasSize(1)); + assertThat(steps.get(0), instanceOf(TinkerGraphStep.class)); + + // The TinkerGraphStep should have the folded HasContainer + final TinkerGraphStep tinkerGraphStep = (TinkerGraphStep) steps.get(0); + assertThat(tinkerGraphStep.getHasContainers(), hasSize(1)); + } + + @Test + public void shouldNotFoldPredicateWithTraversalIntoGraphStep() { + // g.V().has("name", P.eq(__.constant("marko"))) - predicate with traversal + final GraphTraversal traversal = + g.V().has("name", org.apache.tinkerpop.gremlin.process.traversal.P.eq(__.constant("marko").asAdmin())); + final List steps = applyStrategy(traversal.asAdmin()); + + // The HasStep should remain as a separate step + assertThat(steps, hasSize(greaterThanOrEqualTo(2))); + assertThat(steps.get(0), instanceOf(TinkerGraphStep.class)); + + final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep); + assertThat("HasStep with P.eq(traversal) should NOT be folded into TinkerGraphStep", + hasStepPresent, is(true)); + } + + @Test + public void shouldFoldLiteralHasButNotTraversalHasInMixedTraversal() { + // g.V().has("name", "marko").has("age", __.constant(29)) + // Both containers end up in the same HasStep (TraversalHelper.addHasContainer merges). + // The strategy skips the entire HasStep because it contains a traversal-bearing container. + final GraphTraversal traversal = + g.V().has("name", "marko").has("age", __.constant(29)); + final List steps = applyStrategy(traversal.asAdmin()); + + // TinkerGraphStep should have NO folded HasContainers (the merged HasStep is skipped) + assertThat(steps.get(0), instanceOf(TinkerGraphStep.class)); + final TinkerGraphStep tinkerGraphStep = (TinkerGraphStep) steps.get(0); + + // The HasStep with both containers should remain as a separate step + final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep); + assertThat("HasStep with mixed containers should remain as separate step", + hasStepPresent, is(true)); + } + + @Test + public void shouldFoldLiteralHasAfterBarrierAndTraversalHas() { + // g.V().has("age", __.constant(29)).barrier().has("name", "marko") + // The barrier separates the two HasSteps. The strategy should: + // - Skip the traversal-bearing HasStep (has("age", traversal)) + // - Stop at the barrier (not a HasStep or NoOpBarrierStep... actually NoOpBarrierStep IS handled) + // Let's use a different separator. Actually NoOpBarrierStep is handled by the while loop. + // The key test is: after skipping a traversal-bearing HasStep, the strategy continues + // and can fold subsequent literal HasSteps. + // + // With separate HasSteps (not merged), the strategy should fold the literal one. + // We can force separate HasSteps by inserting a NoOpBarrierStep between them. + final GraphTraversal traversal = + g.V().has("age", __.constant(29)).barrier().has("name", "marko"); + final List steps = applyStrategy(traversal.asAdmin()); + + // TinkerGraphStep should have the literal "name" HasContainer folded + assertThat(steps.get(0), instanceOf(TinkerGraphStep.class)); + final TinkerGraphStep tinkerGraphStep = (TinkerGraphStep) steps.get(0); + assertThat("Literal HasContainer after barrier should be folded even when preceded by traversal-bearing HasStep", + tinkerGraphStep.getHasContainers(), hasSize(1)); + assertThat(tinkerGraphStep.getHasContainers().get(0).getKey(), is("name")); + + // The traversal-bearing HasStep for "age" should remain + final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep); + assertThat("Traversal-bearing HasStep should remain as separate step", + hasStepPresent, is(true)); + } + + @Test + public void shouldFoldMultipleLiteralHasStepsSeparatedByTraversalHas() { + // g.V().has("name", "marko").has("age", __.constant(29)).barrier().has("lang", "java") + // has("name") is a separate literal HasStep, has("age") is a separate traversal HasStep, + // has("lang") is a separate literal HasStep after the barrier. + // Strategy should fold both literal HasSteps and skip the traversal one. + final GraphTraversal traversal = + g.V().has("name", "marko").has("age", __.constant(29)).barrier().has("lang", "java"); + final List steps = applyStrategy(traversal.asAdmin()); + + // TinkerGraphStep should have both literal HasContainers folded ("name" and "lang") + assertThat(steps.get(0), instanceOf(TinkerGraphStep.class)); + final TinkerGraphStep tinkerGraphStep = (TinkerGraphStep) steps.get(0); + assertThat("Both literal HasContainers should be folded", + tinkerGraphStep.getHasContainers(), hasSize(2)); + + // The traversal-bearing HasStep (age) should remain + final boolean hasStepPresent = steps.stream().anyMatch(s -> s instanceof HasStep); + assertThat("Traversal-bearing HasStep should remain as separate step", + hasStepPresent, is(true)); + } + +}