You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2023/06/21 19:43:27 UTC

[tinkerpop] 01/02: wip

This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2957
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit e0036006d9724412f2393ff26f25c15a94e1aa83
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Mon Jun 19 11:27:12 2023 -0400

    wip
---
 .../grammar/DefaultGremlinBaseVisitor.java         |  5 ++
 .../language/grammar/GenericLiteralVisitor.java    | 19 +++++
 .../process/traversal/CardinalityValue.java        | 81 ++++++++++++++++++++++
 .../grammar/GeneralLiteralVisitorTest.java         | 34 +++++++++
 .../process/traversal/CardinalityValueTest.java    | 64 +++++++++++++++++
 gremlin-language/src/main/antlr4/Gremlin.g4        |  7 ++
 6 files changed, 210 insertions(+)

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 39dac7efa5..e24640eeb1 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
@@ -1432,4 +1432,9 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
 	 * {@inheritDoc}
 	 */
 	@Override public T visitTraversalMethod_mergeE_empty(final GremlinParser.TraversalMethod_mergeE_emptyContext ctx) { notImplemented(ctx); return null; }
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public T visitTraversalCardinalityValue(final GremlinParser.TraversalCardinalityValueContext ctx) { notImplemented(ctx); return null; }
 }
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 78d144616f..7e604efe80 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
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.language.grammar;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.TerminalNode;
 import org.apache.commons.text.StringEscapeUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.CardinalityValue;
 import org.apache.tinkerpop.gremlin.process.traversal.Merge;
 import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
@@ -612,4 +613,22 @@ public class GenericLiteralVisitor extends DefaultGremlinBaseVisitor<Object> {
         return result;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object visitTraversalCardinalityValue(final GremlinParser.TraversalCardinalityValueContext ctx) {
+        // could be CardinalityValue.single or single so grab the right child index based on number of children
+        final int idx = ctx.getChildCount() == 5 ? 1 : 0;
+        final String specifiedCard = ctx.children.get(idx).getText();
+        if (specifiedCard.equals(VertexProperty.Cardinality.single.name()))
+            return CardinalityValue.single(visitGenericLiteral(ctx.genericLiteral()));
+        else if (specifiedCard.equals(VertexProperty.Cardinality.list.name()))
+            return CardinalityValue.list(visitGenericLiteral(ctx.genericLiteral()));
+        else if (specifiedCard.equals(VertexProperty.Cardinality.set.name()))
+            return CardinalityValue.set(visitGenericLiteral(ctx.genericLiteral()));
+        else
+            throw new GremlinParserException(String.format(
+                    "A CardinalityValue must be defined as one of the available Cardinality values, not %s", specifiedCard));
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CardinalityValue.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CardinalityValue.java
new file mode 100644
index 0000000000..a2461060ca
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CardinalityValue.java
@@ -0,0 +1,81 @@
+/*
+ * 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.VertexProperty;
+
+import java.util.Objects;
+
+/**
+ * Wraps a {@link VertexProperty.Cardinality} with the value it is associated.
+ */
+public class CardinalityValue<T> {
+
+    private final VertexProperty.Cardinality cardinality;
+
+    private final T value;
+
+    private CardinalityValue(final VertexProperty.Cardinality cardinality, final T value) {
+        this.cardinality = cardinality;
+        this.value = value;
+    }
+
+    public static <T> CardinalityValue<T> single(final T value) {
+        return new CardinalityValue<T>(VertexProperty.Cardinality.single, value);
+    }
+
+    public static <T> CardinalityValue<T> list(final T value) {
+        return new CardinalityValue<T>(VertexProperty.Cardinality.list, value);
+    }
+
+    public static <T> CardinalityValue<T> set(final T value) {
+        return new CardinalityValue<T>(VertexProperty.Cardinality.set, value);
+    }
+
+    public VertexProperty.Cardinality getCardinality() {
+        return cardinality;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (!(o instanceof CardinalityValue)) return false;
+
+        CardinalityValue<?> that = (CardinalityValue<?>) o;
+
+        if (cardinality != that.cardinality) return false;
+        return Objects.equals(value, that.value);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = cardinality.hashCode();
+        result = 31 * result + (value != null ? value.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "cv[" + cardinality + ", " + Objects.toString(value) + "]";
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
index 1350b03202..7e066adc88 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
@@ -20,6 +20,8 @@ package org.apache.tinkerpop.gremlin.language.grammar;
 
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
+import org.apache.tinkerpop.gremlin.process.traversal.CardinalityValue;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.experimental.runners.Enclosed;
@@ -673,4 +675,36 @@ public class GeneralLiteralVisitorTest {
             assertEquals(Double.NEGATIVE_INFINITY, GenericLiteralVisitor.instance().visitInfLiteral(ctx));
         }
     }
+
+    @RunWith(Parameterized.class)
+    public static class CardinalityValueTest {
+        @Parameterized.Parameter(value = 0)
+        public String script;
+
+        @Parameterized.Parameter(value = 1)
+        public CardinalityValue expected;
+
+        @Parameterized.Parameters()
+        public static Iterable<Object[]> generateTestParameters() {
+            return Arrays.asList(new Object[][]{
+                    {"single(\"test\")", CardinalityValue.single("test")},
+                    {"list(\"test\")", CardinalityValue.list("test")},
+                    {"set(\"test\")", CardinalityValue.set("test")},
+                    {"CardinalityValue.single(\"test\")", CardinalityValue.single("test")},
+                    {"CardinalityValue.list(\"test\")", CardinalityValue.list("test")},
+                    {"CardinalityValue.set(\"test\")", CardinalityValue.set("test")},
+                    {"single(1l)", CardinalityValue.single(1L)},
+                    {"list(1l)", CardinalityValue.list(1L)},
+                    {"set(1l)", CardinalityValue.set(1L)},
+            });
+        }
+
+        @Test
+        public void shouldParse() {
+            final GremlinLexer lexer = new GremlinLexer(CharStreams.fromString(script));
+            final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer));
+            final GremlinParser.TraversalCardinalityValueContext ctx = parser.traversalCardinalityValue();
+            assertEquals(expected, GenericLiteralVisitor.instance().visitTraversalCardinalityValue(ctx));
+        }
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/CardinalityValueTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/CardinalityValueTest.java
new file mode 100644
index 0000000000..221b13f085
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/CardinalityValueTest.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.VertexProperty;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class CardinalityValueTest {
+
+    @Test
+    public void shouldCreateSingle() {
+        final CardinalityValue<String> cv = CardinalityValue.single("test");
+        assertEquals("test", cv.getValue());
+        assertEquals(VertexProperty.Cardinality.single, cv.getCardinality());
+    }
+
+    @Test
+    public void shouldCreateSet() {
+        final CardinalityValue<String> cv = CardinalityValue.set("test");
+        assertEquals("test", cv.getValue());
+        assertEquals(VertexProperty.Cardinality.set, cv.getCardinality());
+    }
+
+    @Test
+    public void shouldCreateList() {
+        final CardinalityValue<String> cv = CardinalityValue.list("test");
+        assertEquals("test", cv.getValue());
+        assertEquals(VertexProperty.Cardinality.list, cv.getCardinality());
+    }
+
+    @Test
+    public void shouldBeEqual() {
+        assertEquals(CardinalityValue.single("test"), CardinalityValue.single("test"));
+        assertEquals(CardinalityValue.single(1), CardinalityValue.single(1));
+        assertEquals(CardinalityValue.single(null), CardinalityValue.single(null));
+    }
+
+    @Test
+    public void shouldNotBeEqual() {
+        assertNotEquals(CardinalityValue.single(100), CardinalityValue.single("testing"));
+        assertNotEquals(CardinalityValue.single("test"), CardinalityValue.single("testing"));
+        assertNotEquals(CardinalityValue.single(100), CardinalityValue.single(1));
+        assertNotEquals(CardinalityValue.single("null"), CardinalityValue.single(null));
+    }
+}
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index 2e0ce504f5..3f9d7afaf3 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -915,6 +915,12 @@ traversalCardinality
     | 'list' | 'Cardinality.list'
     ;
 
+traversalCardinalityValue
+    : 'CardinalityValue.'? 'single' LPAREN genericLiteral RPAREN
+    | 'CardinalityValue.'? 'set' LPAREN genericLiteral RPAREN
+    | 'CardinalityValue.'? 'list' LPAREN genericLiteral RPAREN
+    ;
+
 traversalColumn
     : 'keys' | 'Column.keys'
     | 'values' | 'Column.values'
@@ -1376,6 +1382,7 @@ genericLiteral
 	| infLiteral
 	// Allow the generic literal to match specific gremlin tokens also
 	| traversalToken
+	| traversalCardinalityValue
 	| traversalCardinality
 	| traversalDirection
 	| traversalMerge