Skip to content

Commit fd59843

Browse files
committed
Introduce executeQuery on Driver level (#1321)
* Introduce executeQuery on Driver level This is a new basic high-level API for executing idempotent queries. * Delete DriverQueryBookmarkManagerPlaceholder * Update documentation * Update documentation
1 parent 94f9c20 commit fd59843

24 files changed

+1286
-144
lines changed

driver/clirr-ignored-differences.xml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,40 @@
409409
<method>org.neo4j.driver.BaseSession session(java.lang.Class, org.neo4j.driver.SessionConfig)</method>
410410
</difference>
411411

412+
<difference>
413+
<className>org/neo4j/driver/Driver</className>
414+
<differenceType>7012</differenceType>
415+
<method>org.neo4j.driver.EagerResult executeQuery(org.neo4j.driver.Query)</method>
416+
</difference>
417+
418+
<difference>
419+
<className>org/neo4j/driver/Driver</className>
420+
<differenceType>7012</differenceType>
421+
<method>java.lang.Object executeQuery(org.neo4j.driver.Query, org.neo4j.driver.QueryConfig)</method>
422+
</difference>
423+
424+
<difference>
425+
<className>org/neo4j/driver/Driver</className>
426+
<differenceType>7012</differenceType>
427+
<method>org.neo4j.driver.EagerResult executeQuery(java.lang.String)</method>
428+
</difference>
429+
430+
<difference>
431+
<className>org/neo4j/driver/Driver</className>
432+
<differenceType>7012</differenceType>
433+
<method>org.neo4j.driver.EagerResult executeQuery(java.lang.String, java.util.Map)</method>
434+
</difference>
435+
436+
<difference>
437+
<className>org/neo4j/driver/Driver</className>
438+
<differenceType>7012</differenceType>
439+
<method>java.lang.Object executeQuery(java.lang.String, java.util.Map, org.neo4j.driver.QueryConfig)</method>
440+
</difference>
441+
442+
<difference>
443+
<className>org/neo4j/driver/Driver</className>
444+
<differenceType>7012</differenceType>
445+
<method>org.neo4j.driver.BookmarkManager queryBookmarkManager()</method>
446+
</difference>
447+
412448
</differences>

driver/src/main/java/org/neo4j/driver/Config.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public final class Config implements Serializable {
7575

7676
private static final Config EMPTY = builder().build();
7777

78+
private final BookmarkManager queryBookmarkManager;
79+
7880
/**
7981
* User defined logging
8082
*/
@@ -102,6 +104,7 @@ public final class Config implements Serializable {
102104
private final MetricsAdapter metricsAdapter;
103105

104106
private Config(ConfigBuilder builder) {
107+
this.queryBookmarkManager = builder.queryBookmarkManager;
105108
this.logging = builder.logging;
106109
this.logLeakedSessions = builder.logLeakedSessions;
107110

@@ -123,6 +126,19 @@ private Config(ConfigBuilder builder) {
123126
this.metricsAdapter = builder.metricsAdapter;
124127
}
125128

129+
/**
130+
* A {@link BookmarkManager} implementation for the driver to use on
131+
* {@link Driver#executeQuery(Query, QueryConfig)} method and its variants by default.
132+
* <p>
133+
* Please note that sessions will not use this automatically, but it is possible to enable it explicitly
134+
* using {@link SessionConfig.Builder#withBookmarkManager(BookmarkManager)}.
135+
*
136+
* @return bookmark manager, must not be {@code null}
137+
*/
138+
public BookmarkManager queryBookmarkManager() {
139+
return queryBookmarkManager;
140+
}
141+
126142
/**
127143
* Logging provider
128144
*
@@ -262,6 +278,8 @@ public String userAgent() {
262278
* Used to build new config instances
263279
*/
264280
public static final class ConfigBuilder {
281+
private BookmarkManager queryBookmarkManager =
282+
BookmarkManagers.defaultManager(BookmarkManagerConfig.builder().build());
265283
private Logging logging = DEV_NULL_LOGGING;
266284
private boolean logLeakedSessions;
267285
private int maxConnectionPoolSize = PoolSettings.DEFAULT_MAX_CONNECTION_POOL_SIZE;
@@ -281,6 +299,22 @@ public static final class ConfigBuilder {
281299

282300
private ConfigBuilder() {}
283301

302+
/**
303+
* Sets a {@link BookmarkManager} implementation for the driver to use on
304+
* {@link Driver#executeQuery(Query, QueryConfig)} method and its variants by default.
305+
* <p>
306+
* Please note that sessions will not use this automatically, but it is possible to enable it explicitly
307+
* using {@link SessionConfig.Builder#withBookmarkManager(BookmarkManager)}.
308+
*
309+
* @param queryBookmarkManager bookmark manager, must not be {@code null}
310+
* @return this builder
311+
*/
312+
public ConfigBuilder withQueryBookmarkManager(BookmarkManager queryBookmarkManager) {
313+
Objects.requireNonNull(queryBookmarkManager, "queryBookmarkManager must not be null");
314+
this.queryBookmarkManager = queryBookmarkManager;
315+
return this;
316+
}
317+
284318
/**
285319
* Provide a logging implementation for the driver to use. Java logging framework {@link java.util.logging} with {@link Level#INFO} is used by default.
286320
* Callers are expected to either implement {@link Logging} interface or provide one of the existing implementations available from static factory

driver/src/main/java/org/neo4j/driver/Driver.java

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
*/
1919
package org.neo4j.driver;
2020

21+
import java.util.Collections;
22+
import java.util.Map;
2123
import java.util.concurrent.CompletionStage;
24+
import java.util.function.Consumer;
2225
import org.neo4j.driver.async.AsyncSession;
2326
import org.neo4j.driver.exceptions.ClientException;
2427
import org.neo4j.driver.reactive.ReactiveSession;
@@ -63,6 +66,114 @@
6366
* @since 1.0 (Modified and Added {@link AsyncSession} and {@link RxSession} since 2.0)
6467
*/
6568
public interface Driver extends AutoCloseable {
69+
/**
70+
* Execute an idempotent query in a managed transaction with automatic retries on retryable errors.
71+
* <p>
72+
* This is a basic high-level API for executing idempotent queries. {@link #executeQuery(Query, QueryConfig)}
73+
* documentation provides more details.
74+
*
75+
* @param query a query value to execute
76+
* @return a query execution result value
77+
*/
78+
default EagerResult executeQuery(Query query) {
79+
var defaultConfig = QueryConfig.builder().build();
80+
return executeQuery(query, defaultConfig);
81+
}
82+
83+
/**
84+
* Execute an idempotent query in a managed transaction with automatic retries on retryable errors.
85+
* <p>
86+
* This is a basic high-level API for executing idempotent queries. There are more advanced APIs available.
87+
* For instance, {@link Session}, {@link Transaction} and transaction functions that are accessible via
88+
* methods like {@link Session#executeWrite(TransactionCallback)}, {@link Session#executeWriteWithoutResult(Consumer)}
89+
* and {@link Session#executeRead(TransactionCallback)} (there are also overloaded options available).
90+
* <p>
91+
* Causal consistency is managed via driver's {@link BookmarkManager} that is enabled by default and may
92+
* be replaced using {@link Config.ConfigBuilder#withQueryBookmarkManager(BookmarkManager)}. It is also possible
93+
* to use a different {@link BookmarkManager} or disable it via
94+
* {@link QueryConfig.Builder#withBookmarkManager(BookmarkManager)} on individual basis.
95+
* <p>
96+
* Sample usage:
97+
* <pre>
98+
* {@code
99+
* var query = new Query("CREATE (n{field: $value}) RETURN n", Map.of("value", "value"));
100+
* var eagerResult = driver.executeQuery(query, QueryConfig.defaultConfig());
101+
* }
102+
* </pre>
103+
* The above sample is functionally similar to the following use of the more advanced APIs:
104+
* <pre>
105+
* {@code
106+
* var query = new Query("CREATE (n{field: $value}) RETURN n", Map.of("value", "value"));
107+
* ResultTransformer<EagerResult> resultTransformer = ResultTransformer implementation;
108+
* var sessionConfig = SessionConfig.builder()
109+
* .withBookmarkManager(driverConfig.queryBookmarkManager())
110+
* .build();
111+
* try (var session = driver.session(sessionConfig)) {
112+
* var eagerResult = session.executeWrite(tx -> {
113+
* var result = tx.run(query);
114+
* return resultTransformer.transform(result);
115+
* });
116+
* }
117+
* }
118+
* </pre>
119+
*
120+
* @param query a query value to execute
121+
* @param config a query execution config value
122+
* @param <T> a type managed by {@link QueryConfig#resultTransformer()}
123+
* @return a query execution result value of a type managed by {@link QueryConfig#resultTransformer()}
124+
*/
125+
<T> T executeQuery(Query query, QueryConfig<T> config);
126+
127+
/**
128+
* Execute an idempotent query in a managed transaction with automatic retries on retryable errors.
129+
* <p>
130+
* This is a basic high-level API for executing idempotent queries. {@link #executeQuery(Query, QueryConfig)}
131+
* documentation provides more details.
132+
*
133+
* @param query a query string to execute
134+
* @return a query execution result value
135+
*/
136+
default EagerResult executeQuery(String query) {
137+
return executeQuery(query, Collections.emptyMap());
138+
}
139+
140+
/**
141+
* Execute an idempotent query in a managed transaction with automatic retries on retryable errors.
142+
* <p>
143+
* This is a basic high-level API for executing idempotent queries. {@link #executeQuery(Query, QueryConfig)}
144+
* documentation provides more details.
145+
*
146+
* @param query a query string to execute
147+
* @param parameters a query parameters
148+
* @return a query execution result value
149+
*/
150+
default EagerResult executeQuery(String query, Map<String, Object> parameters) {
151+
return executeQuery(new Query(query, parameters));
152+
}
153+
154+
/**
155+
* Execute an idempotent query in a managed transaction with automatic retries on retryable errors.
156+
* <p>
157+
* This is a basic high-level API for executing idempotent queries. {@link #executeQuery(Query, QueryConfig)}
158+
* documentation provides more details.
159+
*
160+
* @param query a query string to execute
161+
* @param parameters a query parameters
162+
* @param config a query execution config value
163+
* @param <T> a type managed by {@link QueryConfig#resultTransformer()}
164+
* @return a query execution result value of a type managed by {@link QueryConfig#resultTransformer()}
165+
*/
166+
default <T> T executeQuery(String query, Map<String, Object> parameters, QueryConfig<T> config) {
167+
return executeQuery(new Query(query, parameters), config);
168+
}
169+
170+
/**
171+
* Returns an instance of {@link BookmarkManager} used by {@link #executeQuery(Query, QueryConfig)} method and its variants by default.
172+
*
173+
* @return bookmark manager, must not be {@code null}
174+
*/
175+
BookmarkManager queryBookmarkManager();
176+
66177
/**
67178
* Return a flag to indicate whether or not encryption is used for this driver.
68179
*
@@ -84,6 +195,7 @@ default Session session() {
84195
/**
85196
* Instantiate a new {@link Session} with a specified {@link SessionConfig session configuration}.
86197
* Use {@link SessionConfig#forDatabase(String)} to obtain a general purpose session configuration for the specified database.
198+
*
87199
* @param sessionConfig specifies session configurations for this session.
88200
* @return a new {@link Session} object.
89201
* @see SessionConfig
@@ -257,6 +369,7 @@ default AsyncSession asyncSession(SessionConfig sessionConfig) {
257369
/**
258370
* Returns the driver metrics if metrics reporting is enabled via {@link Config.ConfigBuilder#withDriverMetrics()}.
259371
* Otherwise, a {@link ClientException} will be thrown.
372+
*
260373
* @return the driver metrics if enabled.
261374
* @throws ClientException if the driver metrics reporting is not enabled.
262375
*/
@@ -281,7 +394,7 @@ default AsyncSession asyncSession(SessionConfig sessionConfig) {
281394
/**
282395
* This verifies if the driver can connect to a remote server or a cluster
283396
* by establishing a network connection with the remote and possibly exchanging a few data before closing the connection.
284-
*
397+
* <p>
285398
* It throws exception if fails to connect. Use the exception to further understand the cause of the connectivity problem.
286399
* Note: Even if this method throws an exception, the driver still need to be closed via {@link #close()} to free up all resources.
287400
*/
@@ -290,7 +403,7 @@ default AsyncSession asyncSession(SessionConfig sessionConfig) {
290403
/**
291404
* This verifies if the driver can connect to a remote server or cluster
292405
* by establishing a network connection with the remote and possibly exchanging a few data before closing the connection.
293-
*
406+
* <p>
294407
* This operation is asynchronous and returns a {@link CompletionStage}. This stage is completed with
295408
* {@code null} when the driver connects to the remote server or cluster successfully.
296409
* It is completed exceptionally if the driver failed to connect the remote server or cluster.
@@ -303,12 +416,14 @@ default AsyncSession asyncSession(SessionConfig sessionConfig) {
303416

304417
/**
305418
* Returns true if the server or cluster the driver connects to supports multi-databases, otherwise false.
419+
*
306420
* @return true if the server or cluster the driver connects to supports multi-databases, otherwise false.
307421
*/
308422
boolean supportsMultiDb();
309423

310424
/**
311425
* Asynchronous check if the server or cluster the driver connects to supports multi-databases.
426+
*
312427
* @return a {@link CompletionStage completion stage} that returns true if the server or cluster
313428
* the driver connects to supports multi-databases, otherwise false.
314429
*/
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver;
20+
21+
import java.util.List;
22+
import org.neo4j.driver.summary.ResultSummary;
23+
24+
/**
25+
* An in-memory result of executing a Cypher query that has been consumed in full.
26+
*/
27+
public interface EagerResult {
28+
/**
29+
* Returns the keys of the records this result contains.
30+
*
31+
* @return list of keys
32+
*/
33+
List<String> keys();
34+
35+
/**
36+
* Returns the list of records this result contains.
37+
*
38+
* @return list of records
39+
*/
40+
List<Record> records();
41+
42+
/**
43+
* Returns the result summary.
44+
*
45+
* @return result summary
46+
*/
47+
ResultSummary summary();
48+
}

0 commit comments

Comments
 (0)