[
https://issues.apache.org/jira/browse/TINKERPOP-2334?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17779182#comment-17779182
]
ASF GitHub Bot commented on TINKERPOP-2334:
-------------------------------------------
kenhuuu commented on code in PR #2307:
URL: https://github.com/apache/tinkerpop/pull/2307#discussion_r1370552173
##########
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("%\\{(.*?)\\}");
Review Comment:
Very minor nit: static methods are generally placed near the top of the
class.
> 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)