Skip to content

Commit

Permalink
Add option to wrap a nodes id to the apoc.create.virtual.fromNode
Browse files Browse the repository at this point in the history
  • Loading branch information
gem-neo4j committed Jan 3, 2025
1 parent 444989b commit 951ed5a
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 6 deletions.
10 changes: 7 additions & 3 deletions common/src/main/java/apoc/result/VirtualNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,23 @@ public VirtualNode(long nodeId) {
this.elementId = null;
}

public VirtualNode(Node node, List<String> propertyNames) {
public VirtualNode(Node node, List<String> propertyNames, boolean wrapNodeIDs) {
Objects.requireNonNull(node, ERROR_NODE_NULL);
final long id = node.getId();
// if node is already virtual, we return the same id
this.id = id < 0 ? id : -id - 1;
// to not overlap this ids with ids from VirtualNode(Label[] labels, Map<String, Object> props)
this.id = id < 0 || wrapNodeIDs ? id : -id - 1;
// to not overlap this nodes ids with ids from VirtualNode(Label[] labels, Map<String, Object> props)
MIN_ID.updateAndGet(x -> Math.min(x, this.id));
this.labels.addAll(Util.labelStrings(node));
String[] keys = propertyNames.toArray(new String[propertyNames.size()]);
this.props.putAll(node.getProperties(keys));
this.elementId = node.getElementId();
}

public VirtualNode(Node node, List<String> propertyNames) {
this(node, propertyNames, false);
}

public static VirtualNode from(Node node) {
return new VirtualNode(node, Iterables.asList(node.getPropertyKeys()));
}
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/java/apoc/create/Create.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,10 @@ public Node vNodeFunction(
public Node virtualFromNodeFunction(
@Name(value = "node", description = "The node to generate a virtual node from.") Node node,
@Name(value = "propertyNames", description = "The properties to copy to the virtual node.")
List<String> propertyNames) {
return new VirtualNode(node, propertyNames);
List<String> propertyNames,
@Name(value = "config", defaultValue = "{}", description = "{ wrapNodeIds = false :: BOOLEAN }")
Map<String, Object> config) {
return new VirtualNode(node, propertyNames, Util.toBoolean(config.get("wrapNodeIds")));
}

@Procedure("apoc.create.vNodes")
Expand Down
19 changes: 19 additions & 0 deletions core/src/test/java/apoc/create/CreateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,25 @@ public void testVirtualFromNodeFunction() {
Node node = (Node) row.get("node");

assertTrue(node.hasLabel(label("Person")));
assertTrue(node.getId() < 0);
assertEquals("Vincent", node.getProperty("name"));
assertNull(node.getProperty("born"));
});
}

@Test
public void testVirtualFromNodeFunctionWithWrapping() {
testCall(
db,
"""
CREATE (n:Person{name:'Vincent', born: 1974} )
RETURN apoc.create.virtual.fromNode(n, ['name'], { wrapNodeIds : true }) AS node
""",
(row) -> {
Node node = (Node) row.get("node");

assertTrue(node.hasLabel(label("Person")));
assertTrue(node.getId() >= 0);
assertEquals("Vincent", node.getProperty("name"));
assertNull(node.getProperty("born"));
});
Expand Down
8 changes: 7 additions & 1 deletion core/src/test/resources/functions/common/functions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,7 @@
}, {
"isDeprecated" : false,
"aggregating" : false,
"signature" : "apoc.create.virtual.fromNode(node :: NODE, propertyNames :: LIST<STRING>) :: NODE",
"signature" : "apoc.create.virtual.fromNode(node :: NODE, propertyNames :: LIST<STRING>, config = {} :: MAP) :: NODE",
"name" : "apoc.create.virtual.fromNode",
"description" : "Returns a virtual `NODE` from the given existing `NODE`. The virtual `NODE` only contains the requested properties.",
"returnDescription" : "NODE",
Expand All @@ -1660,6 +1660,12 @@
"description" : "The properties to copy to the virtual node.",
"isDeprecated" : false,
"type" : "LIST<STRING>"
}, {
"name" : "config",
"description" : "{ wrapNodeIds = false :: BOOLEAN }",
"isDeprecated" : false,
"default" : "DefaultParameterValue{value={}, type=MAP}",
"type" : "MAP"
} ]
}, {
"isDeprecated" : false,
Expand Down

0 comments on commit 951ed5a

Please sign in to comment.