From 4b7928e8605b9f63f18d1e0d9ece712c5d2deef2 Mon Sep 17 00:00:00 2001 From: Yunling Tao Date: Thu, 9 Oct 2025 14:48:10 -0700 Subject: [PATCH] add splitByElement() to parse nested lists or sets --- CHANGELOG.asciidoc | 1 + .../gremlin/features/StepDefinition.java | 37 ++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index e7bca1cd074..a1c151f4da4 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -113,6 +113,7 @@ This release also includes changes from <>. * Renamed `MergeElementStep` to `MergeElementStep` as it is a base class to `mergeV()` and `mergeE()`. * Renamed `MergeStep` of `merge()` to `MergeElementStep` for consistency. * Modified `RepeatUnrollStrategy` to use a more conservative approach, only unrolling repeat loops containing safe navigation and filtering steps. +* Added `splitByElement()` in `gremlin-test` for parsing nested list and set == TinkerPop 3.7.0 (Gremfir Master of the Pan Flute) diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java index 26aad2c3b8d..829891f2c12 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java @@ -184,7 +184,7 @@ public final class StepDefinition { private List>> objectMatcherConverters = new ArrayList>>() {{ // expects json so that should port to the Gremlin script form - replace curly json braces with square ones // for Gremlin sake. - add(Pair.with(Pattern.compile("m\\[(.*)\\]"), s -> { + add(Pair.with(Pattern.compile("^m\\[(.*)\\]$"), s -> { try { // read tree from JSON - can't parse right to Map as each m[] level needs to be managed individually return convertToObject(mapper.readTree(s)); @@ -193,16 +193,14 @@ public final class StepDefinition { } })); - add(Pair.with(Pattern.compile("l\\[\\]"), s -> Collections.emptyList())); - add(Pair.with(Pattern.compile("l\\[(.*)\\]"), s -> { - final String[] items = s.split(","); - return Stream.of(items).map(String::trim).map(x -> convertToObject(x)).collect(Collectors.toList()); + add(Pair.with(Pattern.compile("^l\\[\\]$"), s -> Collections.emptyList())); + add(Pair.with(Pattern.compile("^l\\[(.*)\\]$"), s -> { + return splitByElement(s).stream().map(x -> convertToObject(x)).collect(Collectors.toList()); })); - add(Pair.with(Pattern.compile("s\\[\\]"), s -> Collections.emptySet())); - add(Pair.with(Pattern.compile("s\\[(.*)\\]"), s -> { - final String[] items = s.split(","); - return Stream.of(items).map(String::trim).map(x -> convertToObject(x)).collect(Collectors.toSet()); + add(Pair.with(Pattern.compile("^s\\[\\]$"), s -> Collections.emptySet())); + add(Pair.with(Pattern.compile("^s\\[(.*)\\]$"), s -> { + return splitByElement(s).stream().map(x -> convertToObject(x)).collect(Collectors.toSet()); })); // return the string values as is, used to wrap results that may contain other regex patterns @@ -642,6 +640,27 @@ private String convertToString(final String pkey, final String pvalue) { return String.format("\"%s\"", pvalue); } + private List splitByElement(String s) { + if (s.trim().isEmpty()) return Collections.emptyList(); + + List items = new ArrayList<>(); + int depth = 0, start = 0; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '[' || c == '{') depth++; + else if (c == ']' || c == '}') depth--; + else if (c == ',' && depth == 0) { + String item = s.substring(start, i).trim(); + if (!item.isEmpty()) items.add(item); + start = i + 1; + } + } + String lastItem = s.substring(start).trim(); + if (!lastItem.isEmpty()) items.add(lastItem); + return items; + } + private Object convertToObject(final Object pvalue) { final Object v; // we may get some json stuff if it's a m[]