Skip to content

Commit 4e2f977

Browse files
authored
Fixes #4157: apoc.dv.queryAndLink how to specify direction (#4222)
* Fixes #4157: apoc.dv.queryAndLink how to specify direction * test fixes * refactoring
1 parent 32192db commit 4e2f977

File tree

5 files changed

+302
-139
lines changed

5 files changed

+302
-139
lines changed

docs/asciidoc/modules/ROOT/pages/overview/apoc.dv/apoc.dv.queryAndLink.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,13 @@ apoc.dv.queryAndLink(node :: NODE?, relName :: STRING?, name :: STRING?, params
3535
|path|PATH?
3636
|===
3737

38+
== Configuration parameters
39+
40+
The procedures support the following config parameters:
41+
42+
.Config parameters
43+
[opts=header]
44+
|===
45+
| name | type | default | description
46+
| direction | String | "OUT" | The direction of the relationships, i.e. outgoing ("OUT") or incoming ("IN").
47+
|===

docs/asciidoc/modules/ROOT/pages/virtual-resource/index.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ phrase over the previous query.
113113

114114
image::apoc.dv.jdbc-queryAndLink.png[scaledwidth="100%"]
115115

116+
The default direction of the relationships is outgoing (i.e. `{direction: "OUT"}`), but it is possible to reverse it by the config parameters.
117+
Example:
118+
119+
[source,cypher]
120+
----
121+
MATCH (hook:Hook) WITH hook
122+
CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, { direction: "IN" }) yield path
123+
RETURN path
124+
----
125+
116126
=== Listing the Virtualized Resource Catalog
117127
The apoc.dv.catalog.list procedure returns a list with all the existing Virtualized resources and their descriptions. It takes no parameters.
118128

extended-it/src/test/java/apoc/dv/DataVirtualizationCatalogTest.java

Lines changed: 101 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package apoc.dv;
22

33
import apoc.create.Create;
4-
import apoc.dv.DataVirtualizationCatalog;
54
import apoc.load.Jdbc;
65
import apoc.load.LoadCsv;
76
import apoc.util.TestUtil;
@@ -20,18 +19,16 @@
2019
import org.neo4j.test.rule.DbmsRule;
2120
import org.neo4j.test.rule.ImpermanentDbmsRule;
2221

23-
import org.junit.jupiter.api.AfterAll;
2422
import org.testcontainers.containers.JdbcDatabaseContainer;
2523
import org.testcontainers.containers.MySQLContainer;
2624

2725
import java.util.List;
2826
import java.util.Map;
29-
import java.util.function.Consumer;
3027
import java.util.stream.Collectors;
3128

3229
import static apoc.ApocConfig.APOC_IMPORT_FILE_ENABLED;
3330
import static apoc.ApocConfig.apocConfig;
34-
import static apoc.util.TestUtil.getUrlFileName;
31+
import static apoc.dv.DataVirtualizationCatalogTestUtil.*;
3532
import static apoc.util.TestUtil.testCall;
3633
import static apoc.util.TestUtil.testCallEmpty;
3734
import static apoc.util.TestUtil.testResult;
@@ -64,64 +61,22 @@ public static void tearDownContainer() {
6461

6562
@Test
6663
public void testVirtualizeCSV() {
67-
final String name = "csv_vr";
68-
final String url = getUrlFileName("test.csv").toString();
69-
final String desc = "person's details";
70-
final String query = "map.name = $name and map.age = $age";
71-
List<String> labels = List.of("Person");
72-
Map<String, Object> map = Map.of("type", "CSV",
73-
"url", url, "query", query,
74-
"desc", desc,
75-
"labels", labels);
76-
77-
final Consumer<Map<String, Object>> assertCatalogContent = (row) -> {
78-
assertEquals(name, row.get("name"));
79-
assertEquals(url, row.get("url"));
80-
assertEquals("CSV", row.get("type"));
81-
assertEquals(List.of("Person"), row.get("labels"));
82-
assertEquals(desc, row.get("desc"));
83-
assertEquals(query, row.get("query"));
84-
assertEquals(List.of("$name", "$age"), row.get("params"));
85-
};
86-
87-
testCall(db, "CALL apoc.dv.catalog.add($name, $map)",
88-
Map.of("name", name, "map", map),
89-
assertCatalogContent);
90-
91-
testCall(db, "CALL apoc.dv.catalog.list()",
92-
assertCatalogContent);
93-
94-
String personName = "Rana";
95-
String personAge = "11";
96-
97-
Map<String, Object> queryParams = Map.of("name", personName, "age", personAge);
98-
testCall(db, "CALL apoc.dv.query($name, $queryParams, $config)",
99-
Map.of("name", name, "queryParams", queryParams, "config", Map.of("header", true)),
100-
(row) -> {
101-
Node node = (Node) row.get("node");
102-
assertEquals(personName, node.getProperty("name"));
103-
assertEquals(personAge, node.getProperty("age"));
104-
assertEquals(List.of(Label.label("Person")), node.getLabels());
105-
});
106-
107-
String hookNodeName = "node to test linking";
108-
109-
db.executeTransactionally("create (:Hook {name: $hookNodeName})", Map.of("hookNodeName", hookNodeName));
64+
CsvTestResult result = getCsvCommonResult(db);
11065

11166
final String relType = "LINKED_TO";
11267
testCall(db, "MATCH (hook:Hook) WITH hook " +
113-
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
114-
"RETURN path ",
115-
Map.of("name", name, "queryParams", queryParams, "relType", relType, "config", Map.of("header", true)),
68+
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
69+
"RETURN path ",
70+
Map.of("name", result.name(), "queryParams", result.queryParams(), "relType", relType, "config", Map.of("header", true)),
11671
(row) -> {
11772
Path path = (Path) row.get("path");
11873
Node node = path.endNode();
119-
assertEquals(personName, node.getProperty("name"));
120-
assertEquals(personAge, node.getProperty("age"));
74+
assertEquals(result.personName(), node.getProperty("name"));
75+
assertEquals(result.personAge(), node.getProperty("age"));
12176
assertEquals(List.of(Label.label("Person")), node.getLabels());
12277

12378
Node hook = path.startNode();
124-
assertEquals(hookNodeName, hook.getProperty("name"));
79+
assertEquals(result.hookNodeName(), hook.getProperty("name"));
12580
assertEquals(List.of(Label.label("Hook")), hook.getLabels());
12681

12782
Relationship relationship = path.lastRelationship();
@@ -131,64 +86,53 @@ public void testVirtualizeCSV() {
13186
});
13287

13388
}
134-
89+
13590
@Test
136-
public void testVirtualizeJDBC() {
137-
String name = "jdbc_vr";
138-
String desc = "country details";
139-
List<Label> labels = List.of(Label.label("Country"));
140-
List<String> labelsAsString = List.of("Country");
141-
final String query = "SELECT * FROM country WHERE Name = ?";
142-
final String url = mysql.getJdbcUrl() + "?useSSL=false";
143-
Map<String, Object> map = Map.of("type", "JDBC",
144-
"url", url, "query", query,
145-
"desc", desc,
146-
"labels", labelsAsString);
147-
148-
testCall(db, "CALL apoc.dv.catalog.add($name, $map)",
149-
Map.of("name", name, "map", map),
91+
public void testVirtualizeCSVWithCustomDirectionIN() {
92+
CsvTestResult result = getCsvCommonResult(db);
93+
94+
final String relType = "LINKED_TO";
95+
testCall(db, "MATCH (hook:Hook) WITH hook " +
96+
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
97+
"RETURN path ",
98+
Map.of("name", result.name(), "queryParams", result.queryParams(), "relType", relType, "config", Map.of("header", true, "direction", "IN")),
15099
(row) -> {
151-
assertEquals(name, row.get("name"));
152-
assertEquals(url, row.get("url"));
153-
assertEquals("JDBC", row.get("type"));
154-
assertEquals(labelsAsString, row.get("labels"));
155-
assertEquals(desc, row.get("desc"));
156-
assertEquals(List.of("?"), row.get("params"));
157-
});
158-
159-
testCallEmpty(db, "CALL apoc.dv.query($name, ['Italy'], $config)", Map.of("name", name,
160-
"config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()))));
100+
Path path = (Path) row.get("path");
101+
Node hook = path.endNode();
102+
assertEquals(result.hookNodeName(), hook.getProperty("name"));
103+
assertEquals(List.of(Label.label("Hook")), hook.getLabels());
104+
Node node = path.startNode();
161105

162-
String country = "Netherlands";
163-
List<String> queryParams = List.of(country);
106+
assertEquals(result.personName(), node.getProperty("name"));
107+
assertEquals(result.personAge(), node.getProperty("age"));
108+
assertEquals(List.of(Label.label("Person")), node.getLabels());
164109

165-
testCall(db, "CALL apoc.dv.query($name, $queryParams, $config)",
166-
Map.of("name", name, "queryParams", queryParams,
167-
"config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()))),
168-
(row) -> {
169-
Node node = (Node) row.get("node");
170-
assertEquals(country, node.getProperty("Name"));
171-
assertEquals(labels, node.getLabels());
110+
Relationship relationship = path.lastRelationship();
111+
assertEquals(node, relationship.getStartNode());
112+
assertEquals(hook, relationship.getEndNode());
113+
assertEquals(relType, relationship.getType().name());
172114
});
173115

174-
String hookNodeName = "node to test linking";
175-
176-
db.executeTransactionally("create (:Hook {name: $hookNodeName})", Map.of("hookNodeName", hookNodeName));
116+
}
177117

118+
@Test
119+
public void testVirtualizeJDBC() {
120+
VirtualizeJdbcResult result = getVirtualizeJdbcCommonResult(db, mysql);
121+
178122
final String relType = "LINKED_TO_NEW";
179123
testCall(db, "MATCH (hook:Hook) WITH hook " +
180-
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
181-
"RETURN path ",
182-
Map.of("name", name, "queryParams", queryParams, "relType", relType,
124+
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
125+
"RETURN path ",
126+
Map.of("name", result.name(), "queryParams", result.queryParams(), "relType", relType,
183127
"config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()))),
184128
(row) -> {
185129
Path path = (Path) row.get("path");
186130
Node node = path.endNode();
187-
assertEquals(country, node.getProperty("Name"));
188-
assertEquals(labels, node.getLabels());
131+
assertEquals(result.country(), node.getProperty("Name"));
132+
assertEquals(result.labels(), node.getLabels());
189133

190134
Node hook = path.startNode();
191-
assertEquals(hookNodeName, hook.getProperty("name"));
135+
assertEquals(result.hookNodeName(), hook.getProperty("name"));
192136
assertEquals(List.of(Label.label("Hook")), hook.getLabels());
193137

194138
Relationship relationship = path.lastRelationship();
@@ -199,64 +143,53 @@ public void testVirtualizeJDBC() {
199143
}
200144

201145
@Test
202-
public void testVirtualizeJDBCWithParameterMap() {
203-
String name = "jdbc_vr";
204-
String desc = "country details";
205-
List<Label> labels = List.of(Label.label("Country"));
206-
List<String> labelsAsString = List.of("Country");
207-
final String query = "SELECT * FROM country WHERE Name = $name AND HeadOfState = $head_of_state AND Code2 = $CODE2";
208-
final String url = mysql.getJdbcUrl() + "?useSSL=false";
209-
Map<String, Object> map = Map.of("type", "JDBC",
210-
"url", url, "query", query,
211-
"desc", desc,
212-
"labels", labelsAsString);
146+
public void testVirtualizeJDBCWithCustomDirectionIN() {
147+
VirtualizeJdbcResult result = getVirtualizeJdbcCommonResult(db, mysql);
213148

214-
testCall(db, "CALL apoc.dv.catalog.add($name, $map)",
215-
Map.of("name", name, "map", map),
149+
final String relType = "LINKED_TO_NEW";
150+
testCall(db, "MATCH (hook:Hook) WITH hook " +
151+
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
152+
"RETURN path ",
153+
Map.of("name", result.name(), "queryParams", result.queryParams(), "relType", relType,
154+
"config", Map.of(
155+
"credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()),
156+
"direction", "IN"
157+
)),
216158
(row) -> {
217-
assertEquals(name, row.get("name"));
218-
assertEquals(url, row.get("url"));
219-
assertEquals("JDBC", row.get("type"));
220-
assertEquals(labelsAsString, row.get("labels"));
221-
assertEquals(desc , row.get("desc"));
222-
assertEquals(List.of("$name", "$head_of_state", "$CODE2"), row.get("params"));
223-
});
224-
225-
testCallEmpty(db, "CALL apoc.dv.query($name, {name: 'Italy', head_of_state: '', CODE2: ''}, $config)",
226-
Map.of("name", name, "config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()))));
159+
Path path = (Path) row.get("path");
160+
Node hook = path.endNode();
161+
assertEquals(result.hookNodeName(), hook.getProperty("name"));
162+
assertEquals(List.of(Label.label("Hook")), hook.getLabels());
227163

228-
String country = "Netherlands";
229-
String code2 = "NL";
230-
String headOfState = "Beatrix";
231-
Map<String, Object> queryParams = Map.of("name", country, "CODE2", code2, "head_of_state", headOfState);
164+
Node node = path.startNode();
165+
assertEquals(result.country(), node.getProperty("Name"));
166+
assertEquals(result.labels(), node.getLabels());
232167

233-
testCall(db, "CALL apoc.dv.query($name, $queryParams, $config)",
234-
Map.of("name", name, "queryParams", queryParams,
235-
"config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()))),
236-
(row) -> {
237-
Node node = (Node) row.get("node");
238-
assertEquals(country, node.getProperty("Name"));
239-
assertEquals(labels, node.getLabels());
168+
Relationship relationship = path.lastRelationship();
169+
assertEquals(node, relationship.getStartNode());
170+
assertEquals(hook, relationship.getEndNode());
171+
assertEquals(relType, relationship.getType().name());
240172
});
173+
}
241174

242-
String hookNodeName = "node to test linking";
243-
244-
db.executeTransactionally("create (:Hook {name: $hookNodeName})", Map.of("hookNodeName", hookNodeName));
175+
@Test
176+
public void testVirtualizeJDBCWithParameterMap() {
177+
VirtualizeJdbcWithParameterResult result = getVirtualizeJdbcWithParamsCommonResult(db, mysql);
245178

246179
final String relType = "LINKED_TO_NEW";
247180
testCall(db, "MATCH (hook:Hook) WITH hook " +
248181
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
249182
"RETURN path ",
250-
Map.of("name", name, "queryParams", queryParams, "relType", relType,
183+
Map.of("name", result.name(), "queryParams", result.queryParams(), "relType", relType,
251184
"config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()))),
252185
(row) -> {
253186
Path path = (Path) row.get("path");
254187
Node node = path.endNode();
255-
assertEquals(country, node.getProperty("Name"));
256-
assertEquals(labels, node.getLabels());
188+
assertEquals(result.country(), node.getProperty("Name"));
189+
assertEquals(result.labels(), node.getLabels());
257190

258191
Node hook = path.startNode();
259-
assertEquals(hookNodeName, hook.getProperty("name"));
192+
assertEquals(result.hookNodeName(), hook.getProperty("name"));
260193
assertEquals(List.of(Label.label("Hook")), hook.getLabels());
261194

262195
Relationship relationship = path.lastRelationship();
@@ -265,6 +198,36 @@ public void testVirtualizeJDBCWithParameterMap() {
265198
assertEquals(relType, relationship.getType().name());
266199
});
267200
}
201+
202+
203+
@Test
204+
public void testVirtualizeJDBCWithParameterMapAndDirectionIN() {
205+
VirtualizeJdbcWithParameterResult result = getVirtualizeJdbcWithParamsCommonResult(db, mysql);
206+
207+
final String relType = "LINKED_TO_NEW";
208+
testCall(db, "MATCH (hook:Hook) WITH hook " +
209+
"CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, $config) yield path " +
210+
"RETURN path ",
211+
Map.of("name", result.name(), "queryParams", result.queryParams(), "relType", relType,
212+
"config", Map.of("credentials", Map.of("user", mysql.getUsername(), "password", mysql.getPassword()),
213+
"direction", "IN"
214+
)),
215+
(row) -> {
216+
Path path = (Path) row.get("path");
217+
Node hook = path.endNode();
218+
assertEquals(result.hookNodeName(), hook.getProperty("name"));
219+
assertEquals(List.of(Label.label("Hook")), hook.getLabels());
220+
221+
Node node = path.startNode();
222+
assertEquals(result.country(), node.getProperty("Name"));
223+
assertEquals(result.labels(), node.getLabels());
224+
225+
Relationship relationship = path.lastRelationship();
226+
assertEquals(node, relationship.getStartNode());
227+
assertEquals(hook, relationship.getEndNode());
228+
assertEquals(relType, relationship.getType().name());
229+
});
230+
}
268231

269232
@Test
270233
public void testRemove() {
@@ -280,7 +243,7 @@ public void testRemove() {
280243

281244
db.executeTransactionally("CALL apoc.dv.catalog.add($name, $map)",
282245
Map.of("name", name, "map", map));
283-
246+
284247
testCallEmpty(db, "CALL apoc.dv.catalog.remove($name)", Map.of("name", name));
285248
}
286249

0 commit comments

Comments
 (0)