This is an automated email from the ASF dual-hosted git repository. xiazcy pushed a commit to branch type-enum-poc in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit c9935f465cdcd78296124eb6f75f55d36578c563 Author: xiazcy <[email protected]> AuthorDate: Fri Sep 5 09:30:48 2025 -0700 Add mechanism for extending data type enums --- .../grammar/DefaultGremlinBaseVisitor.java | 15 +++ .../language/grammar/GenericLiteralVisitor.java | 5 + .../language/grammar/GremlinAntlrToJava.java | 7 ++ .../grammar/TraversalGremlinTypesVisitor.java | 55 ++++++++ .../language/grammar/TraversalMethodVisitor.java | 9 ++ .../grammar/TraversalPredicateVisitor.java | 10 +- .../translator/PythonTranslateVisitor.java | 2 +- .../tinkerpop/gremlin/process/traversal/P.java | 9 ++ .../tinkerpop/gremlin/process/traversal/Type.java | 64 ++++++++++ .../traversal/dsl/graph/GraphTraversal.java | 21 ++-- .../process/traversal/step/map/AsNumberStep.java | 26 +++- .../traversal/translator/PythonTranslator.java | 2 +- .../apache/tinkerpop/gremlin/structure/CType.java | 140 +++++++++++++++++++++ .../tinkerpop/gremlin/structure/CustomType.java | 42 +++++++ .../apache/tinkerpop/gremlin/structure/GType.java | 71 +++++++++++ .../gremlin/structure/GremlinDataType.java | 113 +++++++++++++++++ .../apache/tinkerpop/gremlin/structure/NType.java | 59 +++++++++ .../apache/tinkerpop/gremlin/structure/Point.java | 56 +++++++++ .../gremlin/structure/io/binary/DataType.java | 1 + .../io/binary/TypeSerializerRegistry.java | 10 +- .../structure/io/binary/types/EnumSerializer.java | 2 + .../io/binary/types/GremlinDataTypeSerializer.java | 96 ++++++++++++++ .../tinkerpop/gremlin/util/NumberHelper.java | 10 ++ .../language/translator/GremlinTranslatorTest.java | 4 +- .../tinkerpop/gremlin/process/traversal/PTest.java | 7 ++ .../traversal/step/map/AsNumberStepTest.java | 3 + gremlin-language/src/main/antlr4/Gremlin.g4 | 17 +++ .../gremlin/server/GremlinDriverIntegrateTest.java | 30 ++++- 28 files changed, 857 insertions(+), 29 deletions(-) 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 d988430a26..a3b8f841aa 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 @@ -1082,6 +1082,9 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im /** * {@inheritDoc} */ + @Override public T visitTraversalMethod_asNumber_traversalGremlinTypes(final GremlinParser.TraversalMethod_asNumber_traversalGremlinTypesContext ctx) { notImplemented(ctx); return null; }/** + * {@inheritDoc} + */ @Override public T visitTraversalScope(final GremlinParser.TraversalScopeContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} @@ -1123,6 +1126,10 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im * {@inheritDoc} */ @Override public T visitTraversalN(GremlinParser.TraversalNContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalGremlinTypes(final GremlinParser.TraversalGremlinTypesContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ @@ -1155,6 +1162,14 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im * {@inheritDoc} */ @Override public T visitTraversalPredicate_neq(final GremlinParser.TraversalPredicate_neqContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalPredicate_typeOf(final GremlinParser.TraversalPredicate_typeOfContext ctx) { notImplemented(ctx); return null; } +// /** +// * {@inheritDoc} +// */ +// @Override public T visitTraversalPredicate_nof(final GremlinParser.TraversalPredicate_nofContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java index eb0b9dc343..d9a909bfd6 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java @@ -606,6 +606,11 @@ public class GenericLiteralVisitor extends DefaultGremlinBaseVisitor<Object> { return TraversalEnumParser.parseTraversalNFromContext(ctx); } + @Override + public Object visitTraversalGremlinTypes(final GremlinParser.TraversalGremlinTypesContext ctx) { + return antlr.traversalGremlinTypesVisitor.visitGremlinDataType(ctx); + } + @Override public Object visitTraversalStrategy(final GremlinParser.TraversalStrategyContext ctx) { return antlr.traversalStrategyVisitor.visitTraversalStrategy(ctx); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java index ab6dbccb0a..f7f270e3ae 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java @@ -29,6 +29,7 @@ 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.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.GremlinDataType; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; @@ -94,6 +95,11 @@ public class GremlinAntlrToJava extends DefaultGremlinBaseVisitor<Object> { */ final TraversalStrategyVisitor traversalStrategyVisitor; + /** + * Parses {@link GremlinDataType} instances. + */ + final TraversalGremlinTypesVisitor traversalGremlinTypesVisitor; + /** * Parses {@link P} instances. */ @@ -191,6 +197,7 @@ public class GremlinAntlrToJava extends DefaultGremlinBaseVisitor<Object> { this.txVisitor = new TraversalSourceTxVisitor(g, this); this.traversalPredicateVisitor = new TraversalPredicateVisitor(this); this.traversalStrategyVisitor = new TraversalStrategyVisitor(this); + this.traversalGremlinTypesVisitor = new TraversalGremlinTypesVisitor(this); this.genericVisitor = new GenericLiteralVisitor(this); this.argumentVisitor = new ArgumentVisitor(variableResolver, this); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalGremlinTypesVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalGremlinTypesVisitor.java new file mode 100644 index 0000000000..5489028715 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalGremlinTypesVisitor.java @@ -0,0 +1,55 @@ +/* + * 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.apache.tinkerpop.gremlin.structure.GremlinDataType; + +import java.util.Optional; + +public class TraversalGremlinTypesVisitor { + protected final GremlinAntlrToJava antlr; + + public TraversalGremlinTypesVisitor(final GremlinAntlrToJava antlrToJava) { + this.antlr = antlrToJava; + } + + public GremlinDataType visitGremlinDataType(final GremlinParser.TraversalGremlinTypesContext ctx) { + return tryToConstructGremlinDataType(ctx.getText()); + } + + /** + * Try to instantiate by checking registered {@link GremlinDataType} implementations that are + * registered globally. Only strategies that are registered globally can be constructed in this way. + */ + private static GremlinDataType tryToConstructGremlinDataType(final String typeName) { + System.out.println(typeName); + + // try to grab the class from registered sources + final Optional<GremlinDataType> opt = GremlinDataType.GlobalTypeCache.getRegisteredType(typeName); + + System.out.println(opt); + + if (opt.isEmpty()) + throw new IllegalStateException("GremlinDataType not recognized - " + typeName); + + return opt.get(); + + } + +} 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 058dea096a..1e2546ec86 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 @@ -2128,6 +2128,15 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> TraversalEnumParser.parseTraversalNFromContext(ctx.traversalN())); } + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_asNumber_traversalGremlinTypes(final GremlinParser.TraversalMethod_asNumber_traversalGremlinTypesContext ctx) { + return graphTraversal.asNumber( + antlr.traversalGremlinTypesVisitor.visitGremlinDataType(ctx.traversalGremlinTypes())); + } + public GraphTraversal[] getNestedTraversalList(final GremlinParser.NestedTraversalListContext ctx) { return ctx.nestedTraversalExpr().nestedTraversal() .stream() 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 ca481c8638..849c68be22 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 @@ -23,8 +23,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.TextP; import java.util.Collection; -import java.util.List; -import java.util.Set; public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> { @@ -79,6 +77,14 @@ public class TraversalPredicateVisitor extends DefaultGremlinBaseVisitor<P> { return P.neq(getSingleGenericLiteralArgument(ctx)); } + /** + * {@inheritDoc} + */ + @Override + public P visitTraversalPredicate_typeOf(final GremlinParser.TraversalPredicate_typeOfContext ctx) { + return P.typeOf(getSingleGenericLiteralArgument(ctx)); + } + /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java index 971e61805b..b38b9255bd 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java @@ -111,7 +111,7 @@ public class PythonTranslateVisitor extends AbstractTranslateVisitor { public Void visitClassType(final GremlinParser.ClassTypeContext ctx) { final Optional<? extends Class<? extends TraversalStrategy>> strategy = TraversalStrategies.GlobalCache.getRegisteredStrategyClass(ctx.getText()); final String fqcn = strategy.map(Class::getName).orElse(ctx.getText()); - sb.append("GremlinType('").append(fqcn).append("')"); + sb.append("GremlinDataType('").append(fqcn).append("')"); return null; } 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 917a13891d..718473da76 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 @@ -145,6 +145,15 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable { return new P(Compare.neq, value); } + /** + * Determines if values are of a type. + * + * @since 3.8.0-incubating + */ + public static <V> P<V> typeOf(final V value) { + return new P(Type.typeOf, value); + } + /** * Determines if a value is less than another. * diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Type.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Type.java new file mode 100644 index 0000000000..f1080f0bc1 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Type.java @@ -0,0 +1,64 @@ +/* + * 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.structure.GremlinDataType; + +import java.util.Optional; + +/** + * {@code Type} is a {@code BiPredicate} that determines whether the first argument is a type of the second argument. + * + */ +public enum Type implements PBiPredicate<Object, Object> { + + /** + * Evaluates if the first object is equal to the second per Gremlin Comparison semantics. + * + * @since 3.8.0 + */ + typeOf { + @Override + public boolean test(final Object first, final Object second) { + Class<?> secondClass; + if (second instanceof GremlinDataType) { + secondClass = ((GremlinDataType) second).getType(); + } else if (second instanceof String) { + try { + // for java class names + secondClass = Class.forName((String) second); + } catch (ClassNotFoundException e) { + // for string name of type token we can use the cache + final Optional<GremlinDataType> opt = GremlinDataType.GlobalTypeCache.getRegisteredType((String) second); + if (opt.isEmpty()) + return false; + else + secondClass = opt.get().getType(); + } + } else if (second instanceof Class) { + secondClass = (Class<?>) second; + } else { + return false; + } + + return (secondClass).isAssignableFrom(first.getClass()); + } + + }, +} 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 2d70e4e155..e479b4be63 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 @@ -195,16 +195,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions; 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.structure.Column; -import org.apache.tinkerpop.gremlin.structure.Direction; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Element; -import org.apache.tinkerpop.gremlin.structure.Graph; -import org.apache.tinkerpop.gremlin.structure.Property; -import org.apache.tinkerpop.gremlin.structure.PropertyType; -import org.apache.tinkerpop.gremlin.structure.T; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.apache.tinkerpop.gremlin.structure.*; import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier; import java.time.OffsetDateTime; @@ -1954,6 +1945,16 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { return this.asAdmin().addStep(new AsNumberStep<>(this.asAdmin(), numberToken)); } + public default GraphTraversal<S, Number> asNumber(final GremlinDataType numberToken) { + this.asAdmin().getBytecode().addStep(Symbols.asNumber, numberToken); + return this.asAdmin().addStep(new AsNumberStep<>(this.asAdmin(), numberToken)); + } + + public default GraphTraversal<S, Number> asNumber(final Class numberToken) { + this.asAdmin().getBytecode().addStep(Symbols.asNumber, numberToken); + return this.asAdmin().addStep(new AsNumberStep<>(this.asAdmin(), numberToken)); + } + /** * Calculates the difference between the list traverser and list argument. * diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java index 29ea0007e7..92bacc904d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java @@ -23,6 +23,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.N; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; +import org.apache.tinkerpop.gremlin.structure.GType; +import org.apache.tinkerpop.gremlin.structure.GremlinDataType; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.NumberHelper; @@ -35,6 +37,8 @@ import java.util.Set; public class AsNumberStep<S> extends ScalarMapStep<S, Number> { private N numberToken; + private GremlinDataType gDT; + private Class<?> clazz; public AsNumberStep(final Traversal.Admin traversal) { super(traversal); @@ -46,16 +50,30 @@ public class AsNumberStep<S> extends ScalarMapStep<S, Number> { this.numberToken = numberToken; } + public AsNumberStep(final Traversal.Admin traversal, final GremlinDataType numberToken) { + super(traversal); + this.gDT = numberToken; + } + + public AsNumberStep(final Traversal.Admin traversal, final Class<?> numberToken) { + super(traversal); + this.gDT = GType.valueOf(numberToken.getSimpleName().toUpperCase()); + } + @Override protected Number map(final Traverser.Admin<S> traverser) { final Object object = traverser.get(); if (object instanceof String) { String numberText = (String) object; Number number = parseNumber(numberText); - return numberToken == null ? number : castNumber(number, numberToken); + return numberToken == null ? (gDT == null ? number : castNumber(number, gDT)) + : castNumber(number, numberToken); +// return numberToken == null ? number : castNumber(number, numberToken); } else if (object instanceof Number) { Number number = (Number) object; - return numberToken == null ? number : castNumber(number, numberToken); + return numberToken == null ? (gDT == null ? number : castNumber(number, gDT)) + : castNumber(number, numberToken); +// return numberToken == null ? number : castNumber(number, numberToken); } throw new IllegalArgumentException(String.format("Can't parse type %s as number.", object == null ? "null" : object.getClass().getSimpleName())); } @@ -100,4 +118,8 @@ public class AsNumberStep<S> extends ScalarMapStep<S, Number> { return NumberHelper.castTo(number, numberToken); } + private static Number castNumber(final Number number, final GremlinDataType numberToken) { + return NumberHelper.castTo(number, numberToken); + } + } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java index 907ef242b3..ae342b5771 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java @@ -260,7 +260,7 @@ public final class PythonTranslator implements Translator.ScriptTranslator { @Override protected Script produceScript(final Class<?> o) { - return script.append("GremlinType('" + o.getCanonicalName() + "')"); + return script.append("GremlinDataType('" + o.getCanonicalName() + "')"); } @Override diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/CType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/CType.java new file mode 100644 index 0000000000..e18e4a9036 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/CType.java @@ -0,0 +1,140 @@ +/* + * 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.structure; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +public enum CType implements GremlinDataType{ + ; + + // Registry for custom type mappings + private static final ConcurrentMap<String, CustomTypeInfo> CUSTOM_REGISTRY = new ConcurrentHashMap<>(); + + // Instance fields for the enum + private final Class<?> javaType; + + CType(Class<?> javaType) { + this.javaType = javaType; + } + + + @Override + public String getName() { + return ""; + } + + @Override + public Class<?> getType() { + return null; + } + + @Override + public GremlinDataType fromName(String name) { + return null; + } + + + /** + * Register a custom TypeToken enum class + */ + public static <E extends Enum<E> & GremlinDataType> void register( + String customTypeName, + Class<E> enumClass, + Function<String, E> factory) { + + CUSTOM_REGISTRY.put(customTypeName, new CustomTypeInfo(enumClass, factory)); + } + + /** + * Register using reflection (convenience method) + */ + public static <E extends Enum<E> & GremlinDataType> void register( + String customTypeName, + Class<E> enumClass) { + + register(customTypeName, enumClass, name -> Enum.valueOf(enumClass, name)); + } + + /** + * Create a TypeToken instance from a custom type registration + */ + public static Optional<GremlinDataType> createCustomInstance(String customTypeName, String enumValueName) { + CustomTypeInfo info = CUSTOM_REGISTRY.get(customTypeName); + if (info == null) { + return Optional.empty(); + } + + try { + return Optional.of(info.factory.apply(enumValueName)); + } catch (Exception e) { + return Optional.empty(); + } + } + + /** + * Get the custom type name for a TypeToken instance + */ + public static Optional<String> getCustomTypeName(GremlinDataType token) { + Class<?> tokenClass = token.getClass(); + return CUSTOM_REGISTRY.entrySet().stream() + .filter(entry -> entry.getValue().enumClass.equals(tokenClass)) + .map(Map.Entry::getKey) + .findFirst(); + } + + /** + * Check if a custom type is registered + */ + public static boolean isCustomTypeRegistered(String customTypeName) { + return CUSTOM_REGISTRY.containsKey(customTypeName); + } + + /** + * Get all registered custom type names + */ + public static Set<String> getRegisteredCustomTypes() { + return Collections.unmodifiableSet(CUSTOM_REGISTRY.keySet()); + } + + /** + * Check if a TypeToken instance is a custom type + */ + public static boolean isCustomType(GremlinDataType token) { + return getCustomTypeName(token).isPresent(); + } + + // Internal class to hold registration info + private static class CustomTypeInfo { + final Class<? extends Enum<? extends GremlinDataType>> enumClass; + final Function<String, ? extends GremlinDataType> factory; + + CustomTypeInfo(Class<? extends Enum<? extends GremlinDataType>> enumClass, + Function<String, ? extends GremlinDataType> factory) { + this.enumClass = enumClass; + this.factory = factory; + } + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/CustomType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/CustomType.java new file mode 100644 index 0000000000..a47a2fd990 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/CustomType.java @@ -0,0 +1,42 @@ +/* + * 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.structure; + +/** + * Custom types + */ +public enum CustomType implements GremlinDataType { + POINT(Point.class); + + private final Class<?> javaType; + + CustomType(Class<?> javaType) { + this.javaType = javaType; + } + + @Override + public String getName() { return this.name(); } + + @Override + public Class<?> getType() { return javaType; } + + @Override + public GremlinDataType fromName(String name) { return CustomType.valueOf(name.toUpperCase()); } + +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/GType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/GType.java new file mode 100644 index 0000000000..1a92fadfe0 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/GType.java @@ -0,0 +1,71 @@ +/* + * 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.structure; + +import org.apache.tinkerpop.gremlin.util.NumberHelper; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * Gremlin types + */ +public enum GType implements GremlinDataType { + BIG_DECIMAL(BigDecimal.class), + BIG_INTEGER(BigInteger.class), + BOOLEAN(Boolean.class), + BYTE(Byte.class), + CHARACTER(Character.class), + DATETIME(OffsetDateTime.class), + DOUBLE(Double.class), + FLOAT(Float.class), + INT(int.class), + INTEGER(Integer.class), + LIST(List.class), + LONG(Long.class), + MAP(Map.class), + NUMBER(Number.class), + SET(Set.class), + SHORT(Short.class), + STRING(String.class), + UNKNOWN(null), + UUID(UUID.class), + VERTEX(Vertex.class),; + + private final Class<?> javaType; + + GType(Class<?> javaType) { + this.javaType = javaType; + } + + @Override + public String getName() { return this.name(); } + + @Override + public Class<?> getType() { return javaType; } + + @Override + public GremlinDataType fromName(String name) { return GType.valueOf(name.toUpperCase()); } + +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/GremlinDataType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/GremlinDataType.java new file mode 100644 index 0000000000..bef28c679e --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/GremlinDataType.java @@ -0,0 +1,113 @@ +/* + * 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.structure; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public interface GremlinDataType { + + String getName(); + Class<?> getType(); + GremlinDataType fromName(String name); + + // Optional: provide default categorization methods + default boolean isPrimitive() { + return getType().isPrimitive(); + } + + default boolean isNumeric() { + Class<?> type = getType(); + return type == int.class || type == Integer.class || + type == long.class || type == Long.class || + type == double.class || type == Double.class || + type == float.class || type == Float.class || + type == BigDecimal.class || type == BigInteger.class; + } + + final class GlobalTypeCache { + + private GlobalTypeCache() { + throw new IllegalStateException("Utility class"); + } + + /** + * A register of the simple names for all strategies. + */ + private static final Map<String, GremlinDataType> GLOBAL_TYPE_REGISTRY = new ConcurrentHashMap<>() {}; + + static { + for (GremlinDataType value : GType.values()) { + GLOBAL_TYPE_REGISTRY.put("GType." + value.getName(), value); + } + } + + /** + * Registers all constants of a GremlinDataType class by its name (formatted as {GremlinDataType}.{TYPE}), so + * it is available to the grammar when parsing Gremlin. + */ + public static void registerDataType(final Class<? extends Enum<? extends GremlinDataType>> enumClass) { + for (Enum<? extends GremlinDataType> constant : enumClass.getEnumConstants()) { + GLOBAL_TYPE_REGISTRY.put(enumClass.getSimpleName() + "." + constant.name(), (GremlinDataType) constant); + } + } + + /** + * Unregisters a single GremlinDataType Enum constant by its name (formatted as {GremlinDataType}.{TYPE}). + * If the GremlinDataType is not in the registry then the grammar cannot reference it + */ + public static void registerDataType(final String name, final GremlinDataType gdt) { + GLOBAL_TYPE_REGISTRY.put(name, gdt); + } + + /** + * Unregisters all constants of a GremlinDataType class. If the GremlinDataType is not in the registry then the + * grammar cannot reference it + */ + public static void unregisterDataType(final Class<? extends Enum<? extends GremlinDataType>> enumClass) { + for (Enum<? extends GremlinDataType> constant : enumClass.getEnumConstants()) { + GLOBAL_TYPE_REGISTRY.remove(enumClass.getSimpleName() + "." + constant.name()); + } + } + + /** + * Unregisters a single GremlinDataType by its name (formatted as {GremlinDataType}.{TYPE}). If the GremlinDataType + * is not in the registry then the grammar cannot reference it + */ + public static void unregisterDataType(final String name) { + GLOBAL_TYPE_REGISTRY.remove(name); + } + + /** + * Looks up a Gremlin DataType by its simple name. + */ + public static Optional<GremlinDataType> getRegisteredType(final String typeName) { + System.out.println(GLOBAL_TYPE_REGISTRY); + if (GLOBAL_TYPE_REGISTRY.containsKey(typeName)) + return Optional.of(GLOBAL_TYPE_REGISTRY.get(typeName)); + + return Optional.empty(); + } + + } + +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/NType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/NType.java new file mode 100644 index 0000000000..71219b7f26 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/NType.java @@ -0,0 +1,59 @@ +/* + * 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.structure; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * Number types + */ +public enum NType implements GremlinDataType { + BYTE(Byte.class), + SHORT(Short.class), + INT(int.class), + INTEGER(Integer.class), + LONG(Long.class), + FLOAT(Float.class), + DOUBLE(Double.class), + BIG_INTEGER(BigInteger.class), + BIG_DECIMAL(BigDecimal.class),; + + private final Class<?> javaType; + + NType(Class<?> javaType) { + this.javaType = javaType; + } + + @Override + public String getName() { return this.name(); } + + @Override + public Class<?> getType() { return javaType; } + + @Override + public GremlinDataType fromName(String name) { return NType.valueOf(name.toUpperCase()); } + + static { + // register types +// for (GremlinDataType value : NType.values()) { +// GremlinDataType.GlobalTypeCache.registerDataType("NType." + value.getName(), value); +// } + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Point.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Point.java new file mode 100644 index 0000000000..25d27e25f8 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Point.java @@ -0,0 +1,56 @@ +/* + * 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.structure; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +public class Point { + private Integer x; + private Integer y; + + // constructors + public Point(final Integer x, final Integer y) { + this.x = x; + this.y = y; + } + + // getters and setters + public Integer getX() { + return x; + } + + public Integer getY() { + return y; + } + + public void setX(final Integer x) { + this.x = x; + } + + public void setY(final Integer y) { + this.y = y; + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java index c0738a3496..112ca4f52e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java @@ -73,6 +73,7 @@ public enum DataType { MERGE(0x2E), DT(0x2F), N(0x30), + GREMLINDATATYPE(0X31), CHAR(0X80), DURATION(0X81), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java index 62597d16d9..c535332d64 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java @@ -40,14 +40,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics; -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.Graph; -import org.apache.tinkerpop.gremlin.structure.Property; -import org.apache.tinkerpop.gremlin.structure.T; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.apache.tinkerpop.gremlin.structure.*; import org.apache.tinkerpop.gremlin.structure.io.IoRegistry; import org.apache.tinkerpop.gremlin.structure.io.binary.types.*; import org.apache.tinkerpop.gremlin.util.function.Lambda; @@ -123,6 +116,7 @@ public class TypeSerializerRegistry { new RegistryEntry<>(DT.class, EnumSerializer.DTSerializer), new RegistryEntry<>(Merge.class, EnumSerializer.MergeSerializer), new RegistryEntry<>(N.class, new NSerializer()), + new RegistryEntry<>(GremlinDataType.class, new GremlinDataTypeSerializer()), new RegistryEntry<>(Operator.class, EnumSerializer.OperatorSerializer), new RegistryEntry<>(Order.class, EnumSerializer.OrderSerializer), new RegistryEntry<>(Pick.class, EnumSerializer.PickSerializer), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java index 7ee0dd0406..fccf268607 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java @@ -58,6 +58,8 @@ public class EnumSerializer<E extends Enum> extends SimpleTypeSerializer<E> { public static final EnumSerializer<Pop> PopSerializer = new EnumSerializer<>(DataType.POP, Pop::valueOf); public static final EnumSerializer<Scope> ScopeSerializer = new EnumSerializer<>(DataType.SCOPE, Scope::valueOf); public static final EnumSerializer<T> TSerializer = new EnumSerializer<>(DataType.T, T::valueOf); +// public static final EnumSerializer<GType> GTypeSerializer = new EnumSerializer<>(DataType.GTYPE, GType::valueOf); +// public static final EnumSerializer<NType> NTypeSerializer = new EnumSerializer<>(DataType.NTYPE, NType::valueOf); private final Function<String, E> readFunc; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GremlinDataTypeSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GremlinDataTypeSerializer.java new file mode 100644 index 0000000000..c3c645e9ca --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GremlinDataTypeSerializer.java @@ -0,0 +1,96 @@ +/* + * 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.structure.io.binary.types; + +import org.apache.tinkerpop.gremlin.structure.GType; +import org.apache.tinkerpop.gremlin.structure.GremlinDataType; +import org.apache.tinkerpop.gremlin.structure.io.Buffer; +import org.apache.tinkerpop.gremlin.structure.io.binary.DataType; +import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader; +import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class GremlinDataTypeSerializer extends SimpleTypeSerializer<GremlinDataType> { + // Registry of all known TypeToken implementations + private static final Map<String, TypeTokenFactory> TYPE_FACTORIES = new HashMap<>(); + + static { + // Register your enum types here + registerTypeFactory("GType", GType::valueOf); + // Add more as needed + } + + public GremlinDataTypeSerializer() { + super(DataType.GREMLINDATATYPE); + } + + /** + * Register a factory for creating TypeToken instances from strings + */ + public static void registerTypeFactory(String typeName, TypeTokenFactory factory) { + TYPE_FACTORIES.put(typeName, factory); + } + + @Override + protected GremlinDataType readValue(final Buffer buffer, final GraphBinaryReader context) throws IOException { + // Read the enum class name + final String enumClassName = context.read(buffer); + // Read the enum value name + final String enumValueName = context.read(buffer); + + System.out.println("Reading " + enumClassName + " with value " + enumValueName); + + TypeTokenFactory factory = TYPE_FACTORIES.get(enumClassName); + if (factory == null) { + throw new IOException("Unknown TypeToken enum class: " + enumClassName); + } + + try { + return factory.create(enumValueName); + } catch (Exception e) { + throw new IOException("Failed to create TypeToken for " + enumClassName + "." + enumValueName, e); + } + } + + @Override + protected void writeValue(final GremlinDataType value, final Buffer buffer, final GraphBinaryWriter context) throws IOException { + // Write the enum class name (simple name) + String enumClassName = value.getClass().getSimpleName(); + context.write(enumClassName, buffer); + + System.out.println("Writing " + enumClassName + " to " + buffer); + + // Write the enum value name + if (value instanceof Enum) { + context.write(((Enum<?>) value).name(), buffer); + } else { + // Fallback for non-enum implementations + context.write(value.getType(), buffer); + } + } + + @FunctionalInterface + public interface TypeTokenFactory { + GremlinDataType create(String name) throws Exception; + } + +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java index 41beeaa392..017bd55625 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.util; import org.apache.tinkerpop.gremlin.process.traversal.N; +import org.apache.tinkerpop.gremlin.structure.GremlinDataType; import java.math.BigDecimal; import java.math.BigInteger; @@ -712,6 +713,15 @@ public final class NumberHelper { return performConversion(a, clazz); } + public static Number castTo(final Number a, final GremlinDataType numberToken) { + Class<? extends Number> clazz = (Class<? extends Number>) numberToken.getType(); + return performConversion(a, clazz); + } + + public static Number castTo(final Number a, final Class<? extends Number> clazz) { + return performConversion(a, clazz); + } + /** * Core conversion logic. * Throws ArithmeticException when conversion would overflow. diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java index 0a6f6b3a4a..b381719d45 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java @@ -702,7 +702,7 @@ public class GremlinTranslatorTest { null, "g.withoutStrategies(ReadOnlyStrategy.class)", "g.withoutStrategies(ReadOnlyStrategy)", // javascript needs TINKERPOP-3055 - "g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy')])"}, + "g.without_strategies(*[GremlinDataType('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy')])"}, {"g.withStrategies(ReservedKeysVerificationStrategy(throwException: true, keys: [\"age\"])).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.withStrategies(ReservedKeysVerificationStrategy(throwException:true, keys:[\"age\"])).addV(\"person\").property(\"age\", 29).property(\"name\", \"marko\")", "g.withStrategies(ReservedKeysVerificationStrategy(throwException:boolean0, keys:list0)).addV(string0).property(string1, number0).property(string2, string3)", @@ -721,7 +721,7 @@ public class GremlinTranslatorTest { null, "g.withoutStrategies(ReadOnlyStrategy.class, PathRetractionStrategy.class, FilterRankingStrategy.class)", "g.withoutStrategies(ReadOnlyStrategy, PathRetractionStrategy, FilterRankingStrategy)", // javascript - needs TINKERPOP-3055 - "g.without_strategies(*[GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy'), GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy'), GremlinType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy')])"}, + "g.without_strategies(*[GremlinDataType('org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy'), GremlinDataType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy'), GremlinDataType('org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy')])"}, {"g.inject(0..5)", null, "g.inject(number0..number1)", 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 15855e0108..bda483b7d9 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 @@ -21,6 +21,9 @@ package org.apache.tinkerpop.gremlin.process.traversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; +import org.apache.tinkerpop.gremlin.structure.CustomType; +import org.apache.tinkerpop.gremlin.structure.GType; +import org.apache.tinkerpop.gremlin.structure.Point; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -55,6 +58,10 @@ public class PTest { @Parameterized.Parameters(name = "{0}.test({1}) = {2}") public static Iterable<Object[]> data() { return new ArrayList<>(Arrays.asList(new Object[][]{ + {P.typeOf(Number.class), 1, true}, + {P.typeOf(GType.NUMBER), 1, true}, + {P.typeOf(CustomType.POINT), new Point(1, 2), true}, + {P.typeOf(Number.class.getCanonicalName()), 1, true}, {P.eq(0), 0, true}, {P.eq(0), -0, true}, {P.eq(0), +0, true}, diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java index ec98bd0285..224a587d02 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java @@ -22,6 +22,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.N; 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.StepTest; +import org.apache.tinkerpop.gremlin.structure.GType; +import org.apache.tinkerpop.gremlin.structure.GremlinDataType; import org.junit.Test; import java.math.BigDecimal; @@ -49,6 +51,7 @@ public class AsNumberStepTest extends StepTest { assertEquals(1L, __.__(1L).asNumber().next()); assertEquals(3.14f, __.__(3.14).asNumber(N.float_).next()); assertEquals(3.14, __.__(3.14f).asNumber(N.double_).next()); + assertEquals(3.14, __.__(3.14f).asNumber(GType.DOUBLE).next()); assertEquals(1, __.__("1").asNumber(N.int_).next()); assertEquals(1, __.__("1").asNumber().next()); assertEquals((byte) 1, __.__("1").asNumber(N.byte_).next()); diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index a3544cfe71..0b6ee396d4 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -362,6 +362,7 @@ traversalMethod_asDate traversalMethod_asNumber : K_ASNUMBER LPAREN RPAREN #traversalMethod_asNumber_Empty | K_ASNUMBER LPAREN traversalN RPAREN #traversalMethod_asNumber_traversalN + | K_ASNUMBER LPAREN traversalGremlinTypes RPAREN #traversalMethod_asNumber_traversalGremlinTypes ; traversalMethod_asString @@ -961,6 +962,11 @@ traversalMethod_write ARGUMENT AND TERMINAL RULES **********************************************/ +traversalGremlinTypes + : nakedKey + | nakedKey DOT nakedKey + ; + traversalStrategy : K_NEW? classType (LPAREN (configuration (COMMA configuration)*)? RPAREN)? ; @@ -1095,6 +1101,7 @@ traversalPredicate | traversalPredicate_inside | traversalPredicate_outside | traversalPredicate_between + | traversalPredicate_typeOf | traversalPredicate_within | traversalPredicate_without | traversalPredicate_not @@ -1150,6 +1157,10 @@ traversalPredicate_neq : (K_P DOT K_NEQ | K_NEQ) LPAREN genericArgument RPAREN ; +traversalPredicate_typeOf + : (K_P DOT K_TYPEOF | K_TYPEOF) LPAREN genericArgument RPAREN + ; + traversalPredicate_lt : (K_P DOT K_LT | K_LT) LPAREN genericArgument RPAREN ; @@ -1579,6 +1590,7 @@ genericLiteral | traversalPick | traversalDT | traversalN + | traversalGremlinTypes | genericSetLiteral | genericCollectionLiteral | genericRangeLiteral @@ -1677,6 +1689,10 @@ variable : Identifier ; +//gremlinType +// : Identifier +// ; + // every Gremlin keyword must be listed here or else these words will not be able to be used as // Map/Configuration keys as naked identifiers like [all: 123]. without having that definition // here that sort of Map definition will get a syntax error. @@ -2109,6 +2125,7 @@ K_NEQ: 'neq'; K_NEW: 'new'; K_NORMSACK: 'normSack'; K_NULL: 'null'; +K_TYPEOF: 'typeOf'; K_ONCREATE: 'onCreate'; K_ONMATCH: 'onMatch'; K_OPERATOR: 'Operator'; diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java index 1ba8c43b39..a2f5a793f9 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java @@ -22,11 +22,16 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import nl.altindag.log.LogCaptor; import org.apache.tinkerpop.gremlin.driver.Channelizer; +import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer; +import org.apache.tinkerpop.gremlin.structure.CustomType; +import org.apache.tinkerpop.gremlin.structure.GType; import org.apache.tinkerpop.gremlin.structure.Graph; -import org.apache.tinkerpop.gremlin.structure.io.Mapper; +import org.apache.tinkerpop.gremlin.structure.GremlinDataType; +import org.apache.tinkerpop.gremlin.structure.NType; +import org.apache.tinkerpop.gremlin.structure.Point; +import org.apache.tinkerpop.gremlin.structure.io.binary.types.GremlinDataTypeSerializer; import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; -import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV3; import org.apache.tinkerpop.gremlin.util.ExceptionHelper; import org.apache.tinkerpop.gremlin.TestHelper; @@ -44,7 +49,6 @@ import org.apache.tinkerpop.gremlin.util.message.RequestMessage; import org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode; import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; import org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1; -import org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV2; import org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3; import org.apache.tinkerpop.gremlin.util.ser.Serializers; import org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin; @@ -1978,4 +1982,24 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration cluster.close(); } } + + @Test + public void test() throws Exception { + final Cluster cluster = TestClientFactory.build().serializer(Serializers.GRAPHBINARY_V1).create(); + try { + final Client client = cluster.connect().alias("g"); + final GraphTraversalSource g = traversal().with(DriverRemoteConnection.using(client)); + GremlinDataType.GlobalTypeCache.registerDataType(NType.class); + GremlinDataTypeSerializer.registerTypeFactory("NType", NType::valueOf); + GremlinDataType.GlobalTypeCache.registerDataType(CustomType.class); + GremlinDataTypeSerializer.registerTypeFactory("CustomType", CustomType::valueOf); + System.out.println(g.inject("1").asNumber(NType.DOUBLE).next()); + System.out.println(client.submit("g.inject('1').asNumber(NType.DOUBLE)", RequestOptions.build().language("gremlin-lang").create()).all().get()); + System.out.println(g.inject(1.0,2,3,"hello",false).is(P.typeOf(GType.NUMBER)).fold().next()); + System.out.println(client.submit("g.inject(1.0,'hello').is(P.typeOf(GType.DOUBLE)).fold()", RequestOptions.build().language("gremlin-lang").create()).all().get()); + cluster.close(); + } finally { + cluster.close(); + } + } }
