[ 
https://issues.apache.org/jira/browse/TINKERPOP-2334?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17779179#comment-17779179
 ] 

ASF GitHub Bot commented on TINKERPOP-2334:
-------------------------------------------

kenhuuu commented on code in PR #2307:
URL: https://github.com/apache/tinkerpop/pull/2307#discussion_r1370549922


##########
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/FormatStep.java:
##########
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalProduct;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalRing;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Reference implementation for String format step, a mid-traversal step which 
will handle result formatting
+ * to string values. If the incoming traverser is a non-String value then an 
{@code IllegalArgumentException}
+ * will be thrown.
+ *
+ * @author Valentyn Kahamlyk
+ */
+public final class FormatStep<S> extends MapStep<S, String> implements 
TraversalParent, Scoping, PathProcessor {
+
+    private String format;
+    private Set<String> variables;
+    private TraversalRing<S, String> traversalRing = new TraversalRing<>();
+    private Set<String> keepLabels;
+
+    public FormatStep(final Traversal.Admin traversal, final String format) {
+        super(traversal);
+        this.format = format;
+        this.variables = getVariables();
+    }
+
+    @Override
+    protected Traverser.Admin<String> processNextStart() {
+        final Map<String, Object> values = new HashMap<>();
+
+        final Traverser.Admin traverser = this.starts.next();
+
+        boolean productive = true;
+        for (final String var : variables) {
+            final Object current = traverser.get();
+            // try to get property value
+            if (current instanceof Element) {
+                final Property prop = ((Element) current).property(var);
+                if (prop != null && prop.isPresent()) {
+                    values.put(var, prop.value());
+                    continue;
+                }
+            }
+
+            final TraversalProduct product =
+                    TraversalUtil.produce((S) 
this.getNullableScopeValue(Pop.last, var, traverser), 
this.traversalRing.next());
+
+            if (!product.isProductive() || product.get() == null) {
+                productive = false;
+                break;
+            }
+
+            values.put(var, product.get());
+        }
+        this.traversalRing.reset();
+
+        return productive ?
+                
PathProcessor.processTraverserPathLabels(traverser.split(evaluate(values), 
this), this.keepLabels) :
+                EmptyTraverser.instance();
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.stepString(this, this.format, this.traversalRing);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        return Objects.hash(result, format, traversalRing);
+    }
+
+    @Override
+    public List<Traversal.Admin<S, String>> getLocalChildren() {
+        return this.traversalRing.getTraversals();
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        this.traversalRing.reset();
+    }
+
+    @Override
+    public FormatStep<S> clone() {
+        final FormatStep<S> clone = (FormatStep<S>) super.clone();
+        clone.format = this.format;
+        clone.variables = this.variables;
+        clone.traversalRing = this.traversalRing;
+        return clone;
+    }
+
+    @Override
+    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+        super.setTraversal(parentTraversal);
+        this.traversalRing.getTraversals().forEach(this::integrateChild);
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT, 
TraverserRequirement.SIDE_EFFECTS);
+    }
+
+    @Override
+    public Set<String> getScopeKeys() {
+        return variables;
+    }
+
+    @Override
+    public void setKeepLabels(final Set<String> labels) {
+        this.keepLabels = labels;
+    }
+
+    @Override
+    public Set<String> getKeepLabels() {
+        return this.keepLabels;
+    }
+
+    // private methods
+
+    private static final Pattern VARIABLE_PATTERN = 
Pattern.compile("%\\{(.*?)\\}");
+
+    Set<String> getVariables() {

Review Comment:
   Nit: Did you want this to be package private? If not, explicitly add the 
private modifier.





> Add format() step
> -----------------
>
>                 Key: TINKERPOP-2334
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-2334
>             Project: TinkerPop
>          Issue Type: Improvement
>          Components: process
>    Affects Versions: 3.4.4
>            Reporter: Stephen Mallette
>            Assignee: Valentyn Kahamlyk
>            Priority: Major
>
> Provide for a {{format()}} step which will handle result formatting to string 
> values. This change will help resolve the need for string concatenation 
> functions while providing a lot of flexibility to how results can be formed:
> {code}
> gremlin> g.V().hasLabel('person').format("%{n} is %{a} years old.").by('n',
> 'name').by('a', 'age')
> ==>marko is 29 years old.
> ==>vadas is 27 years old.
> ==>josh is 32 years old.
> ==>peter is 35 years old.
> gremlin> g.V().hasLabel('person').format("%{name} is %{age} years old.")
> ==>marko is 29 years old.
> ==>vadas is 27 years old.
> ==>josh is 32 years old.
> ==>peter is 35 years old.
> {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to