This is an automated email from the ASF dual-hosted git repository. xiazcy pushed a commit to branch multi-label-experiment in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 27da3669c7d134d4c46e4bbb4deb856542389bf7 Author: Yang Xia <[email protected]> AuthorDate: Wed Jun 17 07:49:19 2026 -0700 Add cardinality --- .../grammar/DefaultGremlinBaseVisitor.java | 4 - .../language/grammar/TraversalMethodVisitor.java | 19 --- .../grammar/TraversalSourceSpawnMethodVisitor.java | 26 +--- .../process/traversal/step/map/AddVertexStep.java | 15 +- .../apache/tinkerpop/gremlin/structure/Graph.java | 44 ++++++ .../gremlin/structure/LabelCardinality.java | 153 +++++++++++++++++++ .../structure/io/binary/types/EdgeSerializer.java | 15 +- .../structure/io/binary/types/GraphSerializer.java | 6 +- .../io/binary/types/VertexSerializer.java | 6 +- .../structure/io/graphml/GraphMLWriter.java | 6 +- .../io/graphson/GraphSONSerializersV1.java | 8 +- .../io/graphson/GraphSONSerializersV2.java | 8 +- .../io/graphson/GraphSONSerializersV3.java | 8 +- .../structure/io/gryo/GryoSerializersV3.java | 10 +- .../gremlin/structure/util/star/StarGraph.java | 14 +- .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 8 +- gremlin-go/driver/cucumber/gremlin.go | 8 +- .../gremlin-javascript/test/cucumber/gremlin.js | 8 +- gremlin-language/src/main/antlr4/Gremlin.g4 | 2 - .../src/main/python/tests/feature/gremlin.py | 8 +- .../gremlin/language/translator/translations.json | 170 +++------------------ .../gremlin/test/features/map/AddEdge.feature | 32 ---- .../gremlin/test/features/map/MergeVertex.feature | 2 +- .../test/features/sideEffect/AddLabel.feature | 4 +- .../test/features/sideEffect/DropLabel.feature | 18 +-- .../ser/binary/TypeSerializerFailureTests.java | 7 +- .../tinkergraph/structure/AbstractTinkerGraph.java | 27 ++++ .../gremlin/tinkergraph/structure/TinkerEdge.java | 38 +++-- .../gremlin/tinkergraph/structure/TinkerGraph.java | 10 +- .../structure/TinkerTransactionGraph.java | 10 +- .../tinkergraph/structure/TinkerVertex.java | 65 ++++++-- .../traversal/step/map/MergeVMultiLabelTest.java | 5 +- .../step/sideEffect/LabelMutationPropertyTest.java | 7 +- .../step/sideEffect/LabelMutationStepTest.java | 13 +- .../structure/TinkerVertexMultiLabelTest.java | 24 +-- 35 files changed, 438 insertions(+), 370 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 5257be977a..a3cc037253 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 @@ -167,10 +167,6 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im * {@inheritDoc} */ @Override public T visitTraversalMethod_addE_String(final GremlinParser.TraversalMethod_addE_StringContext ctx) { notImplemented(ctx); return null; } - /** - * {@inheritDoc} - */ - @Override public T visitTraversalMethod_addE_StringVarargs(final GremlinParser.TraversalMethod_addE_StringVarargsContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java index cc65794ed6..cf99aeb3e5 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 @@ -205,25 +205,6 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> } } - /** - * {@inheritDoc} - */ - @Override - public GraphTraversal visitTraversalMethod_addE_StringVarargs(final GremlinParser.TraversalMethod_addE_StringVarargsContext ctx) { - final List<GremlinParser.StringArgumentContext> args = ctx.stringArgument(); - final Object firstLiteralOrVar = antlr.argumentVisitor.visitStringArgument(args.get(0)); - final String firstLabel = firstLiteralOrVar instanceof String ? (String) firstLiteralOrVar : ((GValue<String>) firstLiteralOrVar).get(); - final Object secondLiteralOrVar = antlr.argumentVisitor.visitStringArgument(args.get(1)); - final String secondLabel = secondLiteralOrVar instanceof String ? (String) secondLiteralOrVar : ((GValue<String>) secondLiteralOrVar).get(); - - final String[] moreLabels = new String[args.size() - 2]; - for (int i = 2; i < args.size(); i++) { - final Object literalOrVar = antlr.argumentVisitor.visitStringArgument(args.get(i)); - moreLabels[i - 2] = literalOrVar instanceof String ? (String) literalOrVar : ((GValue<String>) literalOrVar).get(); - } - return this.graphTraversal.addE(firstLabel, secondLabel, moreLabels); - } - /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java index 5ce9b41c09..5ce311697f 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java @@ -57,27 +57,13 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor */ @Override public GraphTraversal visitTraversalSourceSpawnMethod_addE(final GremlinParser.TraversalSourceSpawnMethod_addEContext ctx) { - final List<GremlinParser.StringArgumentContext> stringArgs = ctx.stringArgument(); - if (stringArgs != null && !stringArgs.isEmpty()) { - if (stringArgs.size() == 1) { - final Object literalOrVar = antlr.argumentVisitor.visitStringArgument(stringArgs.get(0)); - if (GValue.valueInstanceOf(literalOrVar, String.class)) { - return this.traversalSource.addE((GValue<String>) literalOrVar); - } else { - return this.traversalSource.addE((String) literalOrVar); - } + final GremlinParser.StringArgumentContext stringArg = ctx.stringArgument(); + if (stringArg != null) { + final Object literalOrVar = antlr.argumentVisitor.visitStringArgument(stringArg); + if (GValue.valueInstanceOf(literalOrVar, String.class)) { + return this.traversalSource.addE((GValue<String>) literalOrVar); } else { - // Multi-label: addE("a", "b", ...) - final Object firstLiteralOrVar = antlr.argumentVisitor.visitStringArgument(stringArgs.get(0)); - final String firstLabel = firstLiteralOrVar instanceof String ? (String) firstLiteralOrVar : ((GValue<String>) firstLiteralOrVar).get(); - final Object secondLiteralOrVar = antlr.argumentVisitor.visitStringArgument(stringArgs.get(1)); - final String secondLabel = secondLiteralOrVar instanceof String ? (String) secondLiteralOrVar : ((GValue<String>) secondLiteralOrVar).get(); - final String[] moreLabels = new String[stringArgs.size() - 2]; - for (int i = 2; i < stringArgs.size(); i++) { - final Object literalOrVar = antlr.argumentVisitor.visitStringArgument(stringArgs.get(i)); - moreLabels[i - 2] = literalOrVar instanceof String ? (String) literalOrVar : ((GValue<String>) literalOrVar).get(); - } - return this.traversalSource.addE(firstLabel, secondLabel, moreLabels); + return this.traversalSource.addE((String) literalOrVar); } } else if (ctx.nestedTraversal() != null) { return this.traversalSource.addE(anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal())); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java index 4c2b505b53..8a48d1728b 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java @@ -49,24 +49,27 @@ public class AddVertexStep<S> extends ScalarMapStep<S, Vertex> implements AddVer public AddVertexStep(final Traversal.Admin traversal, final String label) { super(traversal); - this.internalParameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label); + if (label != null) { + this.internalParameters.set(this, T.label, label); + } userProvidedLabel = label != null; } public AddVertexStep(final Traversal.Admin traversal, final Traversal.Admin<S,String> vertexLabelTraversal) { super(traversal); - this.internalParameters.set(this, T.label, null == vertexLabelTraversal ? Vertex.DEFAULT_LABEL : vertexLabelTraversal); + if (vertexLabelTraversal != null) { + this.internalParameters.set(this, T.label, vertexLabelTraversal); + } userProvidedLabel = vertexLabelTraversal != null; } public AddVertexStep(final Traversal.Admin traversal, final Set<String> labels) { super(traversal); - if (labels == null || labels.isEmpty()) { - this.internalParameters.set(this, T.label, Vertex.DEFAULT_LABEL); - userProvidedLabel = false; - } else { + if (labels != null && !labels.isEmpty()) { this.internalParameters.set(this, T.label, labels); userProvidedLabel = true; + } else { + userProvidedLabel = false; } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java index 3f9f246297..fe6291e616 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java @@ -655,6 +655,28 @@ public interface Graph extends AutoCloseable, Host { return new VertexPropertyFeatures() { }; } + + /** + * Gets the {@link LabelCardinality} for vertices in this graph. Defines how many labels + * a vertex can have and whether labels are mutable. + * + * @return the label cardinality for vertices, defaulting to {@link LabelCardinality#ZERO_OR_MORE} + * @since 4.0.0 + */ + default LabelCardinality getLabelCardinality() { + return LabelCardinality.ZERO_OR_MORE; + } + + /** + * Gets the default label returned for vertices with no explicit labels when the cardinality + * requires at least one label ({@link LabelCardinality#ONE} or {@link LabelCardinality#ONE_OR_MORE}). + * + * @return the default vertex label, typically {@link Vertex#DEFAULT_LABEL} + * @since 4.0.0 + */ + default String getDefaultLabel() { + return Vertex.DEFAULT_LABEL; + } } /** @@ -703,6 +725,28 @@ public interface Graph extends AutoCloseable, Host { return new EdgePropertyFeatures() { }; } + + /** + * Gets the {@link LabelCardinality} for edges in this graph. Defines how many labels + * an edge can have and whether labels are mutable. + * + * @return the label cardinality for edges, defaulting to {@link LabelCardinality#ZERO_OR_ONE} + * @since 4.0.0 + */ + default LabelCardinality getLabelCardinality() { + return LabelCardinality.ZERO_OR_ONE; + } + + /** + * Gets the default label returned for edges with no explicit labels when the cardinality + * requires at least one label ({@link LabelCardinality#ONE} or {@link LabelCardinality#ONE_OR_MORE}). + * + * @return the default edge label, typically {@link Edge#DEFAULT_LABEL} + * @since 4.0.0 + */ + default String getDefaultLabel() { + return Edge.DEFAULT_LABEL; + } } /** diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/LabelCardinality.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/LabelCardinality.java new file mode 100644 index 0000000000..690fa75cef --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/LabelCardinality.java @@ -0,0 +1,153 @@ +/* + * 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.HashSet; +import java.util.Set; + +/** + * Defines the label cardinality for graph elements (vertices and edges). Providers declare their + * supported cardinality via {@link Graph.Features} and use the validation methods to enforce + * label mutation constraints. + * <p> + * The four cardinality modes are: + * <ul> + * <li>{@link #ONE} — Exactly one label, immutable (classic TinkerPop 3.x behavior)</li> + * <li>{@link #ZERO_OR_ONE} — Zero or one label, mutable, droppable to zero</li> + * <li>{@link #ONE_OR_MORE} — One or more labels, must always have at least one (virtual default fills when empty)</li> + * <li>{@link #ZERO_OR_MORE} — Zero or more labels, fully flexible</li> + * </ul> + * + * @since 4.0.0 + */ +public enum LabelCardinality { + + /** + * Exactly one label, immutable. All mutation operations throw. + * This provides backward compatibility with TinkerPop 3.x single-label semantics. + */ + ONE, + + /** + * Zero or one label, mutable. The element can have at most one label at a time. + * To change the label, the existing one must be dropped first. + */ + ZERO_OR_ONE, + + /** + * One or more labels, mutable. The element must always have at least one label. + * When all explicit labels are removed, the provider's default label (e.g., "vertex" or "edge") + * is returned at read time as a virtual floor. + */ + ONE_OR_MORE, + + /** + * Zero or more labels, fully flexible. No constraints on the number of labels. + * Elements can have any number of labels including zero. + */ + ZERO_OR_MORE; + + /** + * Whether this cardinality allows multiple labels on an element simultaneously. + * + * @return {@code true} for {@link #ONE_OR_MORE} and {@link #ZERO_OR_MORE} + */ + public boolean supportsMultiLabel() { + return this == ONE_OR_MORE || this == ZERO_OR_MORE; + } + + /** + * Whether this cardinality allows an element to have zero labels. + * + * @return {@code true} for {@link #ZERO_OR_ONE} and {@link #ZERO_OR_MORE} + */ + public boolean supportsZeroLabels() { + return this == ZERO_OR_ONE || this == ZERO_OR_MORE; + } + + /** + * Whether this cardinality allows label mutation (addLabel/dropLabel). + * + * @return {@code true} for all modes except {@link #ONE} + */ + public boolean supportsMutation() { + return this != ONE; + } + + /** + * Validates that adding the specified labels would not violate this cardinality's constraints. + * Must be called BEFORE any mutation to ensure no invalid intermediate states. + * + * @param currentLabels the element's current label set + * @param label the first label to add + * @param moreLabels additional labels to add (varargs) + * @throws IllegalStateException if the addition would violate cardinality constraints + */ + public void validateAdd(final Set<String> currentLabels, final String label, final String... moreLabels) { + if (!supportsMutation()) + throw new IllegalStateException("Label mutation is not supported with cardinality " + this + + ". Labels are immutable once assigned."); + + if (!supportsMultiLabel()) { + // ZERO_OR_ONE: resulting set must have at most 1 element + // Fast path: single label + empty set → always valid + if (moreLabels.length == 0 && currentLabels.isEmpty()) + return; + + // Compute the resulting set size + final Set<String> resultSet = new HashSet<>(currentLabels); + resultSet.add(label); + for (final String l : moreLabels) { + resultSet.add(l); + } + if (resultSet.size() > 1) + throw new IllegalStateException("Cannot add label: would result in " + resultSet.size() + + " labels but cardinality is " + this + ". Drop the existing label first."); + } + } + + /** + * Validates that dropping a specific label would not violate this cardinality's constraints. + * For mutable cardinalities, dropping always succeeds (floor is applied at read time). + * + * @param currentLabels the element's current label set + * @param label the label to drop + * @throws IllegalStateException if mutation is not supported (ONE mode) + */ + public void validateDrop(final Set<String> currentLabels, final String label) { + if (!supportsMutation()) + throw new IllegalStateException("Label mutation is not supported with cardinality " + this + + ". Labels are immutable once assigned."); + // No floor validation needed — floor is applied at read time by the element's labels() method + } + + /** + * Validates that dropping all labels would not violate this cardinality's constraints. + * For mutable cardinalities, dropping all always succeeds (floor is applied at read time). + * + * @param currentLabels the element's current label set + * @throws IllegalStateException if mutation is not supported (ONE mode) + */ + public void validateDropAll(final Set<String> currentLabels) { + if (!supportsMutation()) + throw new IllegalStateException("Label mutation is not supported with cardinality " + this + + ". Labels are immutable once assigned."); + // Always succeeds for mutable cardinalities — floor applied at read time + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java index fe48d6f6ae..2f63384fcf 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java @@ -100,26 +100,17 @@ public class EdgeSerializer extends SimpleTypeSerializer<Edge> { context.write(value.id(), buffer); // Write all edge labels as List<String> for multi-label support final Set<String> edgeLabels = value.labels(); - if (edgeLabels == null || edgeLabels.isEmpty()) { - throw new IOException("Unexpected null or empty labels when nullable is false"); - } - context.writeValue(new ArrayList<>(edgeLabels), buffer, false); + context.writeValue(edgeLabels == null ? new ArrayList<>() : new ArrayList<>(edgeLabels), buffer, false); context.write(value.inVertex().id(), buffer); // Write all inVertex labels as List<String> for multi-label support final Set<String> inVLabels = value.inVertex().labels(); - if (inVLabels == null || inVLabels.isEmpty()) { - throw new IOException("Unexpected null or empty labels when nullable is false"); - } - context.writeValue(new ArrayList<>(inVLabels), buffer, false); + context.writeValue(inVLabels == null ? new ArrayList<>() : new ArrayList<>(inVLabels), buffer, false); context.write(value.outVertex().id(), buffer); // Write all outVertex labels as List<String> for multi-label support final Set<String> outVLabels = value.outVertex().labels(); - if (outVLabels == null || outVLabels.isEmpty()) { - throw new IOException("Unexpected null or empty labels when nullable is false"); - } - context.writeValue(new ArrayList<>(outVLabels), buffer, false); + context.writeValue(outVLabels == null ? new ArrayList<>() : new ArrayList<>(outVLabels), buffer, false); // we don't serialize the parent Vertex for edges. context.write(null, buffer); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java index 4138555dc1..62f5e2546c 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java @@ -135,7 +135,8 @@ public class GraphSerializer extends SimpleTypeSerializer<Graph> { context.write(vertex.id(), buffer); // serializing label as list here for now according to GraphBinaryV4 - context.writeValue(Collections.singletonList(vertex.label()), buffer, false); + final String vLabel = vertex.label(); + context.writeValue(vLabel == null ? Collections.emptyList() : Collections.singletonList(vLabel), buffer, false); context.writeValue(vertexProperties.size(), buffer, false); for (VertexProperty<Object> vp : vertexProperties) { @@ -154,7 +155,8 @@ public class GraphSerializer extends SimpleTypeSerializer<Graph> { private void writeEdge(Buffer buffer, GraphBinaryWriter context, Edge edge) throws IOException { context.write(edge.id(), buffer); // serializing label as list here for now according to GraphBinaryV4 - context.writeValue(Collections.singletonList(edge.label()), buffer, false); + final String eLabel = edge.label(); + context.writeValue(eLabel == null ? Collections.emptyList() : Collections.singletonList(eLabel), buffer, false); context.write(edge.inVertex().id(), buffer); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java index ce6befecba..f5074cc643 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java @@ -72,11 +72,9 @@ public class VertexSerializer extends SimpleTypeSerializer<Vertex> { protected void writeValue(final Vertex value, final Buffer buffer, final GraphBinaryWriter context) throws IOException { context.write(value.id(), buffer); // Write all labels as List<String> for multi-label support. + // Empty list is valid for zero-label elements (ZERO_OR_MORE / ZERO_OR_ONE cardinality). final java.util.Set<String> labels = value.labels(); - if (labels == null || labels.isEmpty()) { - throw new IOException("Unexpected null or empty labels when nullable is false"); - } - context.writeValue(new ArrayList<>(labels), buffer, false); + context.writeValue(labels == null ? new ArrayList<>() : new ArrayList<>(labels), buffer, false); if (value instanceof ReferenceVertex) { context.write(null, buffer); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java index cae0f9c987..0c75805f3a 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java @@ -266,7 +266,7 @@ public final class GraphMLWriter implements GraphWriter { writer.writeStartElement(GraphMLTokens.DATA); writer.writeAttribute(GraphMLTokens.KEY, this.edgeLabelKey); - writer.writeCharacters(edge.label()); + writer.writeCharacters(edge.label() == null ? "" : edge.label()); writer.writeEndElement(); final List<String> keys = new ArrayList<>(edge.keys()); @@ -296,7 +296,7 @@ public final class GraphMLWriter implements GraphWriter { writer.writeStartElement(GraphMLTokens.DATA); writer.writeAttribute(GraphMLTokens.KEY, this.edgeLabelKey); - writer.writeCharacters(edge.label()); + writer.writeCharacters(edge.label() == null ? "" : edge.label()); writer.writeEndElement(); for (String key : edge.keys()) { @@ -328,7 +328,7 @@ public final class GraphMLWriter implements GraphWriter { writer.writeStartElement(GraphMLTokens.DATA); writer.writeAttribute(GraphMLTokens.KEY, this.vertexLabelKey); - writer.writeCharacters(vertex.label()); + writer.writeCharacters(vertex.label() == null ? "" : vertex.label()); writer.writeEndElement(); for (String key : keys) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java index 4841b482b4..32a49a34c2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java @@ -140,10 +140,10 @@ final class GraphSONSerializersV1 { if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName()); GraphSONUtil.writeWithType(GraphSONTokens.ID, edge.id(), jsonGenerator, serializerProvider, typeSerializer); - jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label() == null ? "" : edge.label()); jsonGenerator.writeStringField(GraphSONTokens.TYPE, GraphSONTokens.EDGE); - jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label()); - jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label()); + jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label() == null ? "" : edge.inVertex().label()); + jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label() == null ? "" : edge.outVertex().label()); GraphSONUtil.writeWithType(GraphSONTokens.IN, edge.inVertex().id(), jsonGenerator, serializerProvider, typeSerializer); GraphSONUtil.writeWithType(GraphSONTokens.OUT, edge.outVertex().id(), jsonGenerator, serializerProvider, typeSerializer); writeProperties(edge, jsonGenerator, serializerProvider, typeSerializer); @@ -196,7 +196,7 @@ final class GraphSONSerializersV1 { jsonGenerator.writeStartObject(); if (typeSerializer != null) jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName()); GraphSONUtil.writeWithType(GraphSONTokens.ID, vertex.id(), jsonGenerator, serializerProvider, typeSerializer); - jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label() == null ? "" : vertex.label()); jsonGenerator.writeStringField(GraphSONTokens.TYPE, GraphSONTokens.VERTEX); writeProperties(vertex, jsonGenerator, serializerProvider, typeSerializer); jsonGenerator.writeEndObject(); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java index 8b52323c94..871569d2a4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java @@ -101,7 +101,7 @@ class GraphSONSerializersV2 { jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField(GraphSONTokens.ID, vertex.id()); - jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label() == null ? "" : vertex.label()); writeProperties(vertex, jsonGenerator); jsonGenerator.writeEndObject(); @@ -150,9 +150,9 @@ class GraphSONSerializersV2 { jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField(GraphSONTokens.ID, edge.id()); - jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label()); - jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label()); - jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label() == null ? "" : edge.label()); + jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label() == null ? "" : edge.inVertex().label()); + jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label() == null ? "" : edge.outVertex().label()); jsonGenerator.writeObjectField(GraphSONTokens.IN, edge.inVertex().id()); jsonGenerator.writeObjectField(GraphSONTokens.OUT, edge.outVertex().id()); writeProperties(edge, jsonGenerator); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java index 6df9141f5b..c9f2520556 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java @@ -101,7 +101,7 @@ class GraphSONSerializersV3 { jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField(GraphSONTokens.ID, vertex.id()); - jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, vertex.label() == null ? "" : vertex.label()); writeTypeForGraphObjectIfUntyped(jsonGenerator, typeInfo, GraphSONTokens.VERTEX); writeProperties(vertex, jsonGenerator, serializerProvider); @@ -161,10 +161,10 @@ class GraphSONSerializersV3 { jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField(GraphSONTokens.ID, edge.id()); - jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label()); + jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label() == null ? "" : edge.label()); writeTypeForGraphObjectIfUntyped(jsonGenerator, typeInfo, GraphSONTokens.EDGE); - jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label()); - jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label()); + jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, edge.inVertex().label() == null ? "" : edge.inVertex().label()); + jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, edge.outVertex().label() == null ? "" : edge.outVertex().label()); jsonGenerator.writeObjectField(GraphSONTokens.IN, edge.inVertex().id()); jsonGenerator.writeObjectField(GraphSONTokens.OUT, edge.outVertex().id()); writeProperties(edge, jsonGenerator); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java index 5a0beec2ae..e53f1aacef 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java @@ -74,7 +74,7 @@ public final class GryoSerializersV3 { @Override public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Edge edge) { kryo.writeClassAndObject(output, edge.id()); - output.writeString(edge.label()); + output.writeString(edge.label() == null ? "" : edge.label()); kryo.writeClassAndObject(output, edge.inVertex().id()); // temporary try/catch perhaps? need this to get SparkSingleIterationStrategyTest to work. Trying to grab @@ -84,7 +84,8 @@ public final class GryoSerializersV3 { // // ghetto try { - output.writeString(edge.inVertex().label()); + final String inLabel = edge.inVertex().label(); + output.writeString(inLabel == null ? Vertex.DEFAULT_LABEL : inLabel); } catch (Exception ex) { output.writeString(Vertex.DEFAULT_LABEL); } @@ -93,7 +94,8 @@ public final class GryoSerializersV3 { // same nonsense as above for a default label try { - output.writeString(edge.outVertex().label()); + final String outLabel = edge.outVertex().label(); + output.writeString(outLabel == null ? Vertex.DEFAULT_LABEL : outLabel); } catch (Exception ex) { output.writeString(Vertex.DEFAULT_LABEL); } @@ -132,7 +134,7 @@ public final class GryoSerializersV3 { @Override public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Vertex vertex) { kryo.writeClassAndObject(output, vertex.id()); - output.writeString(vertex.label()); + output.writeString(vertex.label() == null ? "" : vertex.label()); final Iterator<? extends VertexProperty> properties = vertex.properties(); output.writeBoolean(properties.hasNext()); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java index 1981a3257b..30c5cb9066 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java @@ -205,7 +205,13 @@ public final class StarGraph implements Graph, Serializable { if (vertex instanceof StarVertex) return (StarGraph) vertex.graph(); // else convert to a star graph final StarGraph starGraph = new StarGraph(); - final StarVertex starVertex = (StarVertex) starGraph.addVertex(T.id, vertex.id(), T.label, vertex.label()); + final String vertexLabel = vertex.label(); + final StarVertex starVertex; + if (vertexLabel != null) { + starVertex = (StarVertex) starGraph.addVertex(T.id, vertex.id(), T.label, vertexLabel); + } else { + starVertex = (StarVertex) starGraph.addVertex(T.id, vertex.id()); + } // Copy multi-labels from source vertex final Set<String> srcLabels = vertex.labels(); @@ -221,7 +227,8 @@ public final class StarGraph implements Graph, Serializable { vp.properties().forEachRemaining(p -> starVertexProperty.property(p.key(), p.value())); }); vertex.edges(Direction.IN).forEachRemaining(edge -> { - final Edge starEdge = starVertex.addInEdge(edge.label(), starGraph.addVertex(T.id, edge.outVertex().id()), T.id, edge.id()); + final String edgeLabel = edge.label() == null ? Edge.DEFAULT_LABEL : edge.label(); + final Edge starEdge = starVertex.addInEdge(edgeLabel, starGraph.addVertex(T.id, edge.outVertex().id()), T.id, edge.id()); edge.properties().forEachRemaining(p -> starEdge.property(p.key(), p.value())); final Set<String> edgeSrcLabels = edge.labels(); if (edgeSrcLabels.size() > 1) { @@ -230,7 +237,8 @@ public final class StarGraph implements Graph, Serializable { }); vertex.edges(Direction.OUT).forEachRemaining(edge -> { - final Edge starEdge = starVertex.addOutEdge(edge.label(), starGraph.addVertex(T.id, edge.inVertex().id()), T.id, edge.id()); + final String edgeLabel = edge.label() == null ? Edge.DEFAULT_LABEL : edge.label(); + final Edge starEdge = starVertex.addOutEdge(edgeLabel, starGraph.addVertex(T.id, edge.inVertex().id()), T.id, edge.id()); edge.properties().forEachRemaining(p -> starEdge.property(p.key(), p.value())); final Set<String> edgeSrcLabels = edge.labels(); if (edgeSrcLabels.size() > 1) { diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 6e19a2d5e1..e2b0f2b16b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -921,8 +921,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27), (g,p) =>g.Union<object>(__.AddE((string) p["xx1"]).Property("weight", 1).From(__.V().Has("name", "marko")).To(__.V().Has("name", "vadas"))), (g,p) =>g.E( [...] {"g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27), (g,p) =>g.AddE((string) "edge").From(__.V().Has("name", "marko")).To(__.V().Has("name", "vadas")).Property("weight", 0.5).With(" [...] {"g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).AddV((string) "person").Property("name", "vadas").Property("age", 27), (g,p) =>g.AddE((string) "knows").From(__.V().Has("name", "marko")).To(__.V().Has("name", "vadas")).Property("weight", 0.5).Add [...] - {"g_addEXa_bX_from_V_to_V_labels_fold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").AddV((string) "person").Property("name", "josh"), (g,p) =>g.AddE((string) "knows", (string) "trusts").From(__.V().Has("name", "marko")).To(__.V().Has("name", "josh")).Labels().Fold(), (g,p) =>g.E().HasLabel("knows"), (g,p) =>g.E().HasLabel("trusts")}}, - {"g_addEXa_b_cX_from_V_to_V_labels_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").AddV((string) "person").Property("name", "josh"), (g,p) =>g.AddE((string) "a", (string) "b", (string) "c").From(__.V().Has("name", "marko")).To(__.V().Has("name", "josh")).Labels().Count()}}, {"g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age [...] {"g_V_addVXanimalX_propertyXage_0X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "softwar [...] {"g_V_addVXanimalvarX_propertyXage_0varX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 29).As("marko").AddV((string) "person").Property("name", "vadas").Property("age", 27).As("vadas").AddV((string) "software").Property("name", "lop").Property("lang", "java").As("lop").AddV((string) "person").Property("name", "josh").Property("age", 32).As("josh").AddV((string) "s [...] @@ -1996,7 +1994,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko"), (g,p) =>g.V().HasLabel("person").Has("name", "marko").AddLabel("employee").Labels().Fold(), (g,p) =>g.V().HasLabel("person").HasLabel("employee")}}, {"g_V_addLabelXa_bX_labels_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person"), (g,p) =>g.V().AddLabel("a", "b").Labels().Count()}}, {"g_V_addLabelXexistingX_labels_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person"), (g,p) =>g.V().AddLabel("person").Labels().Count()}}, - {"g_E_addLabelXfriendX_labels_fold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").As("a").AddV((string) "person").Property("name", "josh").As("b").AddE((string) "knows").From("a").To("b"), (g,p) =>g.E().AddLabel("friend").Labels().Fold(), (g,p) =>g.E().HasLabel("knows"), (g,p) =>g.E().HasLabel("friend")}}, + {"g_E_addLabelXfriendX_labels_fold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").Property("name", "marko").As("a").AddV((string) "person").Property("name", "josh").As("b").AddE((string) "knows").From("a").To("b"), (g,p) =>g.E().AddLabel("friend").Labels().Fold()}}, {"g_V_valueXnameX_aggregateXxX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate("x").Cap<object>("x")}}, {"g_V_aggregateXxX_byXnameX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate("x").By("name").Cap<object>("x")}}, {"g_V_out_aggregateXaX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Aggregate("a").Path()}}, @@ -2058,8 +2056,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_V_dropLabels_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "a", (string) "b"), (g,p) =>g.V().DropLabels().Labels()}}, {"g_V_dropLabelXa_bX_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "a", (string) "b", (string) "c"), (g,p) =>g.V().DropLabel("a", "b").Labels()}}, {"g_V_dropLabels_defaultLabel", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person"), (g,p) =>g.V().DropLabels().Labels()}}, - {"g_E_dropLabelXknowsX_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").As("a").AddV((string) "person").As("b").AddE("knows", "trusts").From("a").To("b"), (g,p) =>g.E().DropLabel("knows").Labels().Fold(), (g,p) =>g.E().HasLabel("knows"), (g,p) =>g.E().HasLabel("trusts")}}, - {"g_E_dropLabels_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").As("a").AddV((string) "person").As("b").AddE("knows", "trusts").From("a").To("b"), (g,p) =>g.E().DropLabels().Labels()}}, + {"g_E_dropLabelXknowsX_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").As("a").AddV((string) "person").As("b").AddE((string) "knows").From("a").To("b"), (g,p) =>g.E().DropLabel("knows").Labels().Fold()}}, + {"g_E_dropLabels_labels", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "person").As("a").AddV((string) "person").As("b").AddE((string) "knows").From("a").To("b"), (g,p) =>g.E().DropLabels().Labels()}}, {"g_V_fail", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fail()}}, {"g_V_failXmsgX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fail("msg")}}, {"g_V_unionXout_failX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Union<object>(__.Out(), __.Fail())}}, diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go index e44a411b01..5f5a2ea179 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -891,8 +891,6 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.AddE(p["xx1"]).Property("weight", 1).From(grem [...] "g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddE("edge").From(gremlingo.T__.V().Has(" [...] "g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).AddV("person").Property("name", "vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddE("knows").From(gremlingo.T__.V().Ha [...] - "g_addEXa_bX_from_V_to_V_labels_fold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").AddV("person").Property("name", "josh")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddE("knows", "trusts").From(gremlingo.T__.V().Has("name", "marko")).To(gremlingo.T__.V().Has("name", "josh")).Labels().Fold()}, func(g *gremlingo.GraphTraversal [...] - "g_addEXa_b_cX_from_V_to_V_labels_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").AddV("person").Property("name", "josh")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddE("a", "b", "c").From(gremlingo.T__.V().Has("name", "marko")).To(gremlingo.T__.V().Has("name", "josh")).Labels().Count()}}, "g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software") [...] "g_V_addVXanimalX_propertyXage_0X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Property("la [...] "g_V_addVXanimalvarX_propertyXage_0varX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Proper [...] @@ -1966,7 +1964,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Has("name", "marko").AddLabel("employee").Labels().Fold()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal [...] "g_V_addLabelXa_bX_labels_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().AddLabel("a", "b").Labels().Count()}}, "g_V_addLabelXexistingX_labels_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().AddLabel("person").Labels().Count()}}, - "g_E_addLabelXfriendX_labels_fold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").As("a").AddV("person").Property("name", "josh").As("b").AddE("knows").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().AddLabel("friend").Labels().Fold()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremling [...] + "g_E_addLabelXfriendX_labels_fold": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").As("a").AddV("person").Property("name", "josh").As("b").AddE("knows").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().AddLabel("friend").Labels().Fold()}}, "g_V_valueXnameX_aggregateXxX_capXxX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Aggregate("x").Cap("x")}}, "g_V_aggregateXxX_byXnameX_capXxX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Aggregate("x").By("name").Cap("x")}}, "g_V_out_aggregateXaX_path": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Out().Aggregate("a").Path()}}, @@ -2028,8 +2026,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_V_dropLabels_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("a", "b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().DropLabels().Labels()}}, "g_V_dropLabelXa_bX_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("a", "b", "c")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().DropLabel("a", "b").Labels()}}, "g_V_dropLabels_defaultLabel": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().DropLabels().Labels()}}, - "g_E_dropLabelXknowsX_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").As("a").AddV("person").As("b").AddE("knows", "trusts").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().DropLabel("knows").Labels().Fold()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("knows [...] - "g_E_dropLabels_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").As("a").AddV("person").As("b").AddE("knows", "trusts").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().DropLabels().Labels()}}, + "g_E_dropLabelXknowsX_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").As("a").AddV("person").As("b").AddE("knows").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().DropLabel("knows").Labels().Fold()}}, + "g_E_dropLabels_labels": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").As("a").AddV("person").As("b").AddE("knows").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().DropLabels().Labels()}}, "g_V_fail": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Fail()}}, "g_V_failXmsgX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Fail("msg")}}, "g_V_unionXout_failX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Union(gremlingo.T__.Out(), gremlingo.T__.Fail())}}, diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js index b0ff76c57d..9893904988 100644 --- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js +++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js @@ -922,8 +922,6 @@ const gremlins = { g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX: [function({g, xx1}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27) }, function({g, xx1}) { return g.union(__.addE(xx1).property("weight", 1).from_(__.V().has("name", "marko")).to(__.V().has("name", "vadas"))) }, function({g, xx1}) { return g.E().has("knows", "weight", 1) }], g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX: [function({g}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27) }, function({g}) { return g.addE("edge").from_(__.V().has("name", "marko")).to(__.V().has("name", "vadas")).property("weight", 0.5).with_("key", "value").values("weight", "key") }], g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX: [function({g}) { return g.addV("person").property("name", "marko").property("age", 29).addV("person").property("name", "vadas").property("age", 27) }, function({g}) { return g.addE("knows").from_(__.V().has("name", "marko")).to(__.V().has("name", "vadas")).property("weight", 0.5).addE("knows").from_(__.V().has("name", "marko")) }], - g_addEXa_bX_from_V_to_V_labels_fold: [function({g}) { return g.addV("person").property("name", "marko").addV("person").property("name", "josh") }, function({g}) { return g.addE("knows", "trusts").from_(__.V().has("name", "marko")).to(__.V().has("name", "josh")).labels().fold() }, function({g}) { return g.E().hasLabel("knows") }, function({g}) { return g.E().hasLabel("trusts") }], - g_addEXa_b_cX_from_V_to_V_labels_count: [function({g}) { return g.addV("person").property("name", "marko").addV("person").property("name", "josh") }, function({g}) { return g.addE("a", "b", "c").from_(__.V().has("name", "marko")).to(__.V().has("name", "josh")).labels().count() }], g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX: [function({g, vid1}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("software").property("name", "ripple").property("lang", "java").as("ripple").addV("p [...] g_V_addVXanimalX_propertyXage_0X: [function({g}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("software").property("name", "ripple").property("lang", "java").as("ripple").addV("person").property("name", "peter").property("ag [...] g_V_addVXanimalvarX_propertyXage_0varX: [function({g, xx1, xx2}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("software").property("name", "ripple").property("lang", "java").as("ripple").addV("person").property("name", "pete [...] @@ -1997,7 +1995,7 @@ const gremlins = { g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels: [function({g}) { return g.addV("person").property("name", "marko") }, function({g}) { return g.V().hasLabel("person").has("name", "marko").addLabel("employee").labels().fold() }, function({g}) { return g.V().hasLabel("person").hasLabel("employee") }], g_V_addLabelXa_bX_labels_count: [function({g}) { return g.addV("person") }, function({g}) { return g.V().addLabel("a", "b").labels().count() }], g_V_addLabelXexistingX_labels_count: [function({g}) { return g.addV("person") }, function({g}) { return g.V().addLabel("person").labels().count() }], - g_E_addLabelXfriendX_labels_fold: [function({g}) { return g.addV("person").property("name", "marko").as("a").addV("person").property("name", "josh").as("b").addE("knows").from_("a").to("b") }, function({g}) { return g.E().addLabel("friend").labels().fold() }, function({g}) { return g.E().hasLabel("knows") }, function({g}) { return g.E().hasLabel("friend") }], + g_E_addLabelXfriendX_labels_fold: [function({g}) { return g.addV("person").property("name", "marko").as("a").addV("person").property("name", "josh").as("b").addE("knows").from_("a").to("b") }, function({g}) { return g.E().addLabel("friend").labels().fold() }], g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return g.V().values("name").aggregate("x").cap("x") }], g_V_aggregateXxX_byXnameX_capXxX: [function({g}) { return g.V().aggregate("x").by("name").cap("x") }], g_V_out_aggregateXaX_path: [function({g}) { return g.V().out().aggregate("a").path() }], @@ -2059,8 +2057,8 @@ const gremlins = { g_V_dropLabels_labels: [function({g}) { return g.addV("a", "b") }, function({g}) { return g.V().dropLabels().labels() }], g_V_dropLabelXa_bX_labels: [function({g}) { return g.addV("a", "b", "c") }, function({g}) { return g.V().dropLabel("a", "b").labels() }], g_V_dropLabels_defaultLabel: [function({g}) { return g.addV("person") }, function({g}) { return g.V().dropLabels().labels() }], - g_E_dropLabelXknowsX_labels: [function({g}) { return g.addV("person").as("a").addV("person").as("b").addE("knows", "trusts").from_("a").to("b") }, function({g}) { return g.E().dropLabel("knows").labels().fold() }, function({g}) { return g.E().hasLabel("knows") }, function({g}) { return g.E().hasLabel("trusts") }], - g_E_dropLabels_labels: [function({g}) { return g.addV("person").as("a").addV("person").as("b").addE("knows", "trusts").from_("a").to("b") }, function({g}) { return g.E().dropLabels().labels() }], + g_E_dropLabelXknowsX_labels: [function({g}) { return g.addV("person").as("a").addV("person").as("b").addE("knows").from_("a").to("b") }, function({g}) { return g.E().dropLabel("knows").labels().fold() }], + g_E_dropLabels_labels: [function({g}) { return g.addV("person").as("a").addV("person").as("b").addE("knows").from_("a").to("b") }, function({g}) { return g.E().dropLabels().labels() }], g_V_fail: [function({g}) { return g.V().fail() }], g_V_failXmsgX: [function({g}) { return g.V().fail("msg") }], g_V_unionXout_failX: [function({g}) { return g.V().union(__.out(), __.fail()) }], diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index 2d7fa316a6..b60c62c6e8 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -113,7 +113,6 @@ traversalSourceSpawnMethod traversalSourceSpawnMethod_addE : K_ADDE LPAREN RPAREN | K_ADDE LPAREN stringArgument RPAREN - | K_ADDE LPAREN stringArgument COMMA stringArgument (COMMA stringArgument)* RPAREN | K_ADDE LPAREN nestedTraversal RPAREN ; @@ -329,7 +328,6 @@ traversalMethod_E traversalMethod_addE : K_ADDE LPAREN RPAREN #traversalMethod_addE_Empty | K_ADDE LPAREN stringArgument RPAREN #traversalMethod_addE_String - | K_ADDE LPAREN stringArgument (COMMA stringArgument)+ RPAREN #traversalMethod_addE_StringVarargs | K_ADDE LPAREN nestedTraversal RPAREN #traversalMethod_addE_Traversal ; diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py b/gremlin-python/src/main/python/tests/feature/gremlin.py index 3c9709c755..61c4af5360 100644 --- a/gremlin-python/src/main/python/tests/feature/gremlin.py +++ b/gremlin-python/src/main/python/tests/feature/gremlin.py @@ -896,8 +896,6 @@ world.gremlins = { 'g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX': [(lambda g, xx1=None:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27)), (lambda g, xx1=None:g.union(__.add_e(xx1).property('weight', 1).from_(__.V().has('name', 'marko')).to(__.V().has('name', 'vadas')))), (lambda g, xx1=None:g.E().has('knows', 'weight', 1))], 'g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX': [(lambda g:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27)), (lambda g:g.add_e('edge').from_(__.V().has('name', 'marko')).to(__.V().has('name', 'vadas')).property('weight', 0.5).with_('key', 'value').values('weight', 'key'))], 'g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX': [(lambda g:g.add_v('person').property('name', 'marko').property('age', 29).add_v('person').property('name', 'vadas').property('age', 27)), (lambda g:g.add_e('knows').from_(__.V().has('name', 'marko')).to(__.V().has('name', 'vadas')).property('weight', 0.5).add_e('knows').from_(__.V().has('name', 'marko')))], - 'g_addEXa_bX_from_V_to_V_labels_fold': [(lambda g:g.add_v('person').property('name', 'marko').add_v('person').property('name', 'josh')), (lambda g:g.add_e('knows', 'trusts').from_(__.V().has('name', 'marko')).to(__.V().has('name', 'josh')).labels().fold()), (lambda g:g.E().has_label('knows')), (lambda g:g.E().has_label('trusts'))], - 'g_addEXa_b_cX_from_V_to_V_labels_count': [(lambda g:g.add_v('person').property('name', 'marko').add_v('person').property('name', 'josh')), (lambda g:g.add_e('a', 'b', 'c').from_(__.V().has('name', 'marko')).to(__.V().has('name', 'josh')).labels().count())], 'g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX': [(lambda g, vid1=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add [...] 'g_V_addVXanimalX_propertyXage_0X': [(lambda g:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_v('person').property('name', 'peter').property('ag [...] 'g_V_addVXanimalvarX_propertyXage_0varX': [(lambda g, xx1=None,xx2=None:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('software').property('name', 'ripple').property('lang', 'java').as_('ripple').add_v('person').property('nam [...] @@ -1971,7 +1969,7 @@ world.gremlins = { 'g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels': [(lambda g:g.add_v('person').property('name', 'marko')), (lambda g:g.V().has_label('person').has('name', 'marko').add_label('employee').labels().fold()), (lambda g:g.V().has_label('person').has_label('employee'))], 'g_V_addLabelXa_bX_labels_count': [(lambda g:g.add_v('person')), (lambda g:g.V().add_label('a', 'b').labels().count())], 'g_V_addLabelXexistingX_labels_count': [(lambda g:g.add_v('person')), (lambda g:g.V().add_label('person').labels().count())], - 'g_E_addLabelXfriendX_labels_fold': [(lambda g:g.add_v('person').property('name', 'marko').as_('a').add_v('person').property('name', 'josh').as_('b').add_e('knows').from_('a').to('b')), (lambda g:g.E().add_label('friend').labels().fold()), (lambda g:g.E().has_label('knows')), (lambda g:g.E().has_label('friend'))], + 'g_E_addLabelXfriendX_labels_fold': [(lambda g:g.add_v('person').property('name', 'marko').as_('a').add_v('person').property('name', 'josh').as_('b').add_e('knows').from_('a').to('b')), (lambda g:g.E().add_label('friend').labels().fold())], 'g_V_valueXnameX_aggregateXxX_capXxX': [(lambda g:g.V().values('name').aggregate('x').cap('x'))], 'g_V_aggregateXxX_byXnameX_capXxX': [(lambda g:g.V().aggregate('x').by('name').cap('x'))], 'g_V_out_aggregateXaX_path': [(lambda g:g.V().out().aggregate('a').path())], @@ -2033,8 +2031,8 @@ world.gremlins = { 'g_V_dropLabels_labels': [(lambda g:g.add_v('a', 'b')), (lambda g:g.V().drop_labels().labels())], 'g_V_dropLabelXa_bX_labels': [(lambda g:g.add_v('a', 'b', 'c')), (lambda g:g.V().drop_label('a', 'b').labels())], 'g_V_dropLabels_defaultLabel': [(lambda g:g.add_v('person')), (lambda g:g.V().drop_labels().labels())], - 'g_E_dropLabelXknowsX_labels': [(lambda g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 'trusts').from_('a').to('b')), (lambda g:g.E().drop_label('knows').labels().fold()), (lambda g:g.E().has_label('knows')), (lambda g:g.E().has_label('trusts'))], - 'g_E_dropLabels_labels': [(lambda g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 'trusts').from_('a').to('b')), (lambda g:g.E().drop_labels().labels())], + 'g_E_dropLabelXknowsX_labels': [(lambda g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')), (lambda g:g.E().drop_label('knows').labels().fold())], + 'g_E_dropLabels_labels': [(lambda g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')), (lambda g:g.E().drop_labels().labels())], 'g_V_fail': [(lambda g:g.V().fail())], 'g_V_failXmsgX': [(lambda g:g.V().fail('msg'))], 'g_V_unionXout_failX': [(lambda g:g.V().union(__.out(), __.fail()))], diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json index 7de3961add..db9e62435f 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json @@ -17831,88 +17831,6 @@ } ] }, - { - "scenario": "g_addEXa_bX_from_V_to_V_labels_fold", - "traversals": [ - { - "original": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "language": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "canonical": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "anonymized": "g.addV(string0).property(string1, string2).addV(string0).property(string1, string3)", - "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").AddV((string) \"person\").Property(\"name\", \"josh\")", - "go": "g.AddV(\"person\").Property(\"name\", \"marko\").AddV(\"person\").Property(\"name\", \"josh\")", - "groovy": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "java": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "javascript": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "python": "g.add_v('person').property('name', 'marko').add_v('person').property('name', 'josh')" - }, - { - "original": "g.addE(\"knows\", \"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().fold()", - "language": "g.addE(\"knows\", \"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().fold()", - "canonical": "g.addE(\"knows\", \"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().fold()", - "anonymized": "g.addE(string0, string1).from(__.V().has(string2, string3)).to(__.V().has(string2, string4)).labels().fold()", - "dotnet": "g.AddE((string) \"knows\", (string) \"trusts\").From(__.V().Has(\"name\", \"marko\")).To(__.V().Has(\"name\", \"josh\")).Labels().Fold()", - "go": "g.AddE(\"knows\", \"trusts\").From(gremlingo.T__.V().Has(\"name\", \"marko\")).To(gremlingo.T__.V().Has(\"name\", \"josh\")).Labels().Fold()", - "groovy": "g.addE(\"knows\", \"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().fold()", - "java": "g.addE(\"knows\", \"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().fold()", - "javascript": "g.addE(\"knows\", \"trusts\").from_(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().fold()", - "python": "g.add_e('knows', 'trusts').from_(__.V().has('name', 'marko')).to(__.V().has('name', 'josh')).labels().fold()" - }, - { - "original": "g.E().hasLabel(\"knows\")", - "language": "g.E().hasLabel(\"knows\")", - "canonical": "g.E().hasLabel(\"knows\")", - "anonymized": "g.E().hasLabel(string0)", - "dotnet": "g.E().HasLabel(\"knows\")", - "go": "g.E().HasLabel(\"knows\")", - "groovy": "g.E().hasLabel(\"knows\")", - "java": "g.E().hasLabel(\"knows\")", - "javascript": "g.E().hasLabel(\"knows\")", - "python": "g.E().has_label('knows')" - }, - { - "original": "g.E().hasLabel(\"trusts\")", - "language": "g.E().hasLabel(\"trusts\")", - "canonical": "g.E().hasLabel(\"trusts\")", - "anonymized": "g.E().hasLabel(string0)", - "dotnet": "g.E().HasLabel(\"trusts\")", - "go": "g.E().HasLabel(\"trusts\")", - "groovy": "g.E().hasLabel(\"trusts\")", - "java": "g.E().hasLabel(\"trusts\")", - "javascript": "g.E().hasLabel(\"trusts\")", - "python": "g.E().has_label('trusts')" - } - ] - }, - { - "scenario": "g_addEXa_b_cX_from_V_to_V_labels_count", - "traversals": [ - { - "original": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "language": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "canonical": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "anonymized": "g.addV(string0).property(string1, string2).addV(string0).property(string1, string3)", - "dotnet": "g.AddV((string) \"person\").Property(\"name\", \"marko\").AddV((string) \"person\").Property(\"name\", \"josh\")", - "go": "g.AddV(\"person\").Property(\"name\", \"marko\").AddV(\"person\").Property(\"name\", \"josh\")", - "groovy": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "java": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "javascript": "g.addV(\"person\").property(\"name\", \"marko\").addV(\"person\").property(\"name\", \"josh\")", - "python": "g.add_v('person').property('name', 'marko').add_v('person').property('name', 'josh')" - }, - { - "original": "g.addE(\"a\", \"b\", \"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()", - "language": "g.addE(\"a\", \"b\", \"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()", - "canonical": "g.addE(\"a\", \"b\", \"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()", - "anonymized": "g.addE(string0, string1, string2).from(__.V().has(string3, string4)).to(__.V().has(string3, string5)).labels().count()", - "dotnet": "g.AddE((string) \"a\", (string) \"b\", (string) \"c\").From(__.V().Has(\"name\", \"marko\")).To(__.V().Has(\"name\", \"josh\")).Labels().Count()", - "go": "g.AddE(\"a\", \"b\", \"c\").From(gremlingo.T__.V().Has(\"name\", \"marko\")).To(gremlingo.T__.V().Has(\"name\", \"josh\")).Labels().Count()", - "groovy": "g.addE(\"a\", \"b\", \"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()", - "java": "g.addE(\"a\", \"b\", \"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()", - "javascript": "g.addE(\"a\", \"b\", \"c\").from_(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()", - "python": "g.add_e('a', 'b', 'c').from_(__.V().has('name', 'marko')).to(__.V().has('name', 'josh')).labels().count()" - } - ] - }, { "scenario": "g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX", "traversals": [ @@ -41652,30 +41570,6 @@ "java": "g.E().addLabel(\"friend\").labels().fold()", "javascript": "g.E().addLabel(\"friend\").labels().fold()", "python": "g.E().add_label('friend').labels().fold()" - }, - { - "original": "g.E().hasLabel(\"knows\")", - "language": "g.E().hasLabel(\"knows\")", - "canonical": "g.E().hasLabel(\"knows\")", - "anonymized": "g.E().hasLabel(string0)", - "dotnet": "g.E().HasLabel(\"knows\")", - "go": "g.E().HasLabel(\"knows\")", - "groovy": "g.E().hasLabel(\"knows\")", - "java": "g.E().hasLabel(\"knows\")", - "javascript": "g.E().hasLabel(\"knows\")", - "python": "g.E().has_label('knows')" - }, - { - "original": "g.E().hasLabel(\"friend\")", - "language": "g.E().hasLabel(\"friend\")", - "canonical": "g.E().hasLabel(\"friend\")", - "anonymized": "g.E().hasLabel(string0)", - "dotnet": "g.E().HasLabel(\"friend\")", - "go": "g.E().HasLabel(\"friend\")", - "groovy": "g.E().hasLabel(\"friend\")", - "java": "g.E().hasLabel(\"friend\")", - "javascript": "g.E().hasLabel(\"friend\")", - "python": "g.E().has_label('friend')" } ] }, @@ -42792,16 +42686,16 @@ "scenario": "g_E_dropLabelXknowsX_labels", "traversals": [ { - "original": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "language": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "canonical": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "anonymized": "g.addV(string0).as(string1).addV(string0).as(string2).addE(string3, string4).from(string1).to(string2)", - "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) \"person\").As(\"b\").AddE(\"knows\", \"trusts\").From(\"a\").To(\"b\")", - "go": "g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\", \"trusts\").From(\"a\").To(\"b\")", - "groovy": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "java": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "javascript": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from_(\"a\").to(\"b\")", - "python": "g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 'trusts').from_('a').to('b')" + "original": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "language": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "canonical": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "anonymized": "g.addV(string0).as(string1).addV(string0).as(string2).addE(string3).from(string1).to(string2)", + "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) \"person\").As(\"b\").AddE((string) \"knows\").From(\"a\").To(\"b\")", + "go": "g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\").From(\"a\").To(\"b\")", + "groovy": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "java": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "javascript": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from_(\"a\").to(\"b\")", + "python": "g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')" }, { "original": "g.E().dropLabel(\"knows\").labels().fold()", @@ -42814,30 +42708,6 @@ "java": "g.E().dropLabel(\"knows\").labels().fold()", "javascript": "g.E().dropLabel(\"knows\").labels().fold()", "python": "g.E().drop_label('knows').labels().fold()" - }, - { - "original": "g.E().hasLabel(\"knows\")", - "language": "g.E().hasLabel(\"knows\")", - "canonical": "g.E().hasLabel(\"knows\")", - "anonymized": "g.E().hasLabel(string0)", - "dotnet": "g.E().HasLabel(\"knows\")", - "go": "g.E().HasLabel(\"knows\")", - "groovy": "g.E().hasLabel(\"knows\")", - "java": "g.E().hasLabel(\"knows\")", - "javascript": "g.E().hasLabel(\"knows\")", - "python": "g.E().has_label('knows')" - }, - { - "original": "g.E().hasLabel(\"trusts\")", - "language": "g.E().hasLabel(\"trusts\")", - "canonical": "g.E().hasLabel(\"trusts\")", - "anonymized": "g.E().hasLabel(string0)", - "dotnet": "g.E().HasLabel(\"trusts\")", - "go": "g.E().HasLabel(\"trusts\")", - "groovy": "g.E().hasLabel(\"trusts\")", - "java": "g.E().hasLabel(\"trusts\")", - "javascript": "g.E().hasLabel(\"trusts\")", - "python": "g.E().has_label('trusts')" } ] }, @@ -42845,16 +42715,16 @@ "scenario": "g_E_dropLabels_labels", "traversals": [ { - "original": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "language": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "canonical": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "anonymized": "g.addV(string0).as(string1).addV(string0).as(string2).addE(string3, string4).from(string1).to(string2)", - "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) \"person\").As(\"b\").AddE(\"knows\", \"trusts\").From(\"a\").To(\"b\")", - "go": "g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\", \"trusts\").From(\"a\").To(\"b\")", - "groovy": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "java": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from(\"a\").to(\"b\")", - "javascript": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", \"trusts\").from_(\"a\").to(\"b\")", - "python": "g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 'trusts').from_('a').to('b')" + "original": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "language": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "canonical": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "anonymized": "g.addV(string0).as(string1).addV(string0).as(string2).addE(string3).from(string1).to(string2)", + "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) \"person\").As(\"b\").AddE((string) \"knows\").From(\"a\").To(\"b\")", + "go": "g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\").From(\"a\").To(\"b\")", + "groovy": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "java": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")", + "javascript": "g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from_(\"a\").to(\"b\")", + "python": "g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')" }, { "original": "g.E().dropLabels().labels()", diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature index 267cefaec9..70058962bc 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature @@ -529,35 +529,3 @@ Feature: Step - addE() """ When iterated to list Then the traversal will raise an error with message containing text of "must resolve to a Vertex or the ID of a Vertex present in the graph" - - @MultiLabel - Scenario: g_addEXa_bX_from_V_to_V_labels_fold - Given the empty graph - And the graph initializer of - """ - g.addV("person").property("name", "marko").addV("person").property("name", "josh") - """ - And the traversal of - """ - g.addE("knows", "trusts").from(__.V().has("name", "marko")).to(__.V().has("name", "josh")).labels().fold() - """ - When iterated to list - Then the result should have a count of 1 - And the graph should return 1 for count of "g.E().hasLabel(\"knows\")" - And the graph should return 1 for count of "g.E().hasLabel(\"trusts\")" - - @MultiLabel - Scenario: g_addEXa_b_cX_from_V_to_V_labels_count - Given the empty graph - And the graph initializer of - """ - g.addV("person").property("name", "marko").addV("person").property("name", "josh") - """ - And the traversal of - """ - g.addE("a", "b", "c").from(__.V().has("name", "marko")).to(__.V().has("name", "josh")).labels().count() - """ - When iterated to list - Then the result should be unordered - | result | - | d[3].l | diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature index 930e3a181b..af095ecc7a 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature @@ -1112,5 +1112,5 @@ Feature: Step - mergeV() When iterated to list Then the result should have a count of 1 And the graph should return 1 for count of "g.V()" - And the graph should return 1 for count of "g.V().hasLabel(\"vertex\")" + And the graph should return 0 for count of "g.V().hasLabel(\"vertex\")" And the graph should return 0 for count of "g.V().hasLabel(\"person\")" diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature index 5c0891ebb8..0837669796 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature @@ -77,6 +77,4 @@ Feature: Step - addLabel() g.E().addLabel("friend").labels().fold() """ When iterated to list - Then the result should have a count of 1 - And the graph should return 1 for count of "g.E().hasLabel(\"knows\")" - And the graph should return 1 for count of "g.E().hasLabel(\"friend\")" + Then the traversal will raise an error with message containing text of "Cannot add label" diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature index 0c60f6c3c0..c96e375cde 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature @@ -46,9 +46,7 @@ Feature: Step - dropLabel() / dropLabels() g.V().dropLabels().labels() """ When iterated to list - Then the result should be unordered - | result | - | vertex | + Then the result should have a count of 0 @MultiLabel Scenario: g_V_dropLabelXa_bX_labels @@ -78,16 +76,14 @@ Feature: Step - dropLabel() / dropLabels() g.V().dropLabels().labels() """ When iterated to list - Then the result should be unordered - | result | - | vertex | + Then the result should have a count of 0 @MultiLabel Scenario: g_E_dropLabelXknowsX_labels Given the empty graph And the graph initializer of """ - g.addV("person").as("a").addV("person").as("b").addE("knows", "trusts").from("a").to("b") + g.addV("person").as("a").addV("person").as("b").addE("knows").from("a").to("b") """ And the traversal of """ @@ -95,21 +91,17 @@ Feature: Step - dropLabel() / dropLabels() """ When iterated to list Then the result should have a count of 1 - And the graph should return 0 for count of "g.E().hasLabel(\"knows\")" - And the graph should return 1 for count of "g.E().hasLabel(\"trusts\")" @MultiLabel Scenario: g_E_dropLabels_labels Given the empty graph And the graph initializer of """ - g.addV("person").as("a").addV("person").as("b").addE("knows", "trusts").from("a").to("b") + g.addV("person").as("a").addV("person").as("b").addE("knows").from("a").to("b") """ And the traversal of """ g.E().dropLabels().labels() """ When iterated to list - Then the result should be unordered - | result | - | edge | + Then the result should have a count of 0 diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java index c23ccee3e0..fced442b11 100644 --- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java +++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java @@ -57,7 +57,10 @@ public class TypeSerializerFailureTests { @Parameterized.Parameters(name = "Value={0}") public static Collection input() { - final ReferenceVertex vertex = new ReferenceVertex("a vertex", (String) null); + // Use an unserializable id (raw Object has no registered TypeSerializer) to force + // serialization failure for vertex/edge cases. Previously null labels caused the + // failure, but now empty labels are serialized gracefully as empty lists. + final ReferenceVertex vertex = new ReferenceVertex(new Object(), "a vertex"); final BulkSet<Object> bulkSet = new BulkSet<>(); bulkSet.add(vertex, 1L); @@ -72,7 +75,7 @@ public class TypeSerializerFailureTests { vertex, bulkSet, Collections.singletonList(vertex), - new ReferenceEdge("an edge", (String) null, vertex, vertex), + new ReferenceEdge(new Object(), "an edge", vertex, vertex), Lambda.supplier(null), metrics, new DefaultTraversalMetrics(1L, Collections.singletonList(metrics)), diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java index b2b5b99281..3f1f994af9 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java @@ -23,6 +23,7 @@ import org.apache.tinkerpop.gremlin.process.computer.GraphComputer; 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.LabelCardinality; import org.apache.tinkerpop.gremlin.structure.Transaction; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -63,6 +64,8 @@ public abstract class AbstractTinkerGraph implements Graph { public static final String GREMLIN_TINKERGRAPH_GRAPH_FORMAT = "gremlin.tinkergraph.graphFormat"; public static final String GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES = "gremlin.tinkergraph.allowNullPropertyValues"; public static final String GREMLIN_TINKERGRAPH_SERVICE = "gremlin.tinkergraph.service"; + public static final String GREMLIN_TINKERGRAPH_VERTEX_LABEL_CARDINALITY = "gremlin.tinkergraph.vertexLabelCardinality"; + public static final String GREMLIN_TINKERGRAPH_EDGE_LABEL_CARDINALITY = "gremlin.tinkergraph.edgeLabelCardinality"; protected AtomicLong currentId = new AtomicLong(-1L); protected Map<Object, VertexProperty> vertexProperties = new ConcurrentHashMap<>(); @@ -77,6 +80,10 @@ public abstract class AbstractTinkerGraph implements Graph { protected IdManager<VertexProperty> vertexPropertyIdManager; protected VertexProperty.Cardinality defaultVertexPropertyCardinality; protected boolean allowNullPropertyValues; + protected LabelCardinality vertexLabelCardinality; + protected LabelCardinality edgeLabelCardinality; + protected String defaultVertexLabel; + protected String defaultEdgeLabel; protected TinkerServiceRegistry serviceRegistry; @@ -385,6 +392,16 @@ public abstract class AbstractTinkerGraph implements Graph { public VertexProperty.Cardinality getCardinality(final String key) { return defaultVertexPropertyCardinality; } + + @Override + public LabelCardinality getLabelCardinality() { + return vertexLabelCardinality; + } + + @Override + public String getDefaultLabel() { + return defaultVertexLabel; + } } public class TinkerGraphEdgeFeatures implements Features.EdgeFeatures { @@ -406,6 +423,16 @@ public abstract class AbstractTinkerGraph implements Graph { public boolean willAllowId(final Object id) { return edgeIdManager.allow(id); } + + @Override + public LabelCardinality getLabelCardinality() { + return edgeLabelCardinality; + } + + @Override + public String getDefaultLabel() { + return defaultEdgeLabel; + } } public class TinkerGraphVertexPropertyFeatures implements Features.VertexPropertyFeatures { diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java index b37913a0aa..c55b3a30ce 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java @@ -29,6 +29,7 @@ import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; @@ -131,12 +132,21 @@ public class TinkerEdge extends TinkerElement implements Edge { @Override public Set<String> labels() { + if (this.edgeLabels.isEmpty()) { + if (!this.graph.edgeLabelCardinality.supportsZeroLabels()) { + return Collections.singleton(this.graph.defaultEdgeLabel); + } + return Collections.emptySet(); + } return Collections.unmodifiableSet(this.edgeLabels); } @Override @Deprecated public String label() { + if (this.edgeLabels.isEmpty()) { + return this.graph.edgeLabelCardinality.supportsZeroLabels() ? null : this.graph.defaultEdgeLabel; + } return this.edgeLabels.iterator().next(); } @@ -147,11 +157,9 @@ public class TinkerEdge extends TinkerElement implements Edge { for (final String l : labels) { ElementHelper.validateLabel(l); } - // Remove default label if it was the only label - if (this.edgeLabels.size() == 1 && this.edgeLabels.contains(Edge.DEFAULT_LABEL)) { - this.graph.removeEdgeFromAdjacency(this, Edge.DEFAULT_LABEL); - this.edgeLabels.remove(Edge.DEFAULT_LABEL); - } + + this.graph.edgeLabelCardinality.validateAdd(this.edgeLabels, label, labels); + this.edgeLabels.add(label); this.graph.addEdgeToAdjacency(this, label); for (final String l : labels) { @@ -164,18 +172,22 @@ public class TinkerEdge extends TinkerElement implements Edge { @Override public void dropLabels() { graph.touch(this); - for (final String l : new LinkedHashSet<>(this.edgeLabels)) { + this.graph.edgeLabelCardinality.validateDropAll(this.edgeLabels); + + for (final String l : new HashSet<>(this.edgeLabels)) { this.graph.removeEdgeFromAdjacency(this, l); } this.edgeLabels.clear(); - this.edgeLabels.add(Edge.DEFAULT_LABEL); - this.graph.addEdgeToAdjacency(this, Edge.DEFAULT_LABEL); - this.label = this.edgeLabels.iterator().next(); + this.label = this.edgeLabels.isEmpty() + ? (this.graph.edgeLabelCardinality.supportsZeroLabels() ? null : this.graph.defaultEdgeLabel) + : this.edgeLabels.iterator().next(); } @Override public void dropLabel(final String label, final String... labels) { graph.touch(this); + this.graph.edgeLabelCardinality.validateDrop(this.edgeLabels, label); + if (this.edgeLabels.contains(label)) { this.graph.removeEdgeFromAdjacency(this, label); this.edgeLabels.remove(label); @@ -186,11 +198,9 @@ public class TinkerEdge extends TinkerElement implements Edge { this.edgeLabels.remove(l); } } - if (this.edgeLabels.isEmpty()) { - this.edgeLabels.add(Edge.DEFAULT_LABEL); - this.graph.addEdgeToAdjacency(this, Edge.DEFAULT_LABEL); - } - this.label = this.edgeLabels.iterator().next(); + this.label = this.edgeLabels.isEmpty() + ? (this.graph.edgeLabelCardinality.supportsZeroLabels() ? null : this.graph.defaultEdgeLabel) + : this.edgeLabels.iterator().next(); } @Override diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java index b780b71281..b47810dc75 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java @@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies; 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.LabelCardinality; import org.apache.tinkerpop.gremlin.structure.Transaction; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -86,6 +87,13 @@ public class TinkerGraph extends AbstractTinkerGraph { configuration.getString(GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY, VertexProperty.Cardinality.single.name())); allowNullPropertyValues = configuration.getBoolean(GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES, false); + vertexLabelCardinality = LabelCardinality.valueOf( + configuration.getString(GREMLIN_TINKERGRAPH_VERTEX_LABEL_CARDINALITY, LabelCardinality.ZERO_OR_MORE.name())); + edgeLabelCardinality = LabelCardinality.valueOf( + configuration.getString(GREMLIN_TINKERGRAPH_EDGE_LABEL_CARDINALITY, LabelCardinality.ZERO_OR_ONE.name())); + defaultVertexLabel = Vertex.DEFAULT_LABEL; + defaultEdgeLabel = Edge.DEFAULT_LABEL; + graphLocation = configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_LOCATION, null); graphFormat = configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_FORMAT, null); @@ -136,7 +144,7 @@ public class TinkerGraph extends AbstractTinkerGraph { ElementHelper.legalPropertyKeyValueArray(keyValues); Object idValue = vertexIdManager.convert(ElementHelper.getIdValue(keyValues).orElse(null)); final Set<String> labels = ElementHelper.getLabelsValue(keyValues).orElse( - Collections.singleton(Vertex.DEFAULT_LABEL)); + Collections.singleton(defaultVertexLabel)); if (null != idValue) { if (this.vertices.containsKey(idValue)) diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java index ad1c59a511..48bfc7a3de 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java @@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies; 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.LabelCardinality; import org.apache.tinkerpop.gremlin.structure.Transaction; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -85,6 +86,13 @@ public final class TinkerTransactionGraph extends AbstractTinkerGraph { configuration.getString(GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY, VertexProperty.Cardinality.single.name())); allowNullPropertyValues = configuration.getBoolean(GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES, false); + vertexLabelCardinality = LabelCardinality.valueOf( + configuration.getString(GREMLIN_TINKERGRAPH_VERTEX_LABEL_CARDINALITY, LabelCardinality.ZERO_OR_MORE.name())); + edgeLabelCardinality = LabelCardinality.valueOf( + configuration.getString(GREMLIN_TINKERGRAPH_EDGE_LABEL_CARDINALITY, LabelCardinality.ZERO_OR_ONE.name())); + defaultVertexLabel = Vertex.DEFAULT_LABEL; + defaultEdgeLabel = Edge.DEFAULT_LABEL; + graphLocation = configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_LOCATION, null); graphFormat = configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_FORMAT, null); @@ -138,7 +146,7 @@ public final class TinkerTransactionGraph extends AbstractTinkerGraph { if (null == idValue) idValue = vertexIdManager.getNextId(this); final Set<String> labels = ElementHelper.getLabelsValue(keyValues).orElse( - Collections.singleton(Vertex.DEFAULT_LABEL)); + Collections.singleton(defaultVertexLabel)); this.tx().readWrite(); final long txNumber = transaction.getTxNumber(); diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java index f3a97beb13..c605841fd0 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java @@ -30,6 +30,7 @@ import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -79,24 +80,41 @@ public class TinkerVertex extends TinkerElement implements Vertex { * Canonical constructor. Constructs a TinkerVertex with multiple labels and a specific version (for transactional graphs). */ protected TinkerVertex(final Object id, final Set<String> labels, final AbstractTinkerGraph graph, final long currentVersion) { - super(id, (labels == null || labels.isEmpty()) ? Vertex.DEFAULT_LABEL : labels.iterator().next(), currentVersion); + super(id, null, currentVersion); // label field set below this.graph = graph; this.isTxMode = graph instanceof TinkerTransactionGraph; this.allowNullPropertyValues = graph.features().vertex().supportsNullPropertyValues(); - this.vertexLabels = (labels == null || labels.isEmpty()) - ? new LinkedHashSet<>(Collections.singleton(Vertex.DEFAULT_LABEL)) - : new LinkedHashSet<>(labels); + // Store only explicit labels — never store the default label physically + this.vertexLabels = (labels == null) ? new HashSet<>() : new HashSet<>(labels); + // Set the cached label field to the effective value (including virtual default) + this.label = effectiveLabel(); + } + + /** + * Computes the effective single label for the deprecated label() API and the cached field. + */ + private String effectiveLabel() { + if (this.vertexLabels.isEmpty()) { + return this.graph.vertexLabelCardinality.supportsZeroLabels() ? null : this.graph.defaultVertexLabel; + } + return this.vertexLabels.iterator().next(); } @Override public Set<String> labels() { + if (this.vertexLabels.isEmpty()) { + if (!this.graph.vertexLabelCardinality.supportsZeroLabels()) { + return Collections.singleton(this.graph.defaultVertexLabel); + } + return Collections.emptySet(); + } return Collections.unmodifiableSet(this.vertexLabels); } @Override @Deprecated public String label() { - return this.vertexLabels.iterator().next(); + return effectiveLabel(); } @Override @@ -106,36 +124,33 @@ public class TinkerVertex extends TinkerElement implements Vertex { ElementHelper.validateLabel(l); } - // Remove default label if it was the only label and we're adding real labels - if (this.vertexLabels.size() == 1 && this.vertexLabels.contains(Vertex.DEFAULT_LABEL)) { - this.vertexLabels.remove(Vertex.DEFAULT_LABEL); - } + this.graph.vertexLabelCardinality.validateAdd(this.vertexLabels, label, labels); this.vertexLabels.add(label); Collections.addAll(this.vertexLabels, labels); - this.label = this.vertexLabels.iterator().next(); + this.label = effectiveLabel(); this.graph.updateVertexLabelIndex(this); } @Override public void dropLabels() { + this.graph.vertexLabelCardinality.validateDropAll(this.vertexLabels); + this.vertexLabels.clear(); - this.vertexLabels.add(Vertex.DEFAULT_LABEL); - this.label = this.vertexLabels.iterator().next(); + this.label = effectiveLabel(); this.graph.updateVertexLabelIndex(this); } @Override public void dropLabel(final String label, final String... labels) { + this.graph.vertexLabelCardinality.validateDrop(this.vertexLabels, label); + this.vertexLabels.remove(label); for (final String l : labels) { this.vertexLabels.remove(l); } - if (this.vertexLabels.isEmpty()) { - this.vertexLabels.add(Vertex.DEFAULT_LABEL); - } - this.label = this.vertexLabels.iterator().next(); + this.label = effectiveLabel(); this.graph.updateVertexLabelIndex(this); } @@ -267,6 +282,24 @@ public class TinkerVertex extends TinkerElement implements Vertex { final List<Edge> edges = new ArrayList<>(); this.edges(Direction.BOTH).forEachRemaining(edge -> edges.add(edge)); edges.stream().filter(edge -> !((TinkerEdge) edge).removed).forEach(Edge::remove); + + // Also remove any orphaned edges from the global edges map that reference this vertex. + // Edges can become orphaned from the adjacency maps when their labels are dropped via + // dropLabels()/dropLabel(), which removes them from the vertex's outEdges/inEdges but + // leaves them in the graph's global edges map. + final Object thisId = this.id(); + final List<Object> orphanedEdgeIds = new ArrayList<>(); + graph.edges().forEachRemaining(edge -> { + if (!((TinkerEdge) edge).removed) { + if (edge.outVertex().id().equals(thisId) || edge.inVertex().id().equals(thisId)) { + orphanedEdgeIds.add(edge.id()); + } + } + }); + for (final Object edgeId : orphanedEdgeIds) { + graph.removeEdge(edgeId); + } + TinkerIndexHelper.removeElementIndex(this); if (null != this.properties) this.properties.values().forEach(vpList -> vpList.forEach(vp -> graph.vertexProperties.remove(vp.id()))); diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java index 2257a15b60..d1f39a8265 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java @@ -147,8 +147,7 @@ public class MergeVMultiLabelTest { g.mergeV(Map.of(T.label, "person", "name", "marko")) .option(Merge.onMatch, Map.of(T.label, Collections.emptySet())).next(); - // empty collection triggers default label behavior - assertThat(v.labels(), hasSize(1)); - assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL)); + // Under ZERO_OR_MORE cardinality, empty collection means no labels + assertThat(v.labels(), hasSize(0)); } } diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java index 5aeea9daa8..71ffc0ce94 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java @@ -133,10 +133,9 @@ public class LabelMutationPropertyTest { // drop all labels g.V(v).dropLabels().iterate(); - assertThat("Iteration " + i + ": after dropLabels(), vertex should have exactly one label", - v.labels(), hasSize(1)); - assertThat("Iteration " + i + ": after dropLabels(), vertex should have default label", - v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL)); + // Under ZERO_OR_MORE cardinality, dropping all labels results in empty set + assertThat("Iteration " + i + ": after dropLabels(), vertex should have no labels", + v.labels(), hasSize(0)); } } diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java index 7ac5c88015..d9c00fbfc6 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java @@ -78,14 +78,13 @@ public class LabelMutationStepTest { assertThat(v.labels(), containsInAnyOrder("person", "manager")); } - @Test + @Test(expected = IllegalStateException.class) public void shouldAddLabelToEdgeViaTraversal() { final Vertex v1 = g.addV("person").next(); final Vertex v2 = g.addV("person").next(); final Edge e = v1.addEdge("knows", v2); + // Under ZERO_OR_ONE cardinality for edges, adding a second label throws g.E().addLabel("friend").iterate(); - assertThat(e.labels(), hasSize(2)); - assertThat(e.labels(), containsInAnyOrder("knows", "friend")); } // --- dropLabel step tests --- @@ -102,8 +101,8 @@ public class LabelMutationStepTest { public void shouldDropAllLabelsViaTraversal() { final Vertex v = g.addV("person").addLabel("employee").next(); g.V(v).dropLabels().iterate(); - assertThat(v.labels(), hasSize(1)); - assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL)); + // Under ZERO_OR_MORE cardinality, dropping all labels results in empty set + assertThat(v.labels(), hasSize(0)); } @Test @@ -120,8 +119,8 @@ public class LabelMutationStepTest { final Vertex v2 = g.addV("person").next(); final Edge e = v1.addEdge("knows", v2); g.E().dropLabels().iterate(); - assertThat(e.labels(), hasSize(1)); - assertThat(e.labels(), containsInAnyOrder(Edge.DEFAULT_LABEL)); + // Under ZERO_OR_ONE cardinality with supportsZeroLabels, edge labels become empty + assertThat(e.labels(), hasSize(0)); } // --- addV multi-label tests --- diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java index 27387d60e9..ffd5efb697 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java @@ -119,8 +119,8 @@ public class TinkerVertexMultiLabelTest { public void shouldDropAllLabelsAndAssignDefault() { final Vertex v = g.addV("person").addLabel("employee").next(); v.dropLabels(); - assertThat(v.labels(), hasSize(1)); - assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL)); + // Under ZERO_OR_MORE cardinality, dropping all labels results in empty set (no virtual default) + assertThat(v.labels(), hasSize(0)); } @Test @@ -143,18 +143,17 @@ public class TinkerVertexMultiLabelTest { public void shouldAssignDefaultWhenDroppingLastSpecificLabel() { final Vertex v = g.addV("person").next(); v.dropLabel("person"); - assertThat(v.labels(), hasSize(1)); - assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL)); + // Under ZERO_OR_MORE cardinality, dropping last label results in empty set (no virtual default) + assertThat(v.labels(), hasSize(0)); } - @Test + @Test(expected = IllegalStateException.class) public void shouldAddLabelToEdge() { final Vertex v1 = g.addV("person").next(); final Vertex v2 = g.addV("person").next(); final Edge e = v1.addEdge("knows", v2); + // Under ZERO_OR_ONE cardinality for edges, adding a second label throws e.addLabel("friend"); - assertThat(e.labels(), hasSize(2)); - assertThat(e.labels(), containsInAnyOrder("knows", "friend")); } @Test @@ -163,8 +162,8 @@ public class TinkerVertexMultiLabelTest { final Vertex v2 = g.addV("person").next(); final Edge e = v1.addEdge("knows", v2); e.dropLabels(); - assertThat(e.labels(), hasSize(1)); - assertThat(e.labels(), containsInAnyOrder(Edge.DEFAULT_LABEL)); + // Under ZERO_OR_ONE cardinality for edges with supportsZeroLabels, labels() returns empty set + assertThat(e.labels(), hasSize(0)); } @Test @@ -177,12 +176,13 @@ public class TinkerVertexMultiLabelTest { } @Test - public void shouldRemoveDefaultLabelWhenAddingFirstRealLabel() { + public void shouldAddLabelToExistingVertexWithDefaultLabel() { + // Under ZERO_OR_MORE, addV() assigns "vertex" physically. Adding "person" simply adds to the set. final Vertex v = g.addV().next(); assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL)); v.addLabel("person"); - assertThat(v.labels(), hasSize(1)); - assertThat(v.labels(), containsInAnyOrder("person")); + assertThat(v.labels(), hasSize(2)); + assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL, "person")); } @Test
