You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by dk...@apache.org on 2019/05/02 16:11:04 UTC

[tinkerpop] 01/01: TINKERPOP-2207 Implemented SimpleValueMapStrategy

This is an automated email from the ASF dual-hosted git repository.

dkuppitz pushed a commit to branch TINKERPOP-2207
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 6efb784abbb5744c044a52582c1940478b8ffd01
Author: Daniel Kuppitz <da...@hotmail.com>
AuthorDate: Thu May 2 09:10:43 2019 -0700

    TINKERPOP-2207 Implemented SimpleValueMapStrategy
---
 CHANGELOG.asciidoc                                 |   1 +
 docs/src/upgrade/release-3.4.x.asciidoc            |  27 +++++
 .../tinkerpop/gremlin/jsr223/CoreImports.java      |   2 +
 .../finalization/SimpleValueMapStrategy.java       |  60 ++++++++++
 .../structure/io/graphson/GraphSONModule.java      |   5 +
 .../gremlin/structure/io/gryo/GryoVersion.java     |   7 +-
 .../finalization/SimpleValueMapStrategyTest.java   |  69 +++++++++++
 .../gremlin/process/ProcessComputerSuite.java      |   6 +-
 .../gremlin/process/ProcessStandardSuite.java      |   6 +-
 .../SimpleValueMapStrategyProcessTest.java         | 133 +++++++++++++++++++++
 10 files changed, 312 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 2bf08bd..9c9263f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 This release also includes changes from <<release-3-3-7, 3.3.7>>.
 
+* Implemented `SimpleValueMapStrategy`.
 * Allow a `Traversal` to know what `TraversalSource` it spawned from.
 * Fixed problem with connection pool sizing and retry.
 
diff --git a/docs/src/upgrade/release-3.4.x.asciidoc b/docs/src/upgrade/release-3.4.x.asciidoc
index bb9cf43..914bc34 100644
--- a/docs/src/upgrade/release-3.4.x.asciidoc
+++ b/docs/src/upgrade/release-3.4.x.asciidoc
@@ -27,6 +27,33 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 Please see the link:https://github.com/apache/tinkerpop/blob/3.4.2/CHANGELOG.asciidoc#release-3-4-2[changelog] for a complete list of all the modifications that are part of this release.
 
+=== Upgrading for Providers
+
+==== Automatic unfolding of valueMap() values
+
+This release contains a new strategy called `SimpleValueMapStrategy`. The strategy is not added by default, but meant to be added mainly by providers who do not support multi-valued
+properties. The strategy will automatically a `.by(unfold())` modulator to all `valueMap()` steps that don't have a `by()` modulator defined by the user. As a result, `valueMap()` will emit
+maps with single-valued values.
+
+```text
+gremlin> g.V().valueMap()
+==>[name:[marko],age:[29]]
+==>[name:[vadas],age:[27]]
+==>[name:[lop],lang:[java]]
+==>[name:[josh],age:[32]]
+==>[name:[ripple],lang:[java]]
+==>[name:[peter],age:[35]]
+gremlin> g.withStrategies(SimpleValueMapStrategy.instance()).V().valueMap()
+==>[name:marko,age:29]
+==>[name:vadas,age:27]
+==>[name:lop,lang:java]
+==>[name:josh,age:32]
+==>[name:ripple,lang:java]
+==>[name:peter,age:35]
+```
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2207[TINKERPOP-2207],
+
 == TinkerPop 3.4.1
 
 *Release Date: March 18, 2019*
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
index cc7881c..23de08a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
@@ -84,6 +84,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.Refe
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ProfileStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.SimpleValueMapStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
@@ -257,6 +258,7 @@ public final class CoreImports {
         CLASS_IMPORTS.add(ReferenceElementStrategy.class);
         CLASS_IMPORTS.add(StandardVerificationStrategy.class);
         CLASS_IMPORTS.add(EdgeLabelVerificationStrategy.class);
+        CLASS_IMPORTS.add(SimpleValueMapStrategy.class);
         // graph traversal
         CLASS_IMPORTS.add(AnonymousTraversalSource.class);
         CLASS_IMPORTS.add(__.class);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategy.java
new file mode 100644
index 0000000..988125e
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategy.java
@@ -0,0 +1,60 @@
+/*
+ * 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.strategy.finalization;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.structure.PropertyType;
+
+/**
+ * SimpleValueMapStrategy automatically adds a {@code .by(unfold())} to every {@code valueMap()} step that has no
+ * by-modulator specified. This is useful especially for providers who do not support multi-valued properties.
+ *
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+public final class SimpleValueMapStrategy
+        extends AbstractTraversalStrategy<TraversalStrategy.FinalizationStrategy>
+        implements TraversalStrategy.FinalizationStrategy {
+
+    private final static SimpleValueMapStrategy INSTANCE = new SimpleValueMapStrategy();
+
+    private SimpleValueMapStrategy() {
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        for (final Step<?, ?> step : traversal.getSteps()) {
+            if (step instanceof PropertyMapStep) {
+                final PropertyMapStep pms = (PropertyMapStep) step;
+                if (pms.getReturnType() == PropertyType.VALUE && pms.getLocalChildren().isEmpty()) {
+                    //noinspection unchecked
+                    pms.modulateBy(__.unfold().asAdmin());
+                }
+            }
+        }
+    }
+
+    public static SimpleValueMapStrategy instance() {
+        return INSTANCE;
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index 6ad5db7..3b6b8d0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -43,6 +43,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Option
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.SimpleValueMapStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
@@ -204,6 +205,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                             StandardVerificationStrategy.class,
                             EarlyLimitStrategy.class,
                             EdgeLabelVerificationStrategy.class,
+                            SimpleValueMapStrategy.class,
                             //
                             GraphFilterStrategy.class,
                             VertexProgramStrategy.class
@@ -328,6 +330,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     StandardVerificationStrategy.class,
                     EarlyLimitStrategy.class,
                     EdgeLabelVerificationStrategy.class,
+                    SimpleValueMapStrategy.class,
                     //
                     GraphFilterStrategy.class,
                     VertexProgramStrategy.class
@@ -433,6 +436,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                             StandardVerificationStrategy.class,
                             EarlyLimitStrategy.class,
                             EdgeLabelVerificationStrategy.class,
+                            SimpleValueMapStrategy.class,
                             //
                             GraphFilterStrategy.class,
                             VertexProgramStrategy.class
@@ -547,6 +551,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     StandardVerificationStrategy.class,
                     EarlyLimitStrategy.class,
                     EdgeLabelVerificationStrategy.class,
+                    SimpleValueMapStrategy.class,
                     //
                     GraphFilterStrategy.class,
                     VertexProgramStrategy.class
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index 73bac27..c13f966 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -52,6 +52,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Option
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.SimpleValueMapStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
@@ -354,7 +355,8 @@ public enum GryoVersion {
             add(GryoTypeReg.of(EarlyLimitStrategy.class, 188));
             add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 164));
-            add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));   // ***LAST ID***
+            add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));
+            add(GryoTypeReg.of(SimpleValueMapStrategy.class, 190));   // ***LAST ID***
 
             add(GryoTypeReg.of(TraverserSet.class, 58));
             add(GryoTypeReg.of(Tree.class, 61));
@@ -590,7 +592,8 @@ public enum GryoVersion {
             add(GryoTypeReg.of(EarlyLimitStrategy.class, 188));
             add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160));
             add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 167));
-            add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));   // ***LAST ID***
+            add(GryoTypeReg.of(EdgeLabelVerificationStrategy.class, 189));
+            add(GryoTypeReg.of(SimpleValueMapStrategy.class, 190));   // ***LAST ID***
             // skip 171, 172 to sync with tp33
             add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173));
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategyTest.java
new file mode 100644
index 0000000..1caf6ae
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategyTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.strategy.finalization;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+@RunWith(Parameterized.class)
+public class SimpleValueMapStrategyTest {
+
+    @Parameterized.Parameter()
+    public Traversal original;
+
+    @Parameterized.Parameter(value = 1)
+    public Traversal changed;
+
+    private void applyStrategy(final Traversal traversal) {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(SimpleValueMapStrategy.instance());
+        traversal.asAdmin().setStrategies(strategies);
+        traversal.asAdmin().applyStrategies();
+    }
+
+    @Test
+    public void doTest() {
+        applyStrategy(original);
+        assertEquals(changed, original);
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> generateTestParameters() {
+        return Arrays.asList(new Traversal[][]{
+                {__.valueMap(), __.valueMap().by(__.unfold())},
+                {__.valueMap("name","age"), __.valueMap("name","age").by(__.unfold())},
+                {__.valueMap().by(__.limit(Scope.local, 1)), __.valueMap().by(__.limit(Scope.local, 1))},
+                {__.valueMap("name","age").by(__.limit(Scope.local, 1)), __.valueMap("name","age").by(__.limit(Scope.local, 1))}
+        });
+    }
+}
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
index 0951b86..e82e8e2 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java
@@ -93,6 +93,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTe
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TreeTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategyProcessTest;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.SimpleValueMapStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategyProcessTest;
@@ -214,7 +215,10 @@ public class ProcessComputerSuite extends AbstractGremlinSuite {
 
             // optimizations
             IncidentToAdjacentStrategyProcessTest.class,
-            EarlyLimitStrategyProcessTest.class
+            EarlyLimitStrategyProcessTest.class,
+
+            // finalization
+            SimpleValueMapStrategyProcessTest.class
     };
 
     /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
index 6bd6d5b..31d6be7 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessStandardSuite.java
@@ -87,6 +87,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventS
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.TranslationStrategyProcessTest;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.SimpleValueMapStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategyProcessTest;
@@ -195,7 +196,10 @@ public class ProcessStandardSuite extends AbstractGremlinSuite {
 
             // optimizations
             IncidentToAdjacentStrategyProcessTest.class,
-            EarlyLimitStrategyProcessTest.class
+            EarlyLimitStrategyProcessTest.class,
+
+            // finalization
+            SimpleValueMapStrategyProcessTest.class
     };
 
     /**
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategyProcessTest.java
new file mode 100644
index 0000000..b5c0040
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/SimpleValueMapStrategyProcessTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.strategy.finalization;
+
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
+import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.WithOptions;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+@RunWith(GremlinProcessRunner.class)
+public class SimpleValueMapStrategyProcessTest extends AbstractGremlinProcessTest {
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void shouldApplyUnfold() throws Exception {
+
+        //
+        // without tokens
+        //
+        GraphTraversal<Vertex, Map<Object, Object>> t = g.withStrategies(SimpleValueMapStrategy.instance())
+                .V().has("person", "name", "marko").valueMap();
+
+        assertTrue(t.hasNext());
+
+        Map<Object, Object> result = t.next();
+
+        assertFalse(t.hasNext());
+        assertEquals(2, result.size());
+        assertTrue(result.containsKey("name"));
+        assertTrue(result.containsKey("age"));
+        assertEquals("marko", result.get("name"));
+        assertEquals(29, result.get("age"));
+
+        //
+        // with tokens
+        //
+        t = g.withStrategies(SimpleValueMapStrategy.instance())
+                .V().has("person", "name", "marko").valueMap().with(WithOptions.tokens);
+
+        assertTrue(t.hasNext());
+
+        result = t.next();
+
+        assertFalse(t.hasNext());
+        assertEquals(4, result.size());
+        assertTrue(result.containsKey(T.id));
+        assertTrue(result.containsKey(T.label));
+        assertTrue(result.containsKey("name"));
+        assertTrue(result.containsKey("age"));
+        assertEquals("person", result.get(T.label));
+        assertEquals("marko", result.get("name"));
+        assertEquals(29, result.get("age"));
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void shouldNotApplyUnfold() throws Exception {
+
+        final List<String> list = Collections.singletonList("X");
+
+        //
+        // without tokens
+        //
+        GraphTraversal<Vertex, Map<Object, Object>> t = g.withStrategies(SimpleValueMapStrategy.instance())
+                .V().has("person", "name", "marko").valueMap().by(__.constant(list));
+
+        assertTrue(t.hasNext());
+
+        Map<Object, Object> result = t.next();
+
+        assertFalse(t.hasNext());
+        assertEquals(2, result.size());
+        assertTrue(result.containsKey("name"));
+        assertTrue(result.containsKey("age"));
+        assertEquals(list, result.get("name"));
+        assertEquals(list, result.get("age"));
+
+        //
+        // with tokens
+        //
+        t = g.withStrategies(SimpleValueMapStrategy.instance())
+                .V().has("person", "name", "marko").valueMap().with(WithOptions.tokens).by(__.constant(list));
+
+        assertTrue(t.hasNext());
+
+        result = t.next();
+
+        assertFalse(t.hasNext());
+        assertEquals(4, result.size());
+        assertTrue(result.containsKey(T.id));
+        assertTrue(result.containsKey(T.label));
+        assertTrue(result.containsKey("name"));
+        assertTrue(result.containsKey("age"));
+        assertEquals(list, result.get(T.id));
+        assertEquals(list, result.get(T.label));
+        assertEquals(list, result.get("name"));
+        assertEquals(list, result.get("age"));
+    }
+}
\ No newline at end of file