Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/main/java/apoc/map/Maps.java
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,36 @@ private void flattenMapRecursively(Map<String, Object> flattenedMap, Map<String,
}
}

@UserFunction
@Description("apoc.map.unflatten(map) yield map - unflattens dot notated nested items in map")
public Map<String,Object> unflatten( @Name( "flatMap" ) Map<String,Object> flatMap ) {
Map<String,Object> unflattenedMap = new HashMap<>();

for ( Map.Entry<String, Object> entry : flatMap.entrySet() ) {
String[] keys = entry.getKey().split( "\\." );

Map<String, Object> current = unflattenedMap;

for ( int i = 0; i < keys.length - 1; ++i ) {
String key = keys[i];

Object temp = current.get( key );
if ( temp == null ) {
Map<String, Object> next = new HashMap<>();
current.put( key, next );
current = next;
continue;
}

current = (Map<String, Object>) temp;
}

current.put( keys[keys.length - 1], entry.getValue() );
}

return unflattenedMap;
}

@UserFunction
@Description("apoc.map.sortedProperties(map, ignoreCase:true) - returns a list of key/value list pairs, with pairs sorted by keys alphabetically, with optional case sensitivity")
public List<List<Object>> sortedProperties(@Name("map") Map<String, Object> map, @Name(value="ignoreCase", defaultValue = "true") boolean ignoreCase) {
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/apoc/map/MapsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.neo4j.graphdb.Node;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;
import org.neo4j.graphdb.QueryExecutionException;

import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -317,6 +318,21 @@ public void testFlattenWithDelimiter() {
});
}

@SuppressWarnings("unchecked")
public void testUnflatten() {
Map<String, Object> flatMap = map( "string", "value", "int", 10, "nested.anotherkey", "anotherValue", "nested.nested.somekey", "someValue", "nested.nested.somenumeric", 123 );
TestUtil.testCall( db, "RETURN apoc.map.unflatten($map) AS value", map( "map", flatMap ), (r) -> {
Map<String, Object> resultMap = (Map<String, Object>)r.get( "value" );
assertEquals( map( "string", "value", "int", 10, "nested", map( "anotherkey", "anotherValue", "nested", map( "somekey", "someValue", "somenumeric", 123 ) ) ), resultMap );
} );
}

@Test (expected = QueryExecutionException.class)
public void testUnflattenConflictingKeys() {
Map<String, Object> flatMap = map( "key", "value", "key.nested", "anotherValue" );
TestUtil.testCall( db, "RETURN apoc.map.unflatten($map) AS value", map( "map", flatMap ), (r) -> {} );
}

@Test
public void testSortedProperties() {
TestUtil.testCall(db, "WITH {b:8, d:3, a:2, E: 12, C:9} as map RETURN apoc.map.sortedProperties(map, false) AS sortedProperties", (r) -> {
Expand Down