TINKERPOP-2041 Implemented text predicates
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/9d83f8af Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/9d83f8af Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/9d83f8af Branch: refs/heads/TINKERPOP-2041 Commit: 9d83f8af6562a54d6e2a200e35de145b9ca26062 Parents: cce3fe6 Author: Daniel Kuppitz <daniel_kupp...@hotmail.com> Authored: Wed Sep 26 15:44:35 2018 -0700 Committer: Daniel Kuppitz <daniel_kupp...@hotmail.com> Committed: Fri Sep 28 12:56:27 2018 -0700 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 1 + docs/src/reference/the-traversal.asciidoc | 34 +++-- docs/src/upgrade/release-3.4.x.asciidoc | 15 +++ .../tinkerpop/gremlin/jsr223/CoreImports.java | 3 + .../tinkerpop/gremlin/process/traversal/TP.java | 107 ++++++++++++++++ .../gremlin/process/traversal/Text.java | 123 +++++++++++++++++++ .../structure/io/graphson/GraphSONModule.java | 5 + .../io/graphson/TraversalSerializersV2d0.java | 35 ++++++ .../io/graphson/TraversalSerializersV3d0.java | 35 ++++++ .../structure/io/gryo/GryoSerializersV1d0.java | 21 ++++ .../structure/io/gryo/GryoSerializersV3d0.java | 21 ++++ .../gremlin/structure/io/gryo/GryoVersion.java | 7 +- .../gremlin/process/traversal/PTest.java | 15 +++ .../GraphSONMapperPartialEmbeddedTypeTest.java | 14 ++- gremlin-dotnet/glv/TP.template | 71 +++++++++++ gremlin-dotnet/glv/generate.groovy | 14 ++- .../src/Gremlin.Net/Process/Traversal/TP.cs | 96 +++++++++++++++ .../Structure/IO/GraphSON/GraphSONWriter.cs | 3 +- .../Structure/IO/GraphSON/TPSerializer.cs | 45 +++++++ .../gremlin/groovy/jsr223/GroovyTranslator.java | 7 ++ gremlin-javascript/glv/TraversalSource.template | 45 ++++++- gremlin-javascript/glv/generate.groovy | 7 ++ .../main/javascript/gremlin-javascript/index.js | 1 + .../gremlin-javascript/lib/process/traversal.js | 63 +++++++++- .../lib/structure/io/type-serializers.js | 24 +++- .../test/cucumber/feature-steps.js | 1 + gremlin-python/glv/TraversalSource.template | 21 +++- gremlin-python/glv/generate.groovy | 9 +- .../gremlin/python/jsr223/PythonTranslator.java | 7 ++ .../jython/gremlin_python/process/traversal.py | 63 +++++++++- .../gremlin_python/structure/io/graphsonV2d0.py | 13 +- .../gremlin_python/structure/io/graphsonV3d0.py | 13 +- .../src/main/jython/radish/feature_steps.py | 3 +- gremlin-test/features/filter/Has.feature | 57 ++++++++- .../process/traversal/step/filter/HasTest.java | 86 +++++++++++++ 35 files changed, 1056 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 5e63da0..e6f3cd8 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima This release also includes changes from <<release-3-3-3, 3.3.3>>. +* Added text predicates. * Rewrote `ConnectiveStrategy` to support an arbitrary number of infix notations in a single traversal. * GraphSON `MessageSerializer`s will automatically register the GremlinServerModule to a provided GraphSONMapper. * Removed support for `-i` option in Gremlin Server which was previously deprecated. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/docs/src/reference/the-traversal.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc index 6146f9b..da7260c 100644 --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@ -3356,24 +3356,32 @@ interface. Steps that allow for this type of modulation will explicitly state so [[a-note-on-predicates]] == A Note on Predicates -A `P` is a predicate of the form `Function<Object,Boolean>`. That is, given some object, return true or false. The -provided predicates are outlined in the table below and are used in various steps such as <<has-step,`has()`>>-step, +A `P` is a predicate of the form `Function<Object,Boolean>`. That is, given some object, return true or false. As of +the relase of TinkerPop 3.4.0, Gremlin also supports simple text predicates, which only work on `String` values. The `TP` +text predicates extends the `P` predicates, but are specialized in that they are of the form `Function<String,Boolean>`. +The provided predicates are outlined in the table below and are used in various steps such as <<has-step,`has()`>>-step, <<where-step,`where()`>>-step, <<is-step,`is()`>>-step, etc. [width="100%",cols="3,15",options="header"] |========================================================= | Predicate | Description -| `eq(object)` | Is the incoming object equal to the provided object? -| `neq(object)` | Is the incoming object not equal to the provided object? -| `lt(number)` | Is the incoming number less than the provided number? -| `lte(number)` | Is the incoming number less than or equal to the provided number? -| `gt(number)` | Is the incoming number greater than the provided number? -| `gte(number)` | Is the incoming number greater than or equal to the provided number? -| `inside(number,number)` | Is the incoming number greater than the first provided number and less than the second? -| `outside(number,number)` | Is the incoming number less than the first provided number or greater than the second? -| `between(number,number)` | Is the incoming number greater than or equal to the first provided number and less than the second? -| `within(objects...)` | Is the incoming object in the array of provided objects? -| `without(objects...)` | Is the incoming object not in the array of the provided objects? +| `P.eq(object)` | Is the incoming object equal to the provided object? +| `P.neq(object)` | Is the incoming object not equal to the provided object? +| `P.lt(number)` | Is the incoming number less than the provided number? +| `P.lte(number)` | Is the incoming number less than or equal to the provided number? +| `P.gt(number)` | Is the incoming number greater than the provided number? +| `P.gte(number)` | Is the incoming number greater than or equal to the provided number? +| `P.inside(number,number)` | Is the incoming number greater than the first provided number and less than the second? +| `P.outside(number,number)` | Is the incoming number less than the first provided number or greater than the second? +| `P.between(number,number)` | Is the incoming number greater than or equal to the first provided number and less than the second? +| `P.within(objects...)` | Is the incoming object in the array of provided objects? +| `P.without(objects...)` | Is the incoming object not in the array of the provided objects? +| `TP.startsWith(string)` | Does the incoming `String` start with the provided `String`? +| `TP.endsWith(string)` | Does the incoming `String` end with the provided `String`? +| `TP.contains(string)` | Does the incoming `String` contain the provided `String`? +| `TP.startsNotWith(string)` | TODO: find a better name +| `TP.endsNotWith(string)` | TODO: find a better name +| `TP.absent(string)` | TODO: find a better name |========================================================= [gremlin-groovy] http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/docs/src/upgrade/release-3.4.x.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/upgrade/release-3.4.x.asciidoc b/docs/src/upgrade/release-3.4.x.asciidoc index e0484a8..d677a5c 100644 --- a/docs/src/upgrade/release-3.4.x.asciidoc +++ b/docs/src/upgrade/release-3.4.x.asciidoc @@ -29,6 +29,21 @@ Please see the link:https://github.com/apache/tinkerpop/blob/3.4.0/CHANGELOG.asc === Upgrading for Users +==== Added text predicates + +Gremlin now supports simple text predicates on top of the existing `P` predicates. Both, the new `TP` text predicates and the old `P` predicates, can be chained using `and()` and `or()`. + +[source,groovy] +---- +gremlin> g.V().has("person","name", contains("o")).valueMap() +==>[name:[marko],age:[29]] +==>[name:[josh],age:[32]] +gremlin> g.V().has("person","name", contains("o").and(gte("j").and(endsWith("ko")))).valueMap() +==>[name:[marko],age:[29]] +---- + +See: link:https://issues.apache.org/jira/browse/TINKERPOP-2041[TINKERPOP-2041] + ==== Changed infix behavior The infix notation of `and()` and `or()` now supports an arbitrary number of traversals and `ConnectiveStrategy` produces a traversal with proper AND and OR semantics. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java index 2b1e33e..38ef258 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java @@ -67,6 +67,7 @@ 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.TP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -181,6 +182,7 @@ public final class CoreImports { CLASS_IMPORTS.add(TraversalOptionParent.class); CLASS_IMPORTS.add(TraversalOptionParent.Pick.class); CLASS_IMPORTS.add(P.class); + CLASS_IMPORTS.add(TP.class); // remote CLASS_IMPORTS.add(RemoteConnection.class); CLASS_IMPORTS.add(RemoteGraph.class); @@ -291,6 +293,7 @@ public final class CoreImports { uniqueMethods(IoCore.class).forEach(METHOD_IMPORTS::add); uniqueMethods(P.class).forEach(METHOD_IMPORTS::add); + uniqueMethods(TP.class).forEach(METHOD_IMPORTS::add); uniqueMethods(__.class).filter(m -> !m.getName().equals("__")).forEach(METHOD_IMPORTS::add); uniqueMethods(Computer.class).forEach(METHOD_IMPORTS::add); uniqueMethods(TimeUtil.class).forEach(METHOD_IMPORTS::add); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TP.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TP.java new file mode 100644 index 0000000..fc245a4 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TP.java @@ -0,0 +1,107 @@ +/* + * 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 java.util.function.BiPredicate; + +/** + * @author Daniel Kuppitz (http://gremlin.guru) + */ +public class TP extends P<String> { + + @SuppressWarnings("WeakerAccess") + public TP(final BiPredicate<String, String> biPredicate, final String value) { + super(biPredicate, value); + } + + @Override + public boolean equals(final Object other) { + return other instanceof TP && super.equals(other); + } + + @Override + public String toString() { + return null == this.originalValue ? this.biPredicate.toString() : this.biPredicate.toString() + "(" + this.originalValue + ")"; + } + + @Override + public TP negate() { + return new TP(this.biPredicate.negate(), this.originalValue); + } + + public TP clone() { + return (TP) super.clone(); + } + + //////////////// statics + + /** + * Determines if String does start with the given value. + * + * @since 3.4.0 + */ + public static TP startsWith(final String value) { + return new TP(Text.startsWith, value); + } + + /** + * Determines if String does not start with the given value. + * + * @since 3.4.0 + */ + public static TP startsNotWith(final String value) { + return new TP(Text.startsNotWith, value); + } + + /** + * Determines if String does start with the given value. + * + * @since 3.4.0 + */ + public static TP endsWith(final String value) { + return new TP(Text.endsWith, value); + } + + /** + * Determines if String does not start with the given value. + * + * @since 3.4.0 + */ + public static TP endsNotWith(final String value) { + return new TP(Text.endsNotWith, value); + } + + /** + * Determines if String does contain the given value. + * + * @since 3.4.0 + */ + public static TP contains(final String value) { + return new TP(Text.contains, value); + } + + /** + * Determines if String does not contain the given value. + * + * @since 3.4.0 + */ + public static TP absent(final String value) { + return new TP(Text.absent, value); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Text.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Text.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Text.java new file mode 100644 index 0000000..5169309 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Text.java @@ -0,0 +1,123 @@ +/* + * 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 java.util.function.BiPredicate; + +/** + * @author Daniel Kuppitz (http://gremlin.guru) + */ +public enum Text implements BiPredicate<String, String> { + + startsWith { + @Override + public boolean test(final String value, final String prefix) { + return value.startsWith(prefix); + } + + /** + * The negative of {@code startsWith} is {@link #startsNotWith}. + */ + @Override + public Text negate() { + return startsNotWith; + } + }, + + startsNotWith { + @Override + public boolean test(final String value, final String prefix) { + return !startsWith.test(value, prefix); + } + + /** + * The negative of {@code startsNotWith} is {@link #startsWith}. + */ + @Override + public Text negate() { + return startsWith; + } + }, + + endsWith { + @Override + public boolean test(final String value, final String suffix) { + return value.endsWith(suffix); + } + + /** + * The negative of {@code endsWith} is {@link #endsNotWith}. + */ + @Override + public Text negate() { + return endsNotWith; + } + }, + + endsNotWith { + @Override + public boolean test(final String value, final String prefix) { + return !endsWith.test(value, prefix); + } + + /** + * The negative of {@code endsNotWith} is {@link #endsWith}. + */ + @Override + public Text negate() { + return endsWith; + } + }, + + contains { + @Override + public boolean test(final String value, final String search) { + return value.contains(search); + } + + /** + * The negative of {@code contains} is {@link #absent}. + */ + @Override + public Text negate() { + return absent; + } + }, + + absent{ + @Override + public boolean test(final String value, final String search) { + return !contains.test(value, search); + } + + /** + * The negative of {@code absent} is {@link #contains}. + */ + @Override + public Text negate() { + return contains; + } + }; + + /** + * Produce the opposite representation of the current {@code Text} enum. + */ + @Override + public abstract Text negate(); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java index 1bccd7c..74647a1 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java @@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Path; 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.TP; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -145,6 +146,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { put(AndP.class, "P"); put(OrP.class, "P"); put(P.class, "P"); + put(TP.class, "TP"); Stream.of( VertexProperty.Cardinality.class, Column.class, @@ -270,6 +272,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { TraversalOptionParent.Pick.values(), T.values()).flatMap(Stream::of).forEach(e -> addDeserializer(e.getClass(), new TraversalSerializersV3d0.EnumJacksonDeserializer(e.getDeclaringClass()))); addDeserializer(P.class, new TraversalSerializersV3d0.PJacksonDeserializer()); + addDeserializer(TP.class, new TraversalSerializersV3d0.TPJacksonDeserializer()); addDeserializer(Lambda.class, new TraversalSerializersV3d0.LambdaJacksonDeserializer()); addDeserializer(Traverser.class, new TraversalSerializersV3d0.TraverserJacksonDeserializer()); Arrays.asList( @@ -359,6 +362,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { put(AndP.class, "P"); put(OrP.class, "P"); put(P.class, "P"); + put(TP.class, "TP"); Stream.of( VertexProperty.Cardinality.class, Column.class, @@ -476,6 +480,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { TraversalOptionParent.Pick.values(), T.values()).flatMap(Stream::of).forEach(e -> addDeserializer(e.getClass(), new TraversalSerializersV2d0.EnumJacksonDeserializer(e.getDeclaringClass()))); addDeserializer(P.class, new TraversalSerializersV2d0.PJacksonDeserializer()); + addDeserializer(TP.class, new TraversalSerializersV2d0.TPJacksonDeserializer()); addDeserializer(Lambda.class, new TraversalSerializersV2d0.LambdaJacksonDeserializer()); addDeserializer(Traverser.class, new TraversalSerializersV2d0.TraverserJacksonDeserializer()); Arrays.asList( http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java index 2a07723..7ba4ca5 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java @@ -24,6 +24,7 @@ import org.apache.commons.configuration.MapConfiguration; import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -372,6 +373,40 @@ final class TraversalSerializersV2d0 { } } + final static class TPJacksonDeserializer extends StdDeserializer<TP> { + + public TPJacksonDeserializer() { + super(TP.class); + } + + @Override + public TP deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + String predicate = null; + String value = null; + + while (jsonParser.nextToken() != JsonToken.END_OBJECT) { + if (jsonParser.getCurrentName().equals(GraphSONTokens.PREDICATE)) { + jsonParser.nextToken(); + predicate = jsonParser.getText(); + } else if (jsonParser.getCurrentName().equals(GraphSONTokens.VALUE)) { + jsonParser.nextToken(); + value = deserializationContext.readValue(jsonParser, String.class); + } + } + + try { + return (TP) TP.class.getMethod(predicate, String.class).invoke(null, value); + } catch (final Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + @Override + public boolean isCachable() { + return true; + } + } + final static class LambdaJacksonDeserializer extends StdDeserializer<Lambda> { public LambdaJacksonDeserializer() { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java index eaa7b0f..ca01ec0 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java @@ -24,6 +24,7 @@ import org.apache.commons.configuration.MapConfiguration; import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; @@ -370,6 +371,40 @@ final class TraversalSerializersV3d0 { } } + final static class TPJacksonDeserializer extends StdDeserializer<TP> { + + public TPJacksonDeserializer() { + super(TP.class); + } + + @Override + public TP deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + String predicate = null; + String value = null; + + while (jsonParser.nextToken() != JsonToken.END_OBJECT) { + if (jsonParser.getCurrentName().equals(GraphSONTokens.PREDICATE)) { + jsonParser.nextToken(); + predicate = jsonParser.getText(); + } else if (jsonParser.getCurrentName().equals(GraphSONTokens.VALUE)) { + jsonParser.nextToken(); + value = deserializationContext.readValue(jsonParser, String.class); + } + } + + try { + return (TP) TP.class.getMethod(predicate, String.class).invoke(null, value); + } catch (final Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + @Override + public boolean isCachable() { + return true; + } + } + final static class LambdaJacksonDeserializer extends StdDeserializer<Lambda> { public LambdaJacksonDeserializer() { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV1d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV1d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV1d0.java index ca7c241..c7de4ec 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV1d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV1d0.java @@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraver import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; @@ -228,6 +229,26 @@ public final class GryoSerializersV1d0 { } } + public final static class TPSerializer implements SerializerShim<TP> { + @Override + public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final TP p) { + output.writeString(p.getBiPredicate().toString()); + kryo.writeObject(output, p.getValue()); + } + + @Override + public <I extends InputShim> TP read(final KryoShim<I, ?> kryo, final I input, final Class<TP> clazz) { + final String predicate = input.readString(); + final String value = kryo.readObject(input, String.class); + + try { + return (TP) TP.class.getMethod(predicate, String.class).invoke(null, value); + } catch (final Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + public final static class LambdaSerializer implements SerializerShim<Lambda> { @Override public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Lambda lambda) { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3d0.java index fee9345..ffda00e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3d0.java @@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraver import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; @@ -344,6 +345,26 @@ public final class GryoSerializersV3d0 { } } + public final static class TPSerializer implements SerializerShim<TP> { + @Override + public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final TP p) { + output.writeString(p.getBiPredicate().toString()); + kryo.writeObject(output, p.getValue()); + } + + @Override + public <I extends InputShim> TP read(final KryoShim<I, ?> kryo, final I input, final Class<TP> clazz) { + final String predicate = input.readString(); + final String value = kryo.readObject(input, String.class); + + try { + return (TP) TP.class.getMethod(predicate, String.class).invoke(null, value); + } catch (final Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + public final static class LambdaSerializer implements SerializerShim<Lambda> { @Override public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Lambda lambda) { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java index 7af3766..fb62fee 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java @@ -33,6 +33,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Path; 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.TP; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep; @@ -244,7 +245,7 @@ public enum GryoVersion { add(GryoTypeReg.of(Collections.singleton(null).getClass(), 54)); add(GryoTypeReg.of(Collections.singletonList(null).getClass(), 24)); add(GryoTypeReg.of(Collections.singletonMap(null, null).getClass(), 23)); - add(GryoTypeReg.of(Types.COLLECTIONS_SYNCHRONIZED_MAP, 185, new UtilSerializers.SynchronizedMapSerializer())); // ***LAST ID*** + add(GryoTypeReg.of(Types.COLLECTIONS_SYNCHRONIZED_MAP, 185, new UtilSerializers.SynchronizedMapSerializer())); add(GryoTypeReg.of(Contains.class, 49)); add(GryoTypeReg.of(Currency.class, 40)); add(GryoTypeReg.of(Date.class, 38)); @@ -311,6 +312,7 @@ public enum GryoVersion { add(GryoTypeReg.of(Bytecode.class, 122, new GryoSerializersV3d0.BytecodeSerializer())); add(GryoTypeReg.of(P.class, 124, new GryoSerializersV3d0.PSerializer())); + add(GryoTypeReg.of(TP.class, 186, new GryoSerializersV3d0.TPSerializer())); // ***LAST ID*** add(GryoTypeReg.of(Lambda.class, 125, new GryoSerializersV3d0.LambdaSerializer())); add(GryoTypeReg.of(Bytecode.Binding.class, 126, new GryoSerializersV3d0.BindingSerializer())); add(GryoTypeReg.of(Order.class, 127)); @@ -436,7 +438,7 @@ public enum GryoVersion { add(GryoTypeReg.of(Collections.singleton(null).getClass(), 54)); add(GryoTypeReg.of(Collections.singletonList(null).getClass(), 24)); add(GryoTypeReg.of(Collections.singletonMap(null, null).getClass(), 23)); - add(GryoTypeReg.of(Types.COLLECTIONS_SYNCHRONIZED_MAP, 185, new UtilSerializers.SynchronizedMapSerializer())); // ***LAST ID*** + add(GryoTypeReg.of(Types.COLLECTIONS_SYNCHRONIZED_MAP, 185, new UtilSerializers.SynchronizedMapSerializer())); add(GryoTypeReg.of(Contains.class, 49)); add(GryoTypeReg.of(Currency.class, 40)); add(GryoTypeReg.of(Date.class, 38)); @@ -502,6 +504,7 @@ public enum GryoVersion { add(GryoTypeReg.of(Bytecode.class, 122, new GryoSerializersV1d0.BytecodeSerializer())); add(GryoTypeReg.of(P.class, 124, new GryoSerializersV1d0.PSerializer())); + add(GryoTypeReg.of(TP.class, 186, new GryoSerializersV1d0.TPSerializer())); // ***LAST ID*** add(GryoTypeReg.of(Lambda.class, 125, new GryoSerializersV1d0.LambdaSerializer())); add(GryoTypeReg.of(Bytecode.Binding.class, 126, new GryoSerializersV1d0.BindingSerializer())); add(GryoTypeReg.of(Order.class, 127)); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java ---------------------------------------------------------------------- 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 6ec33cc..1060b4e 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 @@ -94,6 +94,21 @@ public class PTest { {P.between("m", "n").or(P.eq("daniel")), "marko", true}, {P.between("m", "n").or(P.eq("daniel")), "daniel", true}, {P.between("m", "n").or(P.eq("daniel")), "stephen", false}, + // text predicates + {TP.contains("ark"), "marko", true}, + {TP.contains("ark"), "josh", false}, + {TP.startsWith("jo"), "marko", false}, + {TP.startsWith("jo"), "josh", true}, + {TP.endsWith("ter"), "marko", false}, + {TP.endsWith("ter"), "peter", true}, + {TP.contains("o"), "marko", true}, + {TP.contains("o"), "josh", true}, + {TP.contains("o").and(P.gte("j")), "marko", true}, + {TP.contains("o").and(P.gte("j")), "josh", true}, + {TP.contains("o").and(P.gte("j")).and(TP.endsWith("ko")), "marko", true}, + {TP.contains("o").and(P.gte("j")).and(TP.endsWith("ko")), "josh", false}, + {TP.contains("o").and(P.gte("j").and(TP.endsWith("ko"))), "marko", true}, + {TP.contains("o").and(P.gte("j").and(TP.endsWith("ko"))), "josh", false}, })); } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java index 4e86ebd..52a7ee4 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java @@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.structure.io.graphson; import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.shaded.jackson.databind.JsonMappingException; import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper; @@ -327,10 +328,19 @@ public class GraphSONMapperPartialEmbeddedTypeTest extends AbstractGraphSONTest P.without(1,2,3,4), P.without(Arrays.asList(1,2,3,4)), P.eq(1).and(P.eq(2)), - P.eq(1).or(P.eq(2))); + P.eq(1).or(P.eq(2)), + TP.contains("ark"), + TP.startsWith("mar"), + TP.endsWith("ko"), + TP.endsWith("ko").and(P.gte("mar")), + P.gte("mar").and(TP.endsWith("ko"))); for (P p : variantsOfP) { - assertEquals(p, serializeDeserialize(mapper, p, P.class)); + if (p instanceof TP) { + assertEquals(p, serializeDeserialize(mapper, p, TP.class)); + } else { + assertEquals(p, serializeDeserialize(mapper, p, P.class)); + } } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-dotnet/glv/TP.template ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/glv/TP.template b/gremlin-dotnet/glv/TP.template new file mode 100644 index 0000000..22320ea --- /dev/null +++ b/gremlin-dotnet/glv/TP.template @@ -0,0 +1,71 @@ +#region License + +/* + * 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. + */ + +#endregion + +// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Gremlin.Net.Process.Traversal +{ +#pragma warning disable 1591 + + /// <summary> + /// A <see cref="TP" /> is a predicate of the form Func<string, bool>. + /// That is, given some string, return true or false. + /// </summary> + public class TP : P + { + /// <summary> + /// Initializes a new instance of the <see cref="TP" /> class. + /// </summary> + /// <param name="operatorName">The name of the predicate.</param> + /// <param name="value">The value of the predicate.</param> + /// <param name="other">An optional other predicate that is used as an argument for this predicate.</param> + public TP(string operatorName, string value, P other = null) : base(operatorName, value, other) + { + } + +<% tpmethods.each { method -> %> + public static TP <%= toCSharpMethodName.call(method) %>(string value) + { + return new TP("<%= method %>", value); + } +<% } %> + + private static T[] ToGenericArray<T>(ICollection<T> collection) + { + return collection?.ToArray() ?? new T[0]; + } + + /// <inheritdoc /> + public override string ToString() + { + return Other == null ? \$"{OperatorName}({Value})" : \$"{OperatorName}({Value},{Other})"; + } + } + +#pragma warning restore 1591 +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-dotnet/glv/generate.groovy ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/glv/generate.groovy b/gremlin-dotnet/glv/generate.groovy index 0c93f3d..3dbd959 100644 --- a/gremlin-dotnet/glv/generate.groovy +++ b/gremlin-dotnet/glv/generate.groovy @@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource 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.P +import org.apache.tinkerpop.gremlin.process.traversal.TP import org.apache.tinkerpop.gremlin.process.traversal.IO import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__ import org.apache.tinkerpop.gremlin.structure.Direction @@ -59,6 +60,7 @@ def toCSharpTypeMap = ["Long": "long", "Traversal[]": "ITraversal[]", "Predicate": "IPredicate", "P": "P", + "TP": "TP", "TraversalStrategy": "ITraversalStrategy", "TraversalStrategy[]": "ITraversalStrategy[]", "Function": "IFunction", @@ -241,6 +243,12 @@ def binding = ["pmethods": P.class.getMethods(). collect { it.name }. unique(). sort { a, b -> a <=> b }, + "tpmethods": TP.class.getMethods(). + findAll { Modifier.isStatic(it.getModifiers()) }. + findAll { TP.class.isAssignableFrom(it.returnType) }. + collect { it.name }. + unique(). + sort { a, b -> a <=> b }, "sourceStepMethods": GraphTraversalSource.getMethods(). // SOURCE STEPS findAll { GraphTraversalSource.class.equals(it.returnType) }. findAll { @@ -334,6 +342,10 @@ def pTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/P.template def pFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/P.cs") pFile.newWriter().withWriter{ it << pTemplate } +def tpTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/TP.template")).make(binding) +def tpFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/TP.cs") +tpFile.newWriter().withWriter{ it << tpTemplate } + binding.tokens.each {k,v -> def tokenTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Token.template")).make([tokenFields: v, tokenName: k]) def tokenFile = new File("${projectBaseDir}/src/Gremlin.Net/Process/Traversal/${k}.cs") @@ -382,4 +394,4 @@ def templateCsprojFile = new File("${projectBaseDir}/src/Gremlin.Net.Template/Gr templateCsprojFile.newWriter().withWriter{ it << templateCsprojTemplate } def nuspecTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/Gremlin.Net.Template.nuspec.template")).make(["projectVersion":versionToUse]) def nuspecFile = new File("${projectBaseDir}/src/Gremlin.Net.Template/Gremlin.Net.Template.nuspec") -nuspecFile.newWriter().withWriter{ it << nuspecTemplate } \ No newline at end of file +nuspecFile.newWriter().withWriter{ it << nuspecTemplate } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TP.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TP.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TP.cs new file mode 100644 index 0000000..ac6415d --- /dev/null +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/TP.cs @@ -0,0 +1,96 @@ +#region License + +/* + * 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. + */ + +#endregion + +// THIS IS A GENERATED FILE - DO NOT MODIFY THIS FILE DIRECTLY - see pom.xml +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Gremlin.Net.Process.Traversal +{ +#pragma warning disable 1591 + + /// <summary> + /// A <see cref="TP" /> is a predicate of the form Func<string, bool>. + /// That is, given some string, return true or false. + /// </summary> + public class TP : P + { + /// <summary> + /// Initializes a new instance of the <see cref="P" /> class. + /// </summary> + /// <param name="operatorName">The name of the predicate.</param> + /// <param name="value">The value of the predicate.</param> + /// <param name="other">An optional other predicate that is used as an argument for this predicate.</param> + public TP(string operatorName, string value, P other = null) : base(operatorName, value, other) + { + } + + + public static TP Absent(string value) + { + return new TP("absent", value); + } + + public static TP Contains(string value) + { + return new TP("contains", value); + } + + public static TP EndsNotWith(string value) + { + return new TP("endsNotWith", value); + } + + public static TP EndsWith(string value) + { + return new TP("endsWith", value); + } + + public static TP StartsNotWith(string value) + { + return new TP("startsNotWith", value); + } + + public static TP StartsWith(string value) + { + return new TP("startsWith", value); + } + + + private static T[] ToGenericArray<T>(ICollection<T> collection) + { + return collection?.ToArray() ?? new T[0]; + } + + /// <inheritdoc /> + public override string ToString() + { + return Other == null ? $"{OperatorName}({Value})" : $"{OperatorName}({Value},{Other})"; + } + } + +#pragma warning restore 1591 +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs index 9349e57..3178d21 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs @@ -58,6 +58,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON {typeof(Type), new ClassSerializer()}, {typeof(EnumWrapper), new EnumSerializer()}, {typeof(P), new PSerializer()}, + {typeof(TP), new TPSerializer()}, {typeof(Vertex), new VertexSerializer()}, {typeof(Edge), new EdgeSerializer()}, {typeof(Property), new PropertySerializer()}, @@ -163,4 +164,4 @@ namespace Gremlin.Net.Structure.IO.GraphSON yield return ToDict(e); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TPSerializer.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TPSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TPSerializer.cs new file mode 100644 index 0000000..22ed358 --- /dev/null +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/TPSerializer.cs @@ -0,0 +1,45 @@ +#region License + +/* + * 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. + */ + +#endregion + +using System.Collections.Generic; +using Gremlin.Net.Process.Traversal; + +namespace Gremlin.Net.Structure.IO.GraphSON +{ + internal class TPSerializer : IGraphSONSerializer + { + public Dictionary<string, dynamic> Dictify(dynamic predicate, GraphSONWriter writer) + { + TP p = predicate; + var value = p.Other == null + ? writer.ToDict(p.Value) + : new List<dynamic> {writer.ToDict(p.Value), writer.ToDict(p.Other)}; + var dict = new Dictionary<string, dynamic> + { + {"predicate", p.OperatorName}, + {"value", value} + }; + return GraphSONUtil.ToTypedValue("TP", dict); + } + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java ---------------------------------------------------------------------- diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java index 48ba882..77e2583 100644 --- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java +++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GroovyTranslator.java @@ -23,6 +23,7 @@ import org.apache.commons.configuration.ConfigurationConverter; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; @@ -198,6 +199,7 @@ public final class GroovyTranslator implements Translator.ScriptTranslator { } private StringBuilder convertPToString(final P p, final StringBuilder current) { + if (p instanceof TP) return convertTPToString((TP) p, current); if (p instanceof ConnectiveP) { final List<P<?>> list = ((ConnectiveP) p).getPredicates(); for (int i = 0; i < list.size(); i++) { @@ -210,4 +212,9 @@ public final class GroovyTranslator implements Translator.ScriptTranslator { current.append("P.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")"); return current; } + + private StringBuilder convertTPToString(final TP p, final StringBuilder current) { + current.append("TP.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")"); + return current; + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-javascript/glv/TraversalSource.template ---------------------------------------------------------------------- diff --git a/gremlin-javascript/glv/TraversalSource.template b/gremlin-javascript/glv/TraversalSource.template index ffe0fbc..14df95b 100644 --- a/gremlin-javascript/glv/TraversalSource.template +++ b/gremlin-javascript/glv/TraversalSource.template @@ -162,6 +162,48 @@ function createP(operator, args) { return new (Function.prototype.bind.apply(P, args)); } +class TP { + /** + * Represents an operation. + * @constructor + */ + constructor(operator, value, other) { + this.operator = operator; + this.value = value; + this.other = other; + } + + /** + * Returns the string representation of the instance. + * @returns {string} + */ + toString() { + if (this.other === undefined) { + return this.operator + '(' + this.value + ')'; + } + return this.operator + '(' + this.value + ', ' + this.other + ')'; + } + + and(arg) { + return new P('and', this, arg); + } + + or(arg) { + return new P('or', this, arg); + } +<% tpmethods.each{ method -> %> + /** @param {...Object} args */ + static <%= toJs.call(method) %>(...args) { + return createTP('<%= method %>', args); + } +<% } %> +} + +function createTP(operator, args) { + args.unshift(null, operator); + return new (Function.prototype.bind.apply(TP, args)); +} + class Traverser { constructor(object, bulk) { this.object = object; @@ -199,6 +241,7 @@ class EnumValue { module.exports = { EnumValue, P, + TP, IO, Traversal, TraversalSideEffects, @@ -208,4 +251,4 @@ enums.each{ enumClass -> enumClass.getEnumConstants().sort { a, b -> a.name() <=> b.name() }.collect { toJs.call(it.name()) }.join(' ') + "')" } %> -}; \ No newline at end of file +}; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-javascript/glv/generate.groovy ---------------------------------------------------------------------- diff --git a/gremlin-javascript/glv/generate.groovy b/gremlin-javascript/glv/generate.groovy index aab55d4..243c607 100644 --- a/gremlin-javascript/glv/generate.groovy +++ b/gremlin-javascript/glv/generate.groovy @@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource 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.P +import org.apache.tinkerpop.gremlin.process.traversal.TP import org.apache.tinkerpop.gremlin.process.traversal.IO import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__ import java.lang.reflect.Modifier @@ -69,6 +70,12 @@ def binding = ["enums": CoreImports.getClassImports() collect { it.name }. unique(). sort { a, b -> a <=> b }, + "tpmethods": TP.class.getMethods(). + findAll { Modifier.isStatic(it.getModifiers()) }. + findAll { TP.class.isAssignableFrom(it.returnType) }. + collect { it.name }. + unique(). + sort { a, b -> a <=> b }, "sourceStepMethods": GraphTraversalSource.getMethods(). // SOURCE STEPS findAll { GraphTraversalSource.class.equals(it.returnType) }. findAll { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js index c2e810d..b15ecbc 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/index.js @@ -49,6 +49,7 @@ module.exports = { Bytecode: Bytecode, EnumValue: t.EnumValue, P: t.P, + TP: t.TP, Traversal: t.Traversal, TraversalSideEffects: t.TraversalSideEffects, TraversalStrategies: strategiesModule.TraversalStrategies, http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js index 2b9ba26..50a7a3e 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js @@ -310,6 +310,66 @@ function createP(operator, args) { return new (Function.prototype.bind.apply(P, args)); } +class TP { + /** + * Represents an operation. + * @constructor + */ + constructor(operator, value, other) { + this.operator = operator; + this.value = value; + this.other = other; + } + + /** + * Returns the string representation of the instance. + * @returns {string} + */ + toString() { + if (this.other === undefined) { + return this.operator + '(' + this.value + ')'; + } + return this.operator + '(' + this.value + ', ' + this.other + ')'; + } + + + /** @param {...Object} args */ + static absent(...args) { + return createTP('absent', args); + } + + /** @param {...Object} args */ + static contains(...args) { + return createTP('contains', args); + } + + /** @param {...Object} args */ + static endsNotWith(...args) { + return createTP('endsNotWith', args); + } + + /** @param {...Object} args */ + static endsWith(...args) { + return createTP('endsWith', args); + } + + /** @param {...Object} args */ + static startsNotWith(...args) { + return createTP('startsNotWith', args); + } + + /** @param {...Object} args */ + static startsWith(...args) { + return createTP('startsWith', args); + } + +} + +function createTP(operator, args) { + args.unshift(null, operator); + return new (Function.prototype.bind.apply(TP, args)); +} + class Traverser { constructor(object, bulk) { this.object = object; @@ -347,6 +407,7 @@ class EnumValue { module.exports = { EnumValue, P, + TP, IO, Traversal, TraversalSideEffects, @@ -363,4 +424,4 @@ module.exports = { pop: toEnum('Pop', 'all first last mixed'), scope: toEnum('Scope', 'global local'), t: toEnum('T', 'id key label value') -}; \ No newline at end of file +}; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js index 0e17cc8..ca81c2a 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js @@ -150,6 +150,28 @@ class PSerializer extends TypeSerializer { } } +class TPSerializer extends TypeSerializer { + /** @param {TP} item */ + serialize(item) { + const result = {}; + result[typeKey] = 'g:TP'; + const resultValue = result[valueKey] = { + 'predicate': item.operator + }; + if (item.other === undefined || item.other === null) { + resultValue['value'] = this.writer.adaptObject(item.value); + } + else { + resultValue['value'] = [ this.writer.adaptObject(item.value), this.writer.adaptObject(item.other) ]; + } + return result; + } + + canBeUsedFor(value) { + return (value instanceof t.TP); + } +} + class LambdaSerializer extends TypeSerializer { /** @param {Function} item */ serialize(item) { @@ -391,4 +413,4 @@ module.exports = { valueKey, VertexPropertySerializer, VertexSerializer -}; \ No newline at end of file +}; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js index a0ddddb..abef2a2 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js @@ -218,6 +218,7 @@ function getSandbox(g, parameters) { }, Order: traversalModule.order, P: traversalModule.P, + TP: traversalModule.TP, IO: traversalModule.IO, Pick: traversalModule.pick, Pop: traversalModule.pop, http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/glv/TraversalSource.template ---------------------------------------------------------------------- diff --git a/gremlin-python/glv/TraversalSource.template b/gremlin-python/glv/TraversalSource.template index 713681b..00a5934 100644 --- a/gremlin-python/glv/TraversalSource.template +++ b/gremlin-python/glv/TraversalSource.template @@ -152,6 +152,25 @@ def <%= method %>(*args): statics.add_static('<%= method %>',<%= method %>) <% } %> +class TP(P): + def __init__(self, operator, value, other=None): + P.__init__(self, operator, value, other) +<% tpmethods.each { method -> %> + @staticmethod + def <%= method %>(*args): + return TP("<%= toJava.call(method) %>", *args) +<% } %> + def __eq__(self, other): + return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other + + def __repr__(self): + return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")" +<% tpmethods.findAll{!it.equals("clone")}.each { method -> %> +def <%= method %>(*args): + return TP.<%= method %>(*args) +statics.add_static('<%= method %>',<%= method %>) +<% } %> + <% tokens.each { k,v -> %> ''' <%= k %> @@ -324,4 +343,4 @@ class Binding(object): return hash(self.key) + hash(self.value) def __repr__(self): - return "binding[" + self.key + "=" + str(self.value) + "]" \ No newline at end of file + return "binding[" + self.key + "=" + str(self.value) + "]" http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/glv/generate.groovy ---------------------------------------------------------------------- diff --git a/gremlin-python/glv/generate.groovy b/gremlin-python/glv/generate.groovy index c7ad241..8c3d647 100644 --- a/gremlin-python/glv/generate.groovy +++ b/gremlin-python/glv/generate.groovy @@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource 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.P +import org.apache.tinkerpop.gremlin.process.traversal.TP import org.apache.tinkerpop.gremlin.process.traversal.IO import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__ import java.lang.reflect.Modifier @@ -63,6 +64,12 @@ def binding = ["enums": CoreImports.getClassImports() collect { toPython(it.name) }. unique(). sort { a, b -> a <=> b }, + "tpmethods": TP.class.getMethods(). + findAll { Modifier.isStatic(it.getModifiers()) }. + findAll { TP.class.isAssignableFrom(it.returnType) }. + collect { toPython(it.name) }. + unique(). + sort { a, b -> a <=> b }, "sourceStepMethods": GraphTraversalSource.getMethods(). // SOURCE STEPS findAll { GraphTraversalSource.class.equals(it.returnType) }. findAll { @@ -102,4 +109,4 @@ traversalFile.newWriter().withWriter{ it << traversalTemplate } def graphTraversalTemplate = engine.createTemplate(new File("${projectBaseDir}/glv/GraphTraversalSource.template")).make(binding) def graphTraversalFile = new File("${projectBaseDir}/src/main/jython/gremlin_python/process/graph_traversal.py") -graphTraversalFile.newWriter().withWriter{ it << graphTraversalTemplate } \ No newline at end of file +graphTraversalFile.newWriter().withWriter{ it << graphTraversalTemplate } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java index 0bc324e..0d2695a 100644 --- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java +++ b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonTranslator.java @@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.Operator; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.Translator; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; @@ -224,6 +225,7 @@ public class PythonTranslator implements Translator.ScriptTranslator { } private StringBuilder convertPToString(final P p, final StringBuilder current) { + if (p instanceof TP) return convertTPToString((TP) p, current); if (p instanceof ConnectiveP) { final List<P<?>> list = ((ConnectiveP) p).getPredicates(); for (int i = 0; i < list.size(); i++) { @@ -237,6 +239,11 @@ public class PythonTranslator implements Translator.ScriptTranslator { return current; } + private StringBuilder convertTPToString(final TP p, final StringBuilder current) { + current.append(convertStatic("TP.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")"); + return current; + } + protected String convertLambdaToString(final Lambda lambda) { final String lambdaString = lambda.getLambdaScript().trim(); return lambdaString.startsWith("lambda") ? lambdaString : "lambda " + lambdaString; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/src/main/jython/gremlin_python/process/traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py index 094bd6d..4892bfc 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py @@ -322,6 +322,67 @@ def without(*args): statics.add_static('without',without) +class TP(object): + def __init__(self, operator, value, other=None): + self.operator = operator + self.value = value + self.other = other + + @staticmethod + def absent(*args): + return TP("absent", *args) + + @staticmethod + def contains(*args): + return TP("contains", *args) + + @staticmethod + def endsNotWith(*args): + return TP("endsNotWith", *args) + + @staticmethod + def endsWith(*args): + return TP("endsWith", *args) + + @staticmethod + def startsNotWith(*args): + return TP("startsNotWith", *args) + + @staticmethod + def startsWith(*args): + return TP("startsWith", *args) + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other + + def __repr__(self): + return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")" + +def absent(*args): + return TP.absent(*args) +statics.add_static('absent',absent) + +def contains(*args): + return TP.contains(*args) +statics.add_static('contains',contains) + +def endsNotWith(*args): + return TP.endsNotWith(*args) +statics.add_static('endsNotWith',endsNotWith) + +def endsWith(*args): + return TP.endsWith(*args) +statics.add_static('endsWith',endsWith) + +def startsNotWith(*args): + return TP.startsNotWith(*args) +statics.add_static('startsNotWith',startsNotWith) + +def startsWith(*args): + return TP.startsWith(*args) +statics.add_static('startsWith',startsWith) + + ''' IO @@ -556,4 +617,4 @@ class Binding(object): return hash(self.key) + hash(self.value) def __repr__(self): - return "binding[" + self.key + "=" + str(self.value) + "]" \ No newline at end of file + return "binding[" + self.key + "=" + str(self.value) + "]" http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py index d53a080..2cb0b5b 100644 --- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py +++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py @@ -27,7 +27,7 @@ from aenum import Enum from gremlin_python import statics from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType -from gremlin_python.process.traversal import Binding, Bytecode, P, Traversal, Traverser, TraversalStrategy +from gremlin_python.process.traversal import Binding, Bytecode, P, TP, Traversal, Traverser, TraversalStrategy from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path # When we fall back to a superclass's serializer, we iterate over this map. @@ -278,6 +278,17 @@ class PSerializer(_GraphSONTypeIO): return GraphSONUtil.typedValue("P", out) +class TPSerializer(_GraphSONTypeIO): + python_type = TP + + @classmethod + def dictify(cls, p, writer): + out = {"predicate": p.operator, + "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else + writer.toDict(p.value)} + return GraphSONUtil.typedValue("TP", out) + + class BindingSerializer(_GraphSONTypeIO): python_type = Binding http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py index 5539448..266e23d 100644 --- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py +++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV3d0.py @@ -27,7 +27,7 @@ from aenum import Enum from gremlin_python import statics from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType -from gremlin_python.process.traversal import Binding, Bytecode, P, Traversal, Traverser, TraversalStrategy, T +from gremlin_python.process.traversal import Binding, Bytecode, P, TP, Traversal, Traverser, TraversalStrategy, T from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path # When we fall back to a superclass's serializer, we iterate over this map. @@ -284,6 +284,17 @@ class PSerializer(_GraphSONTypeIO): return GraphSONUtil.typedValue("P", out) +class TPSerializer(_GraphSONTypeIO): + python_type = TP + + @classmethod + def dictify(cls, p, writer): + out = {"predicate": p.operator, + "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else + writer.toDict(p.value)} + return GraphSONUtil.typedValue("TP", out) + + class BindingSerializer(_GraphSONTypeIO): python_type = Binding http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-python/src/main/jython/radish/feature_steps.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/radish/feature_steps.py b/gremlin-python/src/main/jython/radish/feature_steps.py index aff73dc..151d6d5 100644 --- a/gremlin-python/src/main/jython/radish/feature_steps.py +++ b/gremlin-python/src/main/jython/radish/feature_steps.py @@ -21,7 +21,7 @@ import json import re from gremlin_python.structure.graph import Graph, Path from gremlin_python.process.graph_traversal import __ -from gremlin_python.process.traversal import Barrier, Cardinality, P, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO +from gremlin_python.process.traversal import Barrier, Cardinality, P, TP, Pop, Scope, Column, Order, Direction, T, Pick, Operator, IO from radish import given, when, then from hamcrest import * @@ -256,6 +256,7 @@ def _make_traversal(g, traversal_string, params): "Direction": Direction, "Order": Order, "P": P, + "TP": TP, "IO": IO, "Pick": Pick, "Pop": Pop, http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-test/features/filter/Has.feature ---------------------------------------------------------------------- diff --git a/gremlin-test/features/filter/Has.feature b/gremlin-test/features/filter/Has.feature index ddf9984..9d2bf4f 100644 --- a/gremlin-test/features/filter/Has.feature +++ b/gremlin-test/features/filter/Has.feature @@ -557,4 +557,59 @@ Feature: Step - has() When iterated to list Then the result should be unordered | result | - | d[6].l | \ No newline at end of file + | d[6].l | + + Scenario: g_V_hasXname_containsXarkXX + Given the modern graph + And the traversal of + """ + g.V().has("name", TP.contains("ark")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + + Scenario: g_V_hasXname_startsWithXmarXX + Given the modern graph + And the traversal of + """ + g.V().has("name", TP.startsWith("mar")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | + + Scenario: g_V_hasXname_endsWithXasXX + Given the modern graph + And the traversal of + """ + g.V().has("name", TP.endsWith("as")) + """ + When iterated to list + Then the result should be unordered + | result | + | v[vadas] | + + Scenario: g_V_hasXperson_name_containsXoX_andXltXmXXX + Given the modern graph + And the traversal of + """ + g.V().has("person", "name", TP.contains("o").and(P.lt("m"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[josh] | + + Scenario: g_V_hasXname_gtXmX_andXcontainsXoXXX + Given the modern graph + And the traversal of + """ + g.V().has("name", P.gt("m").and(TP.contains("o"))) + """ + When iterated to list + Then the result should be unordered + | result | + | v[marko] | http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d83f8af/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java index 3bdb24a..cb4abab 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasTest.java @@ -23,6 +23,7 @@ import org.apache.tinkerpop.gremlin.LoadGraphWith; import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TP; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.structure.Edge; @@ -125,6 +126,16 @@ public abstract class HasTest extends AbstractGremlinProcessTest { public abstract Traversal<Vertex, Long> get_g_V_hasXage_withoutX27_29X_count(); + public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_containsXarkXX(); + + public abstract Traversal<Vertex,Vertex> get_g_V_hasXname_startsWithXmarXX(); + + public abstract Traversal<Vertex,Vertex> get_g_V_hasXname_endsWithXasXX(); + + public abstract Traversal<Vertex,Vertex> get_g_V_hasXperson_name_containsXoX_andXltXmXXX(); + + public abstract Traversal<Vertex,Vertex> get_g_V_hasXname_gtXmX_andXcontainsXoXXX(); + @Test @LoadGraphWith(MODERN) public void g_V_outXcreatedX_hasXname__mapXlengthX_isXgtX3XXX_name() { @@ -547,6 +558,56 @@ public abstract class HasTest extends AbstractGremlinProcessTest { assertEquals(2L, traversal.next().longValue()); } + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_containsXarkXX() { + final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_containsXarkXX(); + printTraversalForm(traversal); + assertTrue(traversal.hasNext()); + assertTrue(traversal.next().value("name").equals("marko")); + assertFalse(traversal.hasNext()); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_startsWithXmarXX() { + final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_startsWithXmarXX(); + printTraversalForm(traversal); + assertTrue(traversal.hasNext()); + assertTrue(traversal.next().value("name").equals("marko")); + assertFalse(traversal.hasNext()); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_endsWithXasXX() { + final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_endsWithXasXX(); + printTraversalForm(traversal); + assertTrue(traversal.hasNext()); + assertTrue(traversal.next().value("name").equals("vadas")); + assertFalse(traversal.hasNext()); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXperson_name_containsXoX_andXltXmXXX() { + final Traversal<Vertex, Vertex> traversal = get_g_V_hasXperson_name_containsXoX_andXltXmXXX(); + printTraversalForm(traversal); + assertTrue(traversal.hasNext()); + assertTrue(traversal.next().value("name").equals("josh")); + assertFalse(traversal.hasNext()); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_gtXmX_andXcontainsXoXXX() { + final Traversal<Vertex, Vertex> traversal = get_g_V_hasXname_gtXmX_andXcontainsXoXXX(); + printTraversalForm(traversal); + assertTrue(traversal.hasNext()); + assertTrue(traversal.next().value("name").equals("marko")); + assertFalse(traversal.hasNext()); + } + public static class Traversals extends HasTest { @Override public Traversal<Edge, Edge> get_g_EX11X_outV_outE_hasXid_10X(final Object e11Id, final Object e10Id) { @@ -727,5 +788,30 @@ public abstract class HasTest extends AbstractGremlinProcessTest { public Traversal<Vertex, Long> get_g_V_hasXage_withoutX27_29X_count() { return g.V().has("age", P.without(27, 29)).count(); } + + @Override + public Traversal<Vertex, Vertex> get_g_V_hasXname_containsXarkXX() { + return g.V().has("name", TP.contains("ark")); + } + + @Override + public Traversal<Vertex, Vertex> get_g_V_hasXname_startsWithXmarXX() { + return g.V().has("name", TP.startsWith("mar")); + } + + @Override + public Traversal<Vertex, Vertex> get_g_V_hasXname_endsWithXasXX() { + return g.V().has("name", TP.endsWith("as")); + } + + @Override + public Traversal<Vertex, Vertex> get_g_V_hasXperson_name_containsXoX_andXltXmXXX() { + return g.V().has("person","name", TP.contains("o").and(P.lt("m"))); + } + + @Override + public Traversal<Vertex, Vertex> get_g_V_hasXname_gtXmX_andXcontainsXoXXX() { + return g.V().has("name", P.gt("m").and(TP.contains("o"))); + } } } \ No newline at end of file