This is an automated email from the ASF dual-hosted git repository. Cole-Greer pushed a commit to branch multi-label-toy-graph in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit ad751d50d39ed44684fd55eb2b6c532ac73cefd1 Author: Cole Greer <[email protected]> AuthorDate: Mon Jul 6 12:59:57 2026 -0700 Fix multi-label rendering gaps in ElementMapStep and ComputerGraph - ComputerElement.labels() previously inherited Element's default implementation (Collections.singleton(label())) instead of delegating to the wrapped element, silently losing multi-label data and returning a nondeterministic single label under GraphComputer/OLAP execution. - ElementMapStep.getVertexStructure() always rendered adjacent vertex labels via the deprecated, nondeterministic label() regardless of with("multilabel") mode, ignoring the same multilabel option that the top-level element already respected. Corrected two scenarios in ElementMap.feature whose expected values assumed the old behavior. - gremlin-javascript's DotNetTranslateVisitor never unwrapped the StringArgumentVarargsContext node introduced for multi-label addV(), so generated .NET translations were missing the (string) cast that the Java translator already applies; also fixed a labeled-alternative method name mismatch that left visitTraversalSourceSpawnMethod_addV as dead code (never dispatched by the ANTLR visitor). Assisted-by: Claude Code:claude-sonnet-5 --- .../gremlin/process/computer/util/ComputerGraph.java | 5 +++++ .../gremlin/process/traversal/step/map/ElementMapStep.java | 9 ++++++++- .../lib/language/translator/DotNetTranslateVisitor.ts | 13 ++++++++++++- .../tinkerpop/gremlin/test/features/map/ElementMap.feature | 4 ++-- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java index 5634cbbc09..1a302adaea 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/util/ComputerGraph.java @@ -135,6 +135,11 @@ public final class ComputerGraph implements Graph { return this.element.label(); } + @Override + public Set<String> labels() { + return this.element.labels(); + } + @Override public Graph graph() { return ComputerGraph.this; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java index a9566032e5..9eb0e05a21 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java @@ -97,7 +97,14 @@ public class ElementMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>> imple m.put(T.id, v.id()); // can't add label if doing GraphComputer stuff as there is no access to the label of the adjacent vertex - if (!onGraphComputer) m.put(T.label, v.label()); + if (!onGraphComputer) { + if (isMultilabelEnabled()) { + m.put(T.label, v.labels()); + } else { + final String label = v.label(); + if (!label.isEmpty()) m.put(T.label, label); + } + } return m; } diff --git a/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts b/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts index 8955acc5f4..fc22d85a01 100644 --- a/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts +++ b/gremlin-js/gremlin-javascript/lib/language/translator/DotNetTranslateVisitor.ts @@ -359,6 +359,14 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { if (ctx?.variable() != null || ctx?.stringLiteral() != null) this.sb.push('(string) '); } + private visitStringArgumentVarargsWithCast(ctx: any): void { + for (let ix = 0; ix < ctx.getChildCount(); ix++) { + const child = ctx.getChild(ix); + if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); + this.visit(child); + } + } + private tryAppendCastToString_StringNullableLit(ctx: any): void { if (ctx?.K_NULL != null && ctx.K_NULL() != null) this.sb.push('(string) '); } @@ -421,11 +429,12 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { this.sb.push(')'); } - visitTraversalSourceSpawnMethod_addV(ctx: any): void { + visitTraversalSourceSpawnMethod_addV_String(ctx: any): void { this.sb.push(capitalize(ctx.getChild(0).getText())); for (let ix = 1; ix < ctx.getChildCount(); ix++) { const child = ctx.getChild(ix); if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); + else if (child.constructor?.name === 'StringArgumentVarargsContext') { this.visitStringArgumentVarargsWithCast(child); continue; } this.visit(child); } } @@ -610,6 +619,7 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { for (let ix = 1; ix < ctx.getChildCount(); ix++) { const child = ctx.getChild(ix); if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); + else if (child.constructor?.name === 'StringArgumentVarargsContext') { this.visitStringArgumentVarargsWithCast(child); continue; } this.visit(child); } } @@ -619,6 +629,7 @@ export default class DotNetTranslateVisitor extends TranslateVisitor { for (let ix = 1; ix < ctx.getChildCount(); ix++) { const child = ctx.getChild(ix); if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); + else if (child.constructor?.name === 'StringArgumentVarargsContext') { this.visitStringArgumentVarargsWithCast(child); continue; } this.visit(child); } } diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/ElementMap.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/ElementMap.feature index e5a746bf80..4cc80f1529 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/ElementMap.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/ElementMap.feature @@ -250,7 +250,7 @@ Feature: Step - elementMap() When iterated to list Then the result should be unordered | result | - | m[{"t[id]": "e[marko-knows->josh].id", "t[label]": "s[knows]", "weight": "d[0.5].d", "D[OUT]": "m[{\\"t[id]\\": \\"v[marko].id\\", \\"t[label]\\": \\"person\\"}]", "D[IN]": "m[{\\"t[id]\\": \\"v[josh].id\\", \\"t[label]\\": \\"person\\"}]"}] | + | m[{"t[id]": "e[marko-knows->josh].id", "t[label]": "s[knows]", "weight": "d[0.5].d", "D[OUT]": "m[{\\"t[id]\\": \\"v[marko].id\\", \\"t[label]\\": \\"s[person]\\"}]", "D[IN]": "m[{\\"t[id]\\": \\"v[josh].id\\", \\"t[label]\\": \\"s[person]\\"}]"}] | @GraphComputerVerificationReferenceOnly @MultiLabel @MultiLabelDefault Scenario: g_E_elementMap_multi_label_default @@ -266,7 +266,7 @@ Feature: Step - elementMap() When iterated to list Then the result should be unordered | result | - | m[{"t[id]": "e[marko-knows->josh].id", "t[label]": "s[knows]", "weight": "d[0.5].d", "D[OUT]": "m[{\\"t[id]\\": \\"v[marko].id\\", \\"t[label]\\": \\"person\\"}]", "D[IN]": "m[{\\"t[id]\\": \\"v[josh].id\\", \\"t[label]\\": \\"person\\"}]"}] | + | m[{"t[id]": "e[marko-knows->josh].id", "t[label]": "s[knows]", "weight": "d[0.5].d", "D[OUT]": "m[{\\"t[id]\\": \\"v[marko].id\\", \\"t[label]\\": \\"s[person]\\"}]", "D[IN]": "m[{\\"t[id]\\": \\"v[josh].id\\", \\"t[label]\\": \\"s[person]\\"}]"}] | @GraphComputerVerificationReferenceOnly @MultiLabel @SingleLabelDefault Scenario: g_E_elementMap_single_label_default
