emptySet()
+ : disabledNotificationClassifications.stream()
+ .map(NotificationCategory.class::cast)
+ .collect(Collectors.toSet());
+ notificationConfig = notificationConfig.disableCategories(disabledCategories);
+ return this;
+ }
+
/**
* Sets if telemetry is disabled on the driver side.
*
diff --git a/driver/src/main/java/org/neo4j/driver/NotificationCategory.java b/driver/src/main/java/org/neo4j/driver/NotificationCategory.java
index 65bdecbc8d..f648c939a0 100644
--- a/driver/src/main/java/org/neo4j/driver/NotificationCategory.java
+++ b/driver/src/main/java/org/neo4j/driver/NotificationCategory.java
@@ -17,28 +17,26 @@
package org.neo4j.driver;
import java.io.Serializable;
-import org.neo4j.driver.internal.InternalNotificationCategory;
-import org.neo4j.driver.internal.InternalNotificationCategory.Type;
/**
* Notification category.
*
* @since 5.7
*/
-public sealed interface NotificationCategory extends Serializable permits InternalNotificationCategory {
+public sealed interface NotificationCategory extends Serializable permits NotificationClassification {
/**
* A hint category.
*
* For instance, the given hint cannot be satisfied.
*/
- NotificationCategory HINT = new InternalNotificationCategory(Type.HINT);
+ NotificationCategory HINT = NotificationClassification.HINT;
/**
* An unrecognized category.
*
* For instance, the query or command mentions entities that are unknown to the system.
*/
- NotificationCategory UNRECOGNIZED = new InternalNotificationCategory(Type.UNRECOGNIZED);
+ NotificationCategory UNRECOGNIZED = NotificationClassification.UNRECOGNIZED;
/**
* An unsupported category.
@@ -46,21 +44,21 @@ public sealed interface NotificationCategory extends Serializable permits Intern
* For instance, the query/command is trying to use features that are not supported by the current system or using
* features that are experimental and should not be used in production.
*/
- NotificationCategory UNSUPPORTED = new InternalNotificationCategory(Type.UNSUPPORTED);
+ NotificationCategory UNSUPPORTED = NotificationClassification.UNSUPPORTED;
/**
* A performance category.
*
* For instance, the query uses costly operations and might be slow.
*/
- NotificationCategory PERFORMANCE = new InternalNotificationCategory(Type.PERFORMANCE);
+ NotificationCategory PERFORMANCE = NotificationClassification.PERFORMANCE;
/**
* A deprecation category.
*
* For instance, the query/command use deprecated features that should be replaced.
*/
- NotificationCategory DEPRECATION = new InternalNotificationCategory(Type.DEPRECATION);
+ NotificationCategory DEPRECATION = NotificationClassification.DEPRECATION;
/**
* A security category.
@@ -72,7 +70,7 @@ public sealed interface NotificationCategory extends Serializable permits Intern
*
* @since 5.14
*/
- NotificationCategory SECURITY = new InternalNotificationCategory(Type.SECURITY);
+ NotificationCategory SECURITY = NotificationClassification.SECURITY;
/**
* A topology category.
@@ -84,12 +82,12 @@ public sealed interface NotificationCategory extends Serializable permits Intern
*
* @since 5.14
*/
- NotificationCategory TOPOLOGY = new InternalNotificationCategory(Type.TOPOLOGY);
+ NotificationCategory TOPOLOGY = NotificationClassification.TOPOLOGY;
/**
* A generic category.
*
* For instance, notifications that are not part of a more specific class.
*/
- NotificationCategory GENERIC = new InternalNotificationCategory(Type.GENERIC);
+ NotificationCategory GENERIC = NotificationClassification.GENERIC;
}
diff --git a/driver/src/main/java/org/neo4j/driver/NotificationClassification.java b/driver/src/main/java/org/neo4j/driver/NotificationClassification.java
new file mode 100644
index 0000000000..ad3c794b73
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/NotificationClassification.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver;
+
+import org.neo4j.driver.util.Preview;
+
+/**
+ * Notification classification.
+ *
+ * @since 5.22.0
+ */
+@Preview(name = "GQL-status object")
+public enum NotificationClassification implements NotificationCategory {
+ /**
+ * A hint category.
+ *
+ * For instance, the given hint cannot be satisfied.
+ */
+ HINT,
+
+ /**
+ * An unrecognized category.
+ *
+ * For instance, the query or command mentions entities that are unknown to the system.
+ */
+ UNRECOGNIZED,
+
+ /**
+ * An unsupported category.
+ *
+ * For instance, the query/command is trying to use features that are not supported by the current system or using
+ * features that are experimental and should not be used in production.
+ */
+ UNSUPPORTED,
+
+ /**
+ * A performance category.
+ *
+ * For instance, the query uses costly operations and might be slow.
+ */
+ PERFORMANCE,
+
+ /**
+ * A deprecation category.
+ *
+ * For instance, the query/command use deprecated features that should be replaced.
+ */
+ DEPRECATION,
+
+ /**
+ * A security category.
+ *
+ * For instance, the security warnings.
+ *
+ * Please note that this category was added to a later server version. Therefore, a compatible server version is
+ * required to use it.
+ */
+ SECURITY,
+
+ /**
+ * A topology category.
+ *
+ * For instance, the topology notifications.
+ *
+ * Please note that this category was added to a later server version. Therefore, a compatible server version is
+ * required to use it.
+ */
+ TOPOLOGY,
+
+ /**
+ * A generic category.
+ *
+ * For instance, notifications that are not part of a more specific class.
+ */
+ GENERIC
+}
diff --git a/driver/src/main/java/org/neo4j/driver/NotificationConfig.java b/driver/src/main/java/org/neo4j/driver/NotificationConfig.java
index 5224dfcc0f..ff85533909 100644
--- a/driver/src/main/java/org/neo4j/driver/NotificationConfig.java
+++ b/driver/src/main/java/org/neo4j/driver/NotificationConfig.java
@@ -21,6 +21,7 @@
import org.neo4j.driver.internal.InternalNotificationConfig;
import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.summary.ResultSummary;
+import org.neo4j.driver.util.Preview;
/**
* A notification configuration defining what notifications should be supplied by the server.
@@ -39,6 +40,7 @@
* @see ResultSummary#notifications()
* @see org.neo4j.driver.summary.Notification
*/
+@Preview(name = "GQL-status object")
public sealed interface NotificationConfig extends Serializable permits InternalNotificationConfig {
/**
* Returns a default notification configuration.
diff --git a/driver/src/main/java/org/neo4j/driver/NotificationSeverity.java b/driver/src/main/java/org/neo4j/driver/NotificationSeverity.java
index 09dbcbcc93..d503142686 100644
--- a/driver/src/main/java/org/neo4j/driver/NotificationSeverity.java
+++ b/driver/src/main/java/org/neo4j/driver/NotificationSeverity.java
@@ -19,7 +19,9 @@
import static org.neo4j.driver.internal.InternalNotificationSeverity.Type;
import java.io.Serializable;
+import org.neo4j.driver.Config.ConfigBuilder;
import org.neo4j.driver.internal.InternalNotificationSeverity;
+import org.neo4j.driver.util.Preview;
/**
* Notification severity level.
@@ -36,4 +38,12 @@ public sealed interface NotificationSeverity extends Serializable, Comparable minimumNotificationSeverity() {
+ return Optional.ofNullable(((InternalNotificationConfig) notificationConfig).minimumSeverity());
+ }
+
+ /**
+ * Returns a set of disabled notification classifications.
+ * @return the {@link Set} of disabled {@link NotificationClassification}
+ * @since 5.22.0
+ */
+ @Preview(name = "GQL-status object")
+ public Set disabledNotificationClassifications() {
+ var disabledCategories = ((InternalNotificationConfig) notificationConfig).disabledCategories();
+ return disabledCategories != null
+ ? ((InternalNotificationConfig) notificationConfig)
+ .disabledCategories().stream()
+ .map(NotificationClassification.class::cast)
+ .collect(Collectors.toUnmodifiableSet())
+ : Collections.emptySet();
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -214,6 +246,7 @@ public static final class Builder {
private String database = null;
private String impersonatedUser = null;
private BookmarkManager bookmarkManager;
+
private NotificationConfig notificationConfig = NotificationConfig.defaultConfig();
private Builder() {}
@@ -397,6 +430,42 @@ public Builder withNotificationConfig(NotificationConfig notificationConfig) {
return this;
}
+ /**
+ * Sets a minimum severity for notifications produced by the server.
+ *
+ * @param minimumNotificationSeverity the minimum notification severity
+ * @return this builder
+ * @since 5.22.0
+ */
+ @Preview(name = "GQL-status object")
+ public Builder withMinimumNotificationSeverity(NotificationSeverity minimumNotificationSeverity) {
+ if (minimumNotificationSeverity == null) {
+ notificationConfig = NotificationConfig.disableAllConfig();
+ } else {
+ notificationConfig = notificationConfig.enableMinimumSeverity(minimumNotificationSeverity);
+ }
+ return this;
+ }
+
+ /**
+ * Sets a set of disabled classifications for notifications produced by the server.
+ *
+ * @param disabledNotificationClassifications the set of disabled notification classifications
+ * @return this builder
+ * @since 5.22.0
+ */
+ @Preview(name = "GQL-status object")
+ public Builder withDisabledNotificationClassifications(
+ Set disabledNotificationClassifications) {
+ var disabledCategories = disabledNotificationClassifications == null
+ ? Collections.emptySet()
+ : disabledNotificationClassifications.stream()
+ .map(NotificationCategory.class::cast)
+ .collect(Collectors.toSet());
+ notificationConfig = notificationConfig.disableCategories(disabledCategories);
+ return this;
+ }
+
/**
* Builds the {@link SessionConfig}.
* @return the config
diff --git a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
index 273d9f97d5..61ade28328 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java
@@ -183,7 +183,7 @@ protected ChannelConnector createConnector(
clock,
routingContext,
getDomainNameResolver(),
- config.notificationConfig(),
+ GqlNotificationConfig.from(config.notificationConfig()),
boltAgent);
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/GqlNotificationConfig.java b/driver/src/main/java/org/neo4j/driver/internal/GqlNotificationConfig.java
new file mode 100644
index 0000000000..2a7f888c55
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/GqlNotificationConfig.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver.internal;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.neo4j.driver.NotificationClassification;
+import org.neo4j.driver.NotificationConfig;
+import org.neo4j.driver.NotificationSeverity;
+
+public record GqlNotificationConfig(
+ NotificationSeverity minimumSeverity, Set disabledClassifications) {
+ public static GqlNotificationConfig defaultConfig() {
+ return new GqlNotificationConfig(null, null);
+ }
+
+ public static GqlNotificationConfig from(NotificationConfig notificationConfig) {
+ Objects.requireNonNull(notificationConfig);
+ var config = (InternalNotificationConfig) notificationConfig;
+ var disabledClassifications = config.disabledCategories() != null
+ ? config.disabledCategories().stream()
+ .map(NotificationClassification.class::cast)
+ .collect(Collectors.toUnmodifiableSet())
+ : null;
+ return new GqlNotificationConfig(config.minimumSeverity(), disabledClassifications);
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationCategory.java b/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationCategory.java
deleted file mode 100644
index 7f6762edc9..0000000000
--- a/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationCategory.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) "Neo4j"
- * Neo4j Sweden AB [https://neo4j.com]
- *
- * Licensed 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.neo4j.driver.internal;
-
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Optional;
-import org.neo4j.driver.NotificationCategory;
-
-public record InternalNotificationCategory(Type type) implements NotificationCategory {
-
- public InternalNotificationCategory {
- Objects.requireNonNull(type, "type must not be null");
- }
-
- public enum Type {
- HINT,
- UNRECOGNIZED,
- UNSUPPORTED,
- PERFORMANCE,
- DEPRECATION,
- SECURITY,
- TOPOLOGY,
- GENERIC
- }
-
- public static Optional valueOf(String value) {
- return Arrays.stream(Type.values())
- .filter(type -> type.toString().equals(value))
- .findFirst()
- .map(type -> switch (type) {
- case HINT -> NotificationCategory.HINT;
- case UNRECOGNIZED -> NotificationCategory.UNRECOGNIZED;
- case UNSUPPORTED -> NotificationCategory.UNSUPPORTED;
- case PERFORMANCE -> NotificationCategory.PERFORMANCE;
- case DEPRECATION -> NotificationCategory.DEPRECATION;
- case SECURITY -> NotificationCategory.SECURITY;
- case TOPOLOGY -> NotificationCategory.TOPOLOGY;
- case GENERIC -> NotificationCategory.GENERIC;
- });
- }
-}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationConfig.java b/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationConfig.java
index a27c4ec602..ef85db7fb1 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationConfig.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationConfig.java
@@ -33,7 +33,7 @@ public NotificationConfig enableMinimumSeverity(NotificationSeverity minimumSeve
@Override
public NotificationConfig disableCategories(Set disabledCategories) {
- Objects.requireNonNull(disabledCategories, "disabledCategories must not be null");
+ Objects.requireNonNull(disabledCategories, "disabledClassifications must not be null");
return new InternalNotificationConfig(minimumSeverity, Set.copyOf(disabledCategories));
}
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationSeverity.java b/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationSeverity.java
index 1244cf72b2..d0821526ce 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationSeverity.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/InternalNotificationSeverity.java
@@ -22,9 +22,6 @@
import org.neo4j.driver.NotificationSeverity;
public record InternalNotificationSeverity(Type type, int level) implements NotificationSeverity {
- public static final InternalNotificationSeverity OFF =
- new InternalNotificationSeverity(Type.OFF, Integer.MAX_VALUE);
-
public InternalNotificationSeverity {
Objects.requireNonNull(type, "type must not be null");
}
@@ -47,7 +44,7 @@ public static Optional valueOf(String value) {
.map(type -> switch (type) {
case INFORMATION -> NotificationSeverity.INFORMATION;
case WARNING -> NotificationSeverity.WARNING;
- case OFF -> InternalNotificationSeverity.OFF;
+ case OFF -> NotificationSeverity.OFF;
});
}
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java b/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java
index de8ac27b94..4d2ac34073 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java
@@ -28,7 +28,6 @@
import org.neo4j.driver.BookmarkManager;
import org.neo4j.driver.Config;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.internal.async.LeakLoggingNetworkSession;
import org.neo4j.driver.internal.async.NetworkSession;
@@ -63,7 +62,7 @@ public NetworkSession newInstance(
sessionConfig.impersonatedUser().orElse(null),
logging,
sessionConfig.bookmarkManager().orElse(NoOpBookmarkManager.INSTANCE),
- sessionConfig.notificationConfig(),
+ GqlNotificationConfig.from(sessionConfig.notificationConfig()),
overrideAuthToken,
telemetryDisabled);
}
@@ -141,7 +140,7 @@ private NetworkSession createSession(
String impersonatedUser,
Logging logging,
BookmarkManager bookmarkManager,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
AuthToken authToken,
boolean telemetryDisabled) {
Objects.requireNonNull(bookmarks, "bookmarks may not be null");
diff --git a/driver/src/main/java/org/neo4j/driver/internal/StatusNotificationConfig.java b/driver/src/main/java/org/neo4j/driver/internal/StatusNotificationConfig.java
new file mode 100644
index 0000000000..5136fecc55
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/StatusNotificationConfig.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver.internal;
+
+import java.util.Set;
+import org.neo4j.driver.NotificationClassification;
+import org.neo4j.driver.NotificationSeverity;
+
+public record StatusNotificationConfig(
+ NotificationSeverity minimumNotificationSeverity,
+ Set disabledNotificationClassifications) {}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/LeakLoggingNetworkSession.java b/driver/src/main/java/org/neo4j/driver/internal/async/LeakLoggingNetworkSession.java
index f05ec9a4b1..62492175de 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/LeakLoggingNetworkSession.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/LeakLoggingNetworkSession.java
@@ -26,8 +26,8 @@
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.BookmarkManager;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.DatabaseName;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.retry.RetryLogic;
import org.neo4j.driver.internal.spi.ConnectionProvider;
import org.neo4j.driver.internal.util.Futures;
@@ -45,7 +45,7 @@ public LeakLoggingNetworkSession(
long fetchSize,
Logging logging,
BookmarkManager bookmarkManager,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
AuthToken overrideAuthToken,
boolean telemetryDisabled) {
super(
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/NetworkSession.java b/driver/src/main/java/org/neo4j/driver/internal/async/NetworkSession.java
index cc102342c1..4c036fe297 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/NetworkSession.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/NetworkSession.java
@@ -35,7 +35,6 @@
import org.neo4j.driver.BookmarkManager;
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Query;
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.async.ResultCursor;
@@ -44,6 +43,7 @@
import org.neo4j.driver.internal.DatabaseBookmark;
import org.neo4j.driver.internal.DatabaseName;
import org.neo4j.driver.internal.FailableCursor;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.ImpersonationUtil;
import org.neo4j.driver.internal.cursor.AsyncResultCursor;
import org.neo4j.driver.internal.cursor.ResultCursorFactory;
@@ -73,7 +73,7 @@ public class NetworkSession {
private final BookmarkManager bookmarkManager;
private volatile Set lastUsedBookmarks = Collections.emptySet();
private volatile Set lastReceivedBookmarks;
- private final NotificationConfig notificationConfig;
+ private final GqlNotificationConfig notificationConfig;
private final boolean telemetryDisabled;
public NetworkSession(
@@ -86,7 +86,7 @@ public NetworkSession(
long fetchSize,
Logging logging,
BookmarkManager bookmarkManager,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
AuthToken overrideAuthToken,
boolean telemetryDisabled) {
Objects.requireNonNull(bookmarks, "bookmarks may not be null");
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/UnmanagedTransaction.java b/driver/src/main/java/org/neo4j/driver/internal/async/UnmanagedTransaction.java
index 5b58e37722..cc04a529e8 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/UnmanagedTransaction.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/UnmanagedTransaction.java
@@ -36,7 +36,6 @@
import java.util.function.Function;
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Query;
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.async.ResultCursor;
@@ -45,6 +44,7 @@
import org.neo4j.driver.exceptions.ConnectionReadTimeoutException;
import org.neo4j.driver.exceptions.TransactionTerminatedException;
import org.neo4j.driver.internal.DatabaseBookmark;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.cursor.AsyncResultCursor;
import org.neo4j.driver.internal.cursor.RxResultCursor;
import org.neo4j.driver.internal.messaging.BoltProtocol;
@@ -97,7 +97,7 @@ private enum State {
private CompletableFuture rollbackFuture;
private Throwable causeOfTermination;
private CompletionStage terminationStage;
- private final NotificationConfig notificationConfig;
+ private final GqlNotificationConfig notificationConfig;
private final CompletableFuture beginFuture = new CompletableFuture<>();
private final Logging logging;
@@ -107,7 +107,7 @@ public UnmanagedTransaction(
Connection connection,
Consumer bookmarkConsumer,
long fetchSize,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
ApiTelemetryWork apiTelemetryWork,
Logging logging) {
this(
@@ -125,7 +125,7 @@ protected UnmanagedTransaction(
Consumer bookmarkConsumer,
long fetchSize,
ResultCursorsHolder resultCursors,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
ApiTelemetryWork apiTelemetryWork,
Logging logging) {
this.connection = connection;
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java b/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java
index 268d913b97..1f9e138cb1 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java
@@ -27,7 +27,7 @@
import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42;
import org.neo4j.driver.internal.messaging.v44.BoltProtocolV44;
import org.neo4j.driver.internal.messaging.v5.BoltProtocolV5;
-import org.neo4j.driver.internal.messaging.v54.BoltProtocolV54;
+import org.neo4j.driver.internal.messaging.v55.BoltProtocolV55;
public final class BoltProtocolUtil {
public static final int BOLT_MAGIC_PREAMBLE = 0x6060B017;
@@ -39,7 +39,7 @@ public final class BoltProtocolUtil {
private static final ByteBuf HANDSHAKE_BUF = unreleasableBuffer(copyInt(
BOLT_MAGIC_PREAMBLE,
- BoltProtocolV54.VERSION.toIntRange(BoltProtocolV5.VERSION),
+ BoltProtocolV55.VERSION.toIntRange(BoltProtocolV5.VERSION),
BoltProtocolV44.VERSION.toIntRange(BoltProtocolV42.VERSION),
BoltProtocolV41.VERSION.toInt(),
BoltProtocolV3.VERSION.toInt()))
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelAttributes.java b/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelAttributes.java
index ac2eaaf988..55666f1405 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelAttributes.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelAttributes.java
@@ -50,8 +50,8 @@ public final class ChannelAttributes {
// configuration hints provided by the server
private static final AttributeKey CONNECTION_READ_TIMEOUT = newInstance("connectionReadTimeout");
-
private static final AttributeKey TELEMETRY_ENABLED = newInstance("telemetryEnabled");
+ private static final AttributeKey GQL_STATUS_ENABLED = newInstance("tryUseGqlStatus");
private ChannelAttributes() {}
@@ -178,10 +178,18 @@ public static void setTelemetryEnabled(Channel channel, Boolean telemetryEnabled
setOnce(channel, TELEMETRY_ENABLED, telemetryEnabled);
}
- public static Boolean telemetryEnabled(Channel channel) {
+ public static boolean telemetryEnabled(Channel channel) {
return Optional.ofNullable(get(channel, TELEMETRY_ENABLED)).orElse(false);
}
+ public static void setGqlStatusEnabled(Channel channel, Boolean gqlStatusEnabled) {
+ setOnce(channel, GQL_STATUS_ENABLED, gqlStatusEnabled);
+ }
+
+ public static boolean gqlStatusEnabled(Channel channel) {
+ return Optional.ofNullable(get(channel, GQL_STATUS_ENABLED)).orElse(false);
+ }
+
private static T get(Channel channel, AttributeKey key) {
return channel.attr(key).get();
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelConnectorImpl.java b/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelConnectorImpl.java
index 59e7a5fe84..6bbe794aec 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelConnectorImpl.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelConnectorImpl.java
@@ -30,11 +30,11 @@
import java.util.function.Function;
import org.neo4j.driver.AuthTokenManager;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.internal.ConnectionSettings;
import org.neo4j.driver.internal.DomainNameResolver;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.async.inbound.ConnectTimeoutHandler;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.security.SecurityPlan;
@@ -52,7 +52,7 @@ public class ChannelConnectorImpl implements ChannelConnector {
private final Clock clock;
private final DomainNameResolver domainNameResolver;
private final AddressResolverGroup addressResolverGroup;
- private final NotificationConfig notificationConfig;
+ private final GqlNotificationConfig notificationConfig;
public ChannelConnectorImpl(
ConnectionSettings connectionSettings,
@@ -61,7 +61,7 @@ public ChannelConnectorImpl(
Clock clock,
RoutingContext routingContext,
DomainNameResolver domainNameResolver,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
BoltAgent boltAgent) {
this(
connectionSettings,
@@ -83,7 +83,7 @@ public ChannelConnectorImpl(
Clock clock,
RoutingContext routingContext,
DomainNameResolver domainNameResolver,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
BoltAgent boltAgent) {
this.userAgent = connectionSettings.userAgent();
this.boltAgent = requireNonNull(boltAgent);
diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListener.java b/driver/src/main/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListener.java
index b848b54c09..b125d65bb6 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListener.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListener.java
@@ -23,8 +23,8 @@
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPromise;
import java.time.Clock;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.messaging.BoltProtocol;
import org.neo4j.driver.internal.messaging.v51.BoltProtocolV51;
@@ -34,7 +34,7 @@ public class HandshakeCompletedListener implements ChannelFutureListener {
private final BoltAgent boltAgent;
private final RoutingContext routingContext;
private final ChannelPromise connectionInitializedPromise;
- private final NotificationConfig notificationConfig;
+ private final GqlNotificationConfig notificationConfig;
private final Clock clock;
public HandshakeCompletedListener(
@@ -42,7 +42,7 @@ public HandshakeCompletedListener(
BoltAgent boltAgent,
RoutingContext routingContext,
ChannelPromise connectionInitializedPromise,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
Clock clock) {
requireNonNull(clock, "clock must not be null");
this.userAgent = requireNonNull(userAgent);
diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/AbstractRecordStateResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/AbstractRecordStateResponseHandler.java
new file mode 100644
index 0000000000..24d5792e2c
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/AbstractRecordStateResponseHandler.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver.internal.handlers;
+
+import java.util.List;
+import org.neo4j.driver.internal.summary.InternalGqlStatusObject;
+import org.neo4j.driver.summary.GqlStatusObject;
+
+public abstract class AbstractRecordStateResponseHandler {
+ protected RecordState recordState = RecordState.NOT_REQUESTED;
+
+ protected synchronized GqlStatusObject generateGqlStatusObject(List keys) {
+ return switch (recordState) {
+ case NOT_REQUESTED -> keys.isEmpty()
+ ? InternalGqlStatusObject.OMITTED_RESULT
+ : InternalGqlStatusObject.NO_DATA_UNKNOWN;
+ case HAD_RECORD -> InternalGqlStatusObject.SUCCESS;
+ case NO_RECORD -> keys.isEmpty() ? InternalGqlStatusObject.OMITTED_RESULT : InternalGqlStatusObject.NO_DATA;
+ };
+ }
+
+ protected enum RecordState {
+ NOT_REQUESTED,
+ HAD_RECORD,
+ NO_RECORD
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/LegacyPullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/LegacyPullAllResponseHandler.java
index 726d2a2da3..e8073f6e61 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/handlers/LegacyPullAllResponseHandler.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/LegacyPullAllResponseHandler.java
@@ -36,16 +36,18 @@
import org.neo4j.driver.exceptions.Neo4jException;
import org.neo4j.driver.internal.InternalRecord;
import org.neo4j.driver.internal.messaging.request.PullAllMessage;
+import org.neo4j.driver.internal.messaging.v55.BoltProtocolV55;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.util.Futures;
import org.neo4j.driver.internal.util.Iterables;
import org.neo4j.driver.internal.util.MetadataExtractor;
+import org.neo4j.driver.summary.GqlStatusObject;
import org.neo4j.driver.summary.ResultSummary;
/**
* This is the Pull All response handler that handles pull all messages in Bolt v3 and previous protocol versions.
*/
-public class LegacyPullAllResponseHandler implements PullAllResponseHandler {
+public class LegacyPullAllResponseHandler extends AbstractRecordStateResponseHandler implements PullAllResponseHandler {
private static final Queue UNINITIALIZED_RECORDS = Iterables.emptyQueue();
static final int RECORD_BUFFER_LOW_WATERMARK = Integer.getInteger("recordBufferLowWatermark", 300);
@@ -92,7 +94,9 @@ public synchronized void onSuccess(Map metadata) {
finished = true;
Neo4jException exception = null;
try {
- summary = extractResultSummary(metadata);
+ summary = extractResultSummary(
+ metadata,
+ generateGqlStatusObject(runResponseHandler.queryKeys().keys()));
} catch (Neo4jException e) {
exception = e;
}
@@ -110,7 +114,7 @@ public synchronized void onSuccess(Map metadata) {
@Override
public synchronized void onFailure(Throwable error) {
finished = true;
- summary = extractResultSummary(emptyMap());
+ summary = extractResultSummary(emptyMap(), null);
completionListener.afterFailure(error);
@@ -129,6 +133,7 @@ public synchronized void onFailure(Throwable error) {
@Override
public synchronized void onRecord(Value[] fields) {
+ recordState = RecordState.HAD_RECORD;
if (ignoreRecords) {
completeRecordFuture(null);
} else {
@@ -189,6 +194,9 @@ public synchronized CompletionStage> listAsync(Function m
@Override
public void prePopulateRecords() {
+ synchronized (this) {
+ recordState = RecordState.NO_RECORD;
+ }
connection.writeAndFlush(PullAllMessage.PULL_ALL, this);
}
@@ -291,9 +299,15 @@ private boolean completeFailureFuture(Throwable error) {
return false;
}
- private ResultSummary extractResultSummary(Map metadata) {
+ private ResultSummary extractResultSummary(Map metadata, GqlStatusObject gqlStatusObject) {
var resultAvailableAfter = runResponseHandler.resultAvailableAfter();
- return metadataExtractor.extractSummary(query, connection, resultAvailableAfter, metadata);
+ return metadataExtractor.extractSummary(
+ query,
+ connection,
+ resultAvailableAfter,
+ metadata,
+ connection.protocol().version().compareTo(BoltProtocolV55.VERSION) < 0,
+ gqlStatusObject);
}
private void enableAutoRead() {
diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/pulln/BasicPullResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/pulln/BasicPullResponseHandler.java
index 017319310e..d2681786bb 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/handlers/pulln/BasicPullResponseHandler.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/pulln/BasicPullResponseHandler.java
@@ -29,18 +29,21 @@
import org.neo4j.driver.Value;
import org.neo4j.driver.exceptions.Neo4jException;
import org.neo4j.driver.internal.InternalRecord;
+import org.neo4j.driver.internal.handlers.AbstractRecordStateResponseHandler;
import org.neo4j.driver.internal.handlers.PullResponseCompletionListener;
import org.neo4j.driver.internal.handlers.RunResponseHandler;
import org.neo4j.driver.internal.messaging.request.PullMessage;
+import org.neo4j.driver.internal.messaging.v55.BoltProtocolV55;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.util.MetadataExtractor;
import org.neo4j.driver.internal.value.BooleanValue;
+import org.neo4j.driver.summary.GqlStatusObject;
import org.neo4j.driver.summary.ResultSummary;
/**
* Provides basic handling of pull responses from sever. The state is managed by {@link State}.
*/
-public class BasicPullResponseHandler implements PullResponseHandler {
+public class BasicPullResponseHandler extends AbstractRecordStateResponseHandler implements PullResponseHandler {
private static final Runnable NO_OP_RUNNABLE = () -> {};
private final Query query;
protected final RunResponseHandler runResponseHandler;
@@ -94,9 +97,15 @@ public void onSuccess(Map metadata) {
if (newState == State.SUCCEEDED_STATE) {
completionListener.afterSuccess(metadata);
try {
- summary = extractResultSummary(metadata);
+ summary = extractResultSummary(
+ metadata,
+ generateGqlStatusObject(
+ runResponseHandler.queryKeys().keys()));
} catch (Neo4jException e) {
- summary = extractResultSummary(emptyMap());
+ summary = extractResultSummary(
+ emptyMap(),
+ generateGqlStatusObject(
+ runResponseHandler.queryKeys().keys()));
exception = e;
}
recordConsumer = this.recordConsumer;
@@ -128,7 +137,7 @@ public void onFailure(Throwable error) {
assertRecordAndSummaryConsumerInstalled();
state.onFailure(this);
completionListener.afterFailure(error);
- summary = extractResultSummary(emptyMap());
+ summary = extractResultSummary(emptyMap(), null);
recordConsumer = this.recordConsumer;
summaryConsumer = this.summaryConsumer;
if (syncSignals) {
@@ -147,6 +156,7 @@ public void onRecord(Value[] fields) {
Record record = null;
synchronized (this) {
assertRecordAndSummaryConsumerInstalled();
+ recordState = RecordState.HAD_RECORD;
state.onRecord(this);
newState = state;
if (newState == State.STREAMING_STATE) {
@@ -166,6 +176,7 @@ public void request(long size) {
Runnable postAction;
synchronized (this) {
assertRecordAndSummaryConsumerInstalled();
+ recordState = RecordState.NO_RECORD;
postAction = state.request(this, size);
if (syncSignals) {
postAction.run();
@@ -219,9 +230,15 @@ protected boolean isDone() {
return state.equals(State.SUCCEEDED_STATE) || state.equals(State.FAILURE_STATE);
}
- private ResultSummary extractResultSummary(Map metadata) {
+ private ResultSummary extractResultSummary(Map metadata, GqlStatusObject gqlStatusObject) {
var resultAvailableAfter = runResponseHandler.resultAvailableAfter();
- return metadataExtractor.extractSummary(query, connection, resultAvailableAfter, metadata);
+ return metadataExtractor.extractSummary(
+ query,
+ connection,
+ resultAvailableAfter,
+ metadata,
+ connection.protocol().version().compareTo(BoltProtocolV55.VERSION) < 0,
+ gqlStatusObject);
}
private void addToRequest(long toAdd) {
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java
index bb687acb30..15181cc8cd 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java
@@ -27,7 +27,6 @@
import org.neo4j.driver.AuthToken;
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Query;
import org.neo4j.driver.Session;
import org.neo4j.driver.Transaction;
@@ -35,6 +34,7 @@
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.DatabaseBookmark;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.async.UnmanagedTransaction;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.cursor.ResultCursorFactory;
@@ -49,6 +49,7 @@
import org.neo4j.driver.internal.messaging.v52.BoltProtocolV52;
import org.neo4j.driver.internal.messaging.v53.BoltProtocolV53;
import org.neo4j.driver.internal.messaging.v54.BoltProtocolV54;
+import org.neo4j.driver.internal.messaging.v55.BoltProtocolV55;
import org.neo4j.driver.internal.spi.Connection;
public interface BoltProtocol {
@@ -67,7 +68,7 @@ public interface BoltProtocol {
* @param authToken the authentication token.
* @param routingContext the configured routing context
* @param channelInitializedPromise the promise to be notified when initialization is completed.
- * @param notificationConfig the notification configuration
+ * @param GqlNotificationConfig the notification configuration
* @param clock the clock to use
*/
void initializeChannel(
@@ -76,7 +77,7 @@ void initializeChannel(
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig GqlNotificationConfig,
Clock clock);
/**
@@ -92,7 +93,7 @@ void initializeChannel(
* @param bookmarks the bookmarks. Never null, should be empty when there are no bookmarks.
* @param config the transaction configuration. Never null, should be {@link TransactionConfig#empty()} when absent.
* @param txType the Kernel transaction type
- * @param notificationConfig the notification configuration
+ * @param GqlNotificationConfig the notification configuration
* @param logging the driver logging
* @param flush defines whether to flush the message to the connection
* @return a completion stage completed when transaction is started or completed exceptionally when there was a failure.
@@ -102,7 +103,7 @@ CompletionStage beginTransaction(
Set bookmarks,
TransactionConfig config,
String txType,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig GqlNotificationConfig,
Logging logging,
boolean flush);
@@ -138,7 +139,7 @@ CompletionStage beginTransaction(
* @param bookmarkConsumer the database bookmark consumer.
* @param config the transaction config for the implicitly started auto-commit transaction.
* @param fetchSize the record fetch size for PULL message.
- * @param notificationConfig the notification configuration
+ * @param GqlNotificationConfig the notification configuration
* @param logging the driver logging
* @return stage with cursor.
*/
@@ -149,7 +150,7 @@ ResultCursorFactory runInAutoCommitTransaction(
Consumer bookmarkConsumer,
TransactionConfig config,
long fetchSize,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig GqlNotificationConfig,
Logging logging);
/**
@@ -211,6 +212,8 @@ static BoltProtocol forVersion(BoltProtocolVersion version) {
return BoltProtocolV53.INSTANCE;
} else if (BoltProtocolV54.VERSION.equals(version)) {
return BoltProtocolV54.INSTANCE;
+ } else if (BoltProtocolV55.VERSION.equals(version)) {
+ return BoltProtocolV55.INSTANCE;
}
throw new ClientException("Unknown protocol version: " + version);
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java
index c66547fc1f..a76d34187f 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java
@@ -25,10 +25,10 @@
import org.neo4j.driver.AccessMode;
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.DatabaseName;
+import org.neo4j.driver.internal.GqlNotificationConfig;
public class BeginMessage extends MessageWithMetadata {
public static final byte SIGNATURE = 0x11;
@@ -40,7 +40,8 @@ public BeginMessage(
AccessMode mode,
String impersonatedUser,
String txType,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
+ boolean legacyNotifications,
Logging logging) {
this(
bookmarks,
@@ -51,6 +52,7 @@ public BeginMessage(
impersonatedUser,
txType,
notificationConfig,
+ legacyNotifications,
logging);
}
@@ -62,7 +64,8 @@ public BeginMessage(
DatabaseName databaseName,
String impersonatedUser,
String txType,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
+ boolean legacyNotifications,
Logging logging) {
super(buildMetadata(
txTimeout,
@@ -73,6 +76,7 @@ public BeginMessage(
impersonatedUser,
txType,
notificationConfig,
+ legacyNotifications,
logging));
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java
index 88b0b28e84..2d91a7b0a8 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java
@@ -23,9 +23,9 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.BoltAgent;
+import org.neo4j.driver.internal.GqlNotificationConfig;
public class HelloMessage extends MessageWithMetadata {
public static final byte SIGNATURE = 0x01;
@@ -40,6 +40,7 @@ public class HelloMessage extends MessageWithMetadata {
private static final String PATCH_BOLT_METADATA_KEY = "patch_bolt";
private static final String DATE_TIME_UTC_PATCH_VALUE = "utc";
+ private static final String ENABLE_GQL_STATUS = "use_status_object";
public HelloMessage(
String userAgent,
@@ -47,8 +48,16 @@ public HelloMessage(
Map authToken,
Map routingContext,
boolean includeDateTimeUtc,
- NotificationConfig notificationConfig) {
- super(buildMetadata(userAgent, boltAgent, authToken, routingContext, includeDateTimeUtc, notificationConfig));
+ GqlNotificationConfig gqlNotificationConfig,
+ boolean legacyNotifications) {
+ super(buildMetadata(
+ userAgent,
+ boltAgent,
+ authToken,
+ routingContext,
+ includeDateTimeUtc,
+ gqlNotificationConfig,
+ legacyNotifications));
}
@Override
@@ -86,7 +95,8 @@ private static Map buildMetadata(
Map authToken,
Map routingContext,
boolean includeDateTimeUtc,
- NotificationConfig notificationConfig) {
+ GqlNotificationConfig notificationConfig,
+ boolean legacyNotifications) {
Map result = new HashMap<>(authToken);
if (userAgent != null) {
result.put(USER_AGENT_METADATA_KEY, value(userAgent));
@@ -101,7 +111,7 @@ private static Map buildMetadata(
if (includeDateTimeUtc) {
result.put(PATCH_BOLT_METADATA_KEY, value(Collections.singleton(DATE_TIME_UTC_PATCH_VALUE)));
}
- MessageWithMetadata.appendNotificationConfig(result, notificationConfig);
+ MessageWithMetadata.appendNotificationConfig(result, notificationConfig, legacyNotifications);
return result;
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/MessageWithMetadata.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/MessageWithMetadata.java
index e16a9d57fd..eca850e30d 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/MessageWithMetadata.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/MessageWithMetadata.java
@@ -19,16 +19,15 @@
import static org.neo4j.driver.Values.value;
import java.util.Map;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Value;
-import org.neo4j.driver.internal.InternalNotificationCategory;
-import org.neo4j.driver.internal.InternalNotificationConfig;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.internal.messaging.Message;
abstract class MessageWithMetadata implements Message {
static final String NOTIFICATIONS_MINIMUM_SEVERITY = "notifications_minimum_severity";
static final String NOTIFICATIONS_DISABLED_CATEGORIES = "notifications_disabled_categories";
+ static final String NOTIFICATIONS_DISABLED_CLASSIFICATIONS = "notifications_disabled_classifications";
private final Map metadata;
public MessageWithMetadata(Map metadata) {
@@ -39,23 +38,22 @@ public Map metadata() {
return metadata;
}
- static void appendNotificationConfig(Map result, NotificationConfig config) {
+ static void appendNotificationConfig(
+ Map result, GqlNotificationConfig config, boolean legacyNotifications) {
if (config != null) {
- if (config instanceof InternalNotificationConfig internalConfig) {
- var severity = (InternalNotificationSeverity) internalConfig.minimumSeverity();
- if (severity != null) {
- result.put(
- NOTIFICATIONS_MINIMUM_SEVERITY,
- value(severity.type().toString()));
- }
- var disabledCategories = internalConfig.disabledCategories();
- if (disabledCategories != null) {
- var list = disabledCategories.stream()
- .map(category -> (InternalNotificationCategory) category)
- .map(category -> category.type().toString())
- .toList();
- result.put(NOTIFICATIONS_DISABLED_CATEGORIES, value(list));
- }
+ var severity = (InternalNotificationSeverity) config.minimumSeverity();
+ if (severity != null) {
+ result.put(NOTIFICATIONS_MINIMUM_SEVERITY, value(severity.type().toString()));
+ }
+ var disabledClassifications = config.disabledClassifications();
+ if (disabledClassifications != null) {
+ var list =
+ disabledClassifications.stream().map(Object::toString).toList();
+ result.put(
+ legacyNotifications
+ ? NOTIFICATIONS_DISABLED_CATEGORIES
+ : NOTIFICATIONS_DISABLED_CLASSIFICATIONS,
+ value(list));
}
}
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java
index c10dc0e28e..258781b477 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java
@@ -27,11 +27,11 @@
import org.neo4j.driver.AccessMode;
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Query;
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.DatabaseName;
+import org.neo4j.driver.internal.GqlNotificationConfig;
public class RunWithMetadataMessage extends MessageWithMetadata {
public static final byte SIGNATURE = 0x10;
@@ -46,7 +46,8 @@ public static RunWithMetadataMessage autoCommitTxRunMessage(
AccessMode mode,
Set bookmarks,
String impersonatedUser,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
+ boolean legacyNotifications,
Logging logging) {
return autoCommitTxRunMessage(
query,
@@ -57,6 +58,7 @@ public static RunWithMetadataMessage autoCommitTxRunMessage(
bookmarks,
impersonatedUser,
notificationConfig,
+ legacyNotifications,
logging);
}
@@ -68,7 +70,8 @@ public static RunWithMetadataMessage autoCommitTxRunMessage(
AccessMode mode,
Set bookmarks,
String impersonatedUser,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
+ boolean legacyNotifications,
Logging logging) {
var metadata = buildMetadata(
txTimeout,
@@ -79,6 +82,7 @@ public static RunWithMetadataMessage autoCommitTxRunMessage(
impersonatedUser,
null,
notificationConfig,
+ legacyNotifications,
logging);
return new RunWithMetadataMessage(query.text(), query.parameters().asMap(ofValue()), metadata);
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilder.java
index 955d17c44f..2e2df5ed6a 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilder.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilder.java
@@ -25,9 +25,9 @@
import org.neo4j.driver.AccessMode;
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.DatabaseName;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.util.Iterables;
public class TransactionMetadataBuilder {
@@ -48,7 +48,8 @@ public static Map buildMetadata(
Set bookmarks,
String impersonatedUser,
String txType,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
+ boolean legacyNotifications,
Logging logging) {
var bookmarksPresent = !bookmarks.isEmpty();
var txTimeoutPresent = txTimeout != null;
@@ -97,7 +98,7 @@ public static Map buildMetadata(
if (txTypePresent) {
result.put(TX_TYPE_KEY, value(txType));
}
- MessageWithMetadata.appendNotificationConfig(result, notificationConfig);
+ MessageWithMetadata.appendNotificationConfig(result, notificationConfig, legacyNotifications);
databaseName.databaseName().ifPresent(name -> result.put(DATABASE_NAME_KEY, value(name)));
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java
index d0a16cb28f..06c778ed81 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java
@@ -34,7 +34,6 @@
import org.neo4j.driver.AuthToken;
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.Query;
import org.neo4j.driver.TransactionConfig;
import org.neo4j.driver.exceptions.Neo4jException;
@@ -42,6 +41,7 @@
import org.neo4j.driver.internal.BoltAgent;
import org.neo4j.driver.internal.DatabaseBookmark;
import org.neo4j.driver.internal.DatabaseName;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.async.UnmanagedTransaction;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.cursor.AsyncResultCursorOnlyFactory;
@@ -83,7 +83,7 @@ public void initializeChannel(
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
Clock clock) {
var exception = verifyNotificationConfigSupported(notificationConfig);
if (exception != null) {
@@ -100,7 +100,8 @@ public void initializeChannel(
((InternalAuthToken) authToken).toMap(),
routingContext.toMap(),
includeDateTimeUtcPatchInHello(),
- notificationConfig);
+ notificationConfig,
+ useLegacyNotifications());
} else {
message = new HelloMessage(
userAgent,
@@ -108,7 +109,8 @@ public void initializeChannel(
((InternalAuthToken) authToken).toMap(),
null,
includeDateTimeUtcPatchInHello(),
- notificationConfig);
+ notificationConfig,
+ useLegacyNotifications());
}
var handler = new HelloResponseHandler(channelInitializedPromise, clock);
@@ -134,7 +136,7 @@ public CompletionStage beginTransaction(
Set bookmarks,
TransactionConfig config,
String txType,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
Logging logging,
boolean flush) {
var exception = verifyNotificationConfigSupported(notificationConfig);
@@ -156,6 +158,7 @@ public CompletionStage beginTransaction(
connection.impersonatedUser(),
txType,
notificationConfig,
+ useLegacyNotifications(),
logging);
var handler = new BeginTxResponseHandler(beginTxFuture);
if (flush) {
@@ -188,7 +191,7 @@ public ResultCursorFactory runInAutoCommitTransaction(
Consumer bookmarkConsumer,
TransactionConfig config,
long fetchSize,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
Logging logging) {
var exception = verifyNotificationConfigSupported(notificationConfig);
if (exception != null) {
@@ -203,6 +206,7 @@ public ResultCursorFactory runInAutoCommitTransaction(
bookmarks,
connection.impersonatedUser(),
notificationConfig,
+ useLegacyNotifications(),
logging);
return buildResultCursorFactory(connection, query, bookmarkConsumer, null, runMessage, fetchSize);
}
@@ -246,13 +250,17 @@ protected boolean includeDateTimeUtcPatchInHello() {
return false;
}
- protected Neo4jException verifyNotificationConfigSupported(NotificationConfig notificationConfig) {
+ protected Neo4jException verifyNotificationConfigSupported(GqlNotificationConfig notificationConfig) {
Neo4jException exception = null;
- if (notificationConfig != null && !notificationConfig.equals(NotificationConfig.defaultConfig())) {
+ if (notificationConfig != null && !notificationConfig.equals(GqlNotificationConfig.defaultConfig())) {
exception = new UnsupportedFeatureException(String.format(
"Notification configuration is not supported on Bolt %s",
version().toString()));
}
return exception;
}
+
+ protected boolean useLegacyNotifications() {
+ return true;
+ }
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51.java
index e7fed32fee..11bb0b3125 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51.java
@@ -24,8 +24,8 @@
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import org.neo4j.driver.AuthToken;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.handlers.HelloV51ResponseHandler;
import org.neo4j.driver.internal.messaging.BoltProtocol;
@@ -45,7 +45,7 @@ public void initializeChannel(
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
Clock clock) {
var exception = verifyNotificationConfigSupported(notificationConfig);
if (exception != null) {
@@ -57,9 +57,16 @@ public void initializeChannel(
if (routingContext.isServerRoutingEnabled()) {
message = new HelloMessage(
- userAgent, null, Collections.emptyMap(), routingContext.toMap(), false, notificationConfig);
+ userAgent,
+ null,
+ Collections.emptyMap(),
+ routingContext.toMap(),
+ false,
+ notificationConfig,
+ useLegacyNotifications());
} else {
- message = new HelloMessage(userAgent, null, Collections.emptyMap(), null, false, notificationConfig);
+ message = new HelloMessage(
+ userAgent, null, Collections.emptyMap(), null, false, notificationConfig, useLegacyNotifications());
}
var helloFuture = new CompletableFuture();
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52.java
index 64ec22681c..68cc4e9790 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52.java
@@ -16,8 +16,8 @@
*/
package org.neo4j.driver.internal.messaging.v52;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.exceptions.Neo4jException;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.messaging.BoltProtocol;
import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
import org.neo4j.driver.internal.messaging.v51.BoltProtocolV51;
@@ -27,7 +27,7 @@ public class BoltProtocolV52 extends BoltProtocolV51 {
public static final BoltProtocol INSTANCE = new BoltProtocolV52();
@Override
- protected Neo4jException verifyNotificationConfigSupported(NotificationConfig notificationConfig) {
+ protected Neo4jException verifyNotificationConfigSupported(GqlNotificationConfig notificationConfig) {
return null;
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53.java
index 237d3b1b75..94bdb990ca 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53.java
@@ -24,8 +24,8 @@
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import org.neo4j.driver.AuthToken;
-import org.neo4j.driver.NotificationConfig;
import org.neo4j.driver.internal.BoltAgent;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.cluster.RoutingContext;
import org.neo4j.driver.internal.handlers.HelloV51ResponseHandler;
import org.neo4j.driver.internal.messaging.BoltProtocol;
@@ -44,7 +44,7 @@ public void initializeChannel(
AuthToken authToken,
RoutingContext routingContext,
ChannelPromise channelInitializedPromise,
- NotificationConfig notificationConfig,
+ GqlNotificationConfig notificationConfig,
Clock clock) {
var exception = verifyNotificationConfigSupported(notificationConfig);
if (exception != null) {
@@ -56,9 +56,22 @@ public void initializeChannel(
if (routingContext.isServerRoutingEnabled()) {
message = new HelloMessage(
- userAgent, boltAgent, Collections.emptyMap(), routingContext.toMap(), false, notificationConfig);
+ userAgent,
+ boltAgent,
+ Collections.emptyMap(),
+ routingContext.toMap(),
+ false,
+ notificationConfig,
+ useLegacyNotifications());
} else {
- message = new HelloMessage(userAgent, boltAgent, Collections.emptyMap(), null, false, notificationConfig);
+ message = new HelloMessage(
+ userAgent,
+ boltAgent,
+ Collections.emptyMap(),
+ null,
+ false,
+ notificationConfig,
+ useLegacyNotifications());
}
var helloFuture = new CompletableFuture();
diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v55/BoltProtocolV55.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v55/BoltProtocolV55.java
new file mode 100644
index 0000000000..529d34eb64
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v55/BoltProtocolV55.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver.internal.messaging.v55;
+
+import org.neo4j.driver.internal.messaging.BoltProtocol;
+import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
+import org.neo4j.driver.internal.messaging.v54.BoltProtocolV54;
+
+public class BoltProtocolV55 extends BoltProtocolV54 {
+ public static final BoltProtocolVersion VERSION = new BoltProtocolVersion(5, 5);
+ public static final BoltProtocol INSTANCE = new BoltProtocolV55();
+
+ @Override
+ public BoltProtocolVersion version() {
+ return VERSION;
+ }
+
+ @Override
+ protected boolean useLegacyNotifications() {
+ return false;
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlStatusObject.java b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlStatusObject.java
new file mode 100644
index 0000000000..97919c2c20
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlStatusObject.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver.internal.summary;
+
+import java.util.Map;
+import java.util.Objects;
+import org.neo4j.driver.Value;
+import org.neo4j.driver.Values;
+import org.neo4j.driver.summary.GqlStatusObject;
+
+public class InternalGqlStatusObject implements GqlStatusObject {
+ public static final GqlStatusObject SUCCESS = new InternalGqlStatusObject(
+ "00000",
+ "note: successful completion",
+ Map.ofEntries(
+ Map.entry("CURRENT_SCHEMA", Values.value("/")),
+ Map.entry("OPERATION", Values.value("")),
+ Map.entry("OPERATION_CODE", Values.value("0"))));
+ public static final GqlStatusObject NO_DATA = new InternalGqlStatusObject(
+ "02000",
+ "note: no data",
+ Map.ofEntries(
+ Map.entry("CURRENT_SCHEMA", Values.value("/")),
+ Map.entry("OPERATION", Values.value("")),
+ Map.entry("OPERATION_CODE", Values.value("0"))));
+ public static final GqlStatusObject NO_DATA_UNKNOWN = new InternalGqlStatusObject(
+ "02N42",
+ "note: no data - unknown subcondition",
+ Map.ofEntries(
+ Map.entry("CURRENT_SCHEMA", Values.value("/")),
+ Map.entry("OPERATION", Values.value("")),
+ Map.entry("OPERATION_CODE", Values.value("0"))));
+ public static final GqlStatusObject OMITTED_RESULT = new InternalGqlStatusObject(
+ "00001",
+ "note: successful completion - omitted result",
+ Map.ofEntries(
+ Map.entry("CURRENT_SCHEMA", Values.value("/")),
+ Map.entry("OPERATION", Values.value("")),
+ Map.entry("OPERATION_CODE", Values.value("0"))));
+
+ private final String gqlStatus;
+ private final String statusDescription;
+ private final Map diagnosticRecord;
+
+ public InternalGqlStatusObject(String gqlStatus, String statusDescription, Map diagnosticRecord) {
+ this.gqlStatus = Objects.requireNonNull(gqlStatus);
+ this.statusDescription = Objects.requireNonNull(statusDescription);
+ this.diagnosticRecord = Objects.requireNonNull(diagnosticRecord);
+ }
+
+ @Override
+ public String gqlStatus() {
+ return gqlStatus;
+ }
+
+ @Override
+ public String statusDescription() {
+ return statusDescription;
+ }
+
+ @Override
+ public Map diagnosticRecord() {
+ return diagnosticRecord;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ var that = (InternalGqlStatusObject) o;
+ return Objects.equals(gqlStatus, that.gqlStatus)
+ && Objects.equals(statusDescription, that.statusDescription)
+ && Objects.equals(diagnosticRecord, that.diagnosticRecord);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(gqlStatus, statusDescription, diagnosticRecord);
+ }
+
+ @Override
+ public String toString() {
+ return "InternalGqlStatusObject{" + "gqlStatus='"
+ + gqlStatus + '\'' + ", statusDescription='"
+ + statusDescription + '\'' + ", diagnosticRecord="
+ + diagnosticRecord + '}';
+ }
+}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalNotification.java b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalNotification.java
index a6fc565b4a..b48f93cb83 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalNotification.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalNotification.java
@@ -16,86 +16,85 @@
*/
package org.neo4j.driver.internal.summary;
-import static org.neo4j.driver.internal.value.NullValue.NULL;
-
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
-import java.util.function.Function;
import org.neo4j.driver.NotificationCategory;
+import org.neo4j.driver.NotificationClassification;
import org.neo4j.driver.NotificationSeverity;
import org.neo4j.driver.Value;
-import org.neo4j.driver.internal.InternalNotificationCategory;
-import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.summary.InputPosition;
import org.neo4j.driver.summary.Notification;
-public class InternalNotification implements Notification {
- public static final Function VALUE_TO_NOTIFICATION = value -> {
- var code = value.get("code").asString();
- var title = value.get("title").asString();
- var description = value.get("description").asString();
- var rawSeverityLevel =
- value.containsKey("severity") ? value.get("severity").asString() : null;
- var severityLevel =
- InternalNotificationSeverity.valueOf(rawSeverityLevel).orElse(null);
- var rawCategory = value.containsKey("category") ? value.get("category").asString() : null;
- var category = InternalNotificationCategory.valueOf(rawCategory).orElse(null);
-
- var posValue = value.get("position");
- InputPosition position = null;
- if (posValue != NULL) {
- position = new InternalInputPosition(
- posValue.get("offset").asInt(),
- posValue.get("line").asInt(),
- posValue.get("column").asInt());
- }
-
- return new InternalNotification(
- code, title, description, severityLevel, rawSeverityLevel, category, rawCategory, position);
- };
+public class InternalNotification extends InternalGqlStatusObject implements Notification {
+ public static Optional valueOf(String value) {
+ return Arrays.stream(NotificationClassification.values())
+ .filter(type -> type.toString().equals(value))
+ .findFirst()
+ .map(type -> switch (type) {
+ case HINT -> NotificationCategory.HINT;
+ case UNRECOGNIZED -> NotificationCategory.UNRECOGNIZED;
+ case UNSUPPORTED -> NotificationCategory.UNSUPPORTED;
+ case PERFORMANCE -> NotificationCategory.PERFORMANCE;
+ case DEPRECATION -> NotificationCategory.DEPRECATION;
+ case SECURITY -> NotificationCategory.SECURITY;
+ case TOPOLOGY -> NotificationCategory.TOPOLOGY;
+ case GENERIC -> NotificationCategory.GENERIC;
+ });
+ }
private final String code;
private final String title;
private final String description;
private final NotificationSeverity severityLevel;
private final String rawSeverityLevel;
- private final NotificationCategory category;
- private final String rawCategory;
+ private final NotificationClassification classification;
+ private final String rawClassification;
private final InputPosition position;
public InternalNotification(
+ String gqlStatus,
+ String statusDescription,
+ Map diagnosticRecord,
String code,
String title,
String description,
NotificationSeverity severityLevel,
String rawSeverityLevel,
- NotificationCategory category,
- String rawCategory,
+ NotificationClassification classification,
+ String rawClassification,
InputPosition position) {
- this.code = code;
+ super(gqlStatus, statusDescription, diagnosticRecord);
+ this.code = Objects.requireNonNull(code);
this.title = title;
this.description = description;
this.severityLevel = severityLevel;
this.rawSeverityLevel = rawSeverityLevel;
- this.category = category;
- this.rawCategory = rawCategory;
+ this.classification = classification;
+ this.rawClassification = rawClassification;
this.position = position;
}
+ @SuppressWarnings({"deprecation", "RedundantSuppression"})
@Override
public String code() {
return code;
}
+ @SuppressWarnings({"deprecation", "RedundantSuppression"})
@Override
public String title() {
return title;
}
+ @SuppressWarnings({"deprecation", "RedundantSuppression"})
@Override
public String description() {
return description;
}
+ @SuppressWarnings({"deprecation", "RedundantSuppression"})
@Override
public InputPosition position() {
return position;
@@ -111,21 +110,62 @@ public Optional rawSeverityLevel() {
return Optional.ofNullable(rawSeverityLevel);
}
+ @Override
+ public Optional classification() {
+ return Optional.ofNullable(classification);
+ }
+
+ @Override
+ public Optional rawClassification() {
+ return Optional.ofNullable(rawClassification);
+ }
+
@Override
public Optional category() {
- return Optional.ofNullable(category);
+ return Optional.ofNullable(classification);
}
@Override
public Optional rawCategory() {
- return Optional.ofNullable(rawCategory);
+ return Optional.ofNullable(rawClassification);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ var that = (InternalNotification) o;
+ return Objects.equals(code, that.code)
+ && Objects.equals(title, that.title)
+ && Objects.equals(description, that.description)
+ && Objects.equals(severityLevel, that.severityLevel)
+ && Objects.equals(rawSeverityLevel, that.rawSeverityLevel)
+ && classification == that.classification
+ && Objects.equals(rawClassification, that.rawClassification)
+ && Objects.equals(position, that.position);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ super.hashCode(),
+ code,
+ title,
+ description,
+ severityLevel,
+ rawSeverityLevel,
+ classification,
+ rawClassification,
+ position);
}
@Override
public String toString() {
var info = "code=" + code + ", title=" + title + ", description=" + description + ", severityLevel="
- + severityLevel + ", rawSeverityLevel=" + rawSeverityLevel + ", category=" + category + ", rawCategory="
- + rawCategory;
+ + severityLevel + ", rawSeverityLevel=" + rawSeverityLevel + ", classification=" + classification
+ + ", rawClassification="
+ + rawClassification;
return position == null ? info : info + ", position={" + position + "}";
}
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalResultSummary.java b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalResultSummary.java
index d82e65a1a7..96955167c6 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalResultSummary.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalResultSummary.java
@@ -16,12 +16,13 @@
*/
package org.neo4j.driver.internal.summary;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.neo4j.driver.Query;
import org.neo4j.driver.summary.DatabaseInfo;
+import org.neo4j.driver.summary.GqlStatusObject;
import org.neo4j.driver.summary.Notification;
import org.neo4j.driver.summary.Plan;
import org.neo4j.driver.summary.ProfiledPlan;
@@ -38,6 +39,7 @@ public class InternalResultSummary implements ResultSummary {
private final Plan plan;
private final ProfiledPlan profile;
private final List notifications;
+ private final Set gqlStatusObjects;
private final long resultAvailableAfter;
private final long resultConsumedAfter;
private final DatabaseInfo databaseInfo;
@@ -51,6 +53,7 @@ public InternalResultSummary(
Plan plan,
ProfiledPlan profile,
List notifications,
+ Set gqlStatusObjects,
long resultAvailableAfter,
long resultConsumedAfter) {
this.query = query;
@@ -60,7 +63,8 @@ public InternalResultSummary(
this.counters = counters;
this.plan = resolvePlan(plan, profile);
this.profile = profile;
- this.notifications = notifications;
+ this.notifications = Objects.requireNonNull(notifications);
+ this.gqlStatusObjects = Objects.requireNonNull(gqlStatusObjects);
this.resultAvailableAfter = resultAvailableAfter;
this.resultConsumedAfter = resultConsumedAfter;
}
@@ -102,7 +106,12 @@ public ProfiledPlan profile() {
@Override
public List notifications() {
- return notifications == null ? Collections.emptyList() : notifications;
+ return notifications;
+ }
+
+ @Override
+ public Set gqlStatusObjects() {
+ return gqlStatusObjects;
}
@Override
@@ -146,7 +155,7 @@ public boolean equals(Object o) {
&& Objects.equals(counters, that.counters)
&& Objects.equals(plan, that.plan)
&& Objects.equals(profile, that.profile)
- && Objects.equals(notifications, that.notifications);
+ && Objects.equals(gqlStatusObjects, that.gqlStatusObjects);
}
@Override
@@ -158,7 +167,7 @@ public int hashCode() {
counters,
plan,
profile,
- notifications,
+ gqlStatusObjects,
resultAvailableAfter,
resultConsumedAfter);
}
@@ -172,8 +181,8 @@ public String toString() {
+ queryType + ", counters="
+ counters + ", plan="
+ plan + ", profile="
- + profile + ", notifications="
- + notifications + ", resultAvailableAfter="
+ + profile + ", gqlStatusObjects="
+ + gqlStatusObjects + ", resultAvailableAfter="
+ resultAvailableAfter + ", resultConsumedAfter="
+ resultConsumedAfter + '}';
}
diff --git a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java
index 2efaeff17d..27ef64cfe2 100644
--- a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java
+++ b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java
@@ -16,24 +16,43 @@
*/
package org.neo4j.driver.internal.util;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.teeing;
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toUnmodifiableList;
import static org.neo4j.driver.internal.summary.InternalDatabaseInfo.DEFAULT_DATABASE_INFO;
import static org.neo4j.driver.internal.types.InternalTypeSystem.TYPE_SYSTEM;
+import static org.neo4j.driver.internal.value.NullValue.NULL;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.OptionalInt;
import java.util.Set;
+import java.util.TreeSet;
import java.util.function.Function;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
import org.neo4j.driver.Bookmark;
+import org.neo4j.driver.NotificationClassification;
+import org.neo4j.driver.NotificationSeverity;
import org.neo4j.driver.Query;
import org.neo4j.driver.Value;
+import org.neo4j.driver.Values;
import org.neo4j.driver.exceptions.ProtocolException;
import org.neo4j.driver.exceptions.UntrustedServerException;
import org.neo4j.driver.internal.DatabaseBookmark;
import org.neo4j.driver.internal.InternalBookmark;
+import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.summary.InternalDatabaseInfo;
+import org.neo4j.driver.internal.summary.InternalGqlStatusObject;
+import org.neo4j.driver.internal.summary.InternalInputPosition;
import org.neo4j.driver.internal.summary.InternalNotification;
import org.neo4j.driver.internal.summary.InternalPlan;
import org.neo4j.driver.internal.summary.InternalProfiledPlan;
@@ -41,18 +60,37 @@
import org.neo4j.driver.internal.summary.InternalServerInfo;
import org.neo4j.driver.internal.summary.InternalSummaryCounters;
import org.neo4j.driver.summary.DatabaseInfo;
+import org.neo4j.driver.summary.GqlStatusObject;
+import org.neo4j.driver.summary.InputPosition;
import org.neo4j.driver.summary.Notification;
import org.neo4j.driver.summary.Plan;
import org.neo4j.driver.summary.ProfiledPlan;
import org.neo4j.driver.summary.QueryType;
import org.neo4j.driver.summary.ResultSummary;
import org.neo4j.driver.summary.ServerInfo;
+import org.neo4j.driver.types.MapAccessor;
+import org.neo4j.driver.types.TypeSystem;
public class MetadataExtractor {
public static final int ABSENT_QUERY_ID = -1;
private static final String UNEXPECTED_TYPE_MSG_FMT = "Unexpected query type '%s', consider updating the driver";
private static final Function UNEXPECTED_TYPE_EXCEPTION_SUPPLIER =
(type) -> new ProtocolException(String.format(UNEXPECTED_TYPE_MSG_FMT, type));
+ private static final Comparator GQL_STATUS_OBJECT_COMPARATOR =
+ Comparator.comparingInt(gqlStatusObject -> {
+ var status = gqlStatusObject.gqlStatus();
+ if (status.startsWith("02")) {
+ return 0;
+ } else if (status.startsWith("01")) {
+ return 1;
+ } else if (status.startsWith("00")) {
+ return 2;
+ } else if (status.startsWith("03")) {
+ return 3;
+ } else {
+ return 4;
+ }
+ });
private final String resultAvailableAfterMetadataKey;
private final String resultConsumedAfterMetadataKey;
@@ -93,12 +131,44 @@ public long extractResultAvailableAfter(Map metadata) {
}
public ResultSummary extractSummary(
- Query query, Connection connection, long resultAvailableAfter, Map metadata) {
+ Query query,
+ Connection connection,
+ long resultAvailableAfter,
+ Map metadata,
+ boolean legacyNotifications,
+ GqlStatusObject gqlStatusObject) {
ServerInfo serverInfo = new InternalServerInfo(
connection.serverAgent(),
connection.serverAddress(),
connection.protocol().version());
var dbInfo = extractDatabaseInfo(metadata);
+ Set gqlStatusObjects;
+ List notifications;
+ if (legacyNotifications) {
+ var gqlStatusObjectsAndNotifications = extractGqlStatusObjectsFromNotifications(metadata)
+ .collect(teeing(
+ collectingAndThen(
+ toCollection(
+ () -> (Set) new TreeSet<>(GQL_STATUS_OBJECT_COMPARATOR)),
+ set -> {
+ if (gqlStatusObject != null) {
+ set.add(gqlStatusObject);
+ }
+ return unmodifiableSet(set);
+ }),
+ toUnmodifiableList(),
+ GqlStatusObjectsAndNotifications::new));
+ gqlStatusObjects = gqlStatusObjectsAndNotifications.gqlStatusObjects();
+ notifications = gqlStatusObjectsAndNotifications.notifications();
+ } else {
+ gqlStatusObjects = extractGqlStatusObjects(metadata)
+ .collect(collectingAndThen(
+ toCollection(() -> (Set) new LinkedHashSet()),
+ Collections::unmodifiableSet));
+ notifications = gqlStatusObjects.stream()
+ .flatMap(status -> status instanceof Notification ? Stream.of((Notification) status) : null)
+ .toList();
+ }
return new InternalResultSummary(
query,
serverInfo,
@@ -107,7 +177,8 @@ public ResultSummary extractSummary(
extractCounters(metadata),
extractPlan(metadata),
extractProfiledPlan(metadata),
- extractNotifications(metadata),
+ notifications,
+ gqlStatusObjects,
resultAvailableAfter,
extractResultConsumedAfter(metadata, resultConsumedAfterMetadataKey));
}
@@ -198,12 +269,180 @@ private static ProfiledPlan extractProfiledPlan(Map metadata) {
return null;
}
- private static List extractNotifications(Map metadata) {
+ private static Stream extractGqlStatusObjectsFromNotifications(Map metadata) {
var notificationsValue = metadata.get("notifications");
- if (notificationsValue != null) {
- return notificationsValue.asList(InternalNotification.VALUE_TO_NOTIFICATION);
+ if (notificationsValue != null && TypeSystem.getDefault().LIST().isTypeOf(notificationsValue)) {
+ var iterable = notificationsValue.values(value -> {
+ var code = value.get("code").asString();
+ var title = value.get("title").asString();
+ var description = value.get("description").asString();
+ var rawSeverityLevel =
+ value.containsKey("severity") ? value.get("severity").asString() : null;
+ var severityLevel =
+ InternalNotificationSeverity.valueOf(rawSeverityLevel).orElse(null);
+ var rawCategory =
+ value.containsKey("category") ? value.get("category").asString() : null;
+ var category = InternalNotification.valueOf(rawCategory).orElse(null);
+
+ var posValue = value.get("position");
+ InputPosition position = null;
+ if (posValue != NULL) {
+ position = new InternalInputPosition(
+ posValue.get("offset").asInt(),
+ posValue.get("line").asInt(),
+ posValue.get("column").asInt());
+ }
+
+ var gqlStatusCode = "03N42";
+ var gqlStatusDescription = description;
+ if (NotificationSeverity.WARNING.equals(severityLevel)) {
+ gqlStatusCode = "01N42";
+ if (gqlStatusDescription == null || "null".equals(gqlStatusDescription)) {
+ gqlStatusDescription = "warn: unknown warning";
+ }
+ } else {
+ if (gqlStatusDescription == null || "null".equals(gqlStatusDescription)) {
+ gqlStatusDescription = "info: unknown notification";
+ }
+ }
+
+ var diagnosticRecord = new HashMap(3);
+ diagnosticRecord.put("OPERATION", Values.value(""));
+ diagnosticRecord.put("OPERATION_CODE", Values.value("0"));
+ diagnosticRecord.put("CURRENT_SCHEMA", Values.value("/"));
+ if (rawSeverityLevel != null) {
+ diagnosticRecord.put("_severity", Values.value(rawSeverityLevel));
+ }
+ if (rawCategory != null) {
+ diagnosticRecord.put("_classification", Values.value(rawCategory));
+ }
+ if (position != null) {
+ diagnosticRecord.put(
+ "_position",
+ Values.value(Map.of(
+ "offset",
+ Values.value(position.offset()),
+ "line",
+ Values.value(position.line()),
+ "column",
+ Values.value(position.column()))));
+ }
+
+ return new InternalNotification(
+ gqlStatusCode,
+ gqlStatusDescription,
+ Collections.unmodifiableMap(diagnosticRecord),
+ code,
+ title,
+ description,
+ severityLevel,
+ rawSeverityLevel,
+ (NotificationClassification) category,
+ rawCategory,
+ position);
+ });
+ return StreamSupport.stream(iterable.spliterator(), false).map(Notification.class::cast);
+ } else {
+ return Stream.empty();
+ }
+ }
+
+ private static Stream extractGqlStatusObjects(Map metadata) {
+ var statuses = metadata.get("statuses");
+ if (statuses != null && TypeSystem.getDefault().LIST().isTypeOf(statuses)) {
+ var iterable = statuses.values(MetadataExtractor::extractGqlStatusObject);
+ return StreamSupport.stream(iterable.spliterator(), false);
+ } else {
+ return Stream.empty();
+ }
+ }
+
+ private static GqlStatusObject extractGqlStatusObject(Value value) {
+ var status = value.get("gql_status").asString();
+ var description = value.get("status_description").asString();
+ Map diagnosticRecord;
+ var diagnosticRecordValue = value.get("diagnostic_record");
+ if (diagnosticRecordValue != null && TypeSystem.getDefault().MAP().isTypeOf(diagnosticRecordValue)) {
+ var containsOperation = diagnosticRecordValue.containsKey("OPERATION");
+ var containsOperationCode = diagnosticRecordValue.containsKey("OPERATION_CODE");
+ var containsCurrentSchema = diagnosticRecordValue.containsKey("CURRENT_SCHEMA");
+ if (containsOperation && containsOperationCode && containsCurrentSchema) {
+ diagnosticRecord = diagnosticRecordValue.asMap(Values::value);
+ } else {
+ diagnosticRecord = new HashMap<>(diagnosticRecordValue.asMap(Values::value));
+ if (!containsOperation) {
+ diagnosticRecord.put("OPERATION", Values.value(""));
+ }
+ if (!containsOperationCode) {
+ diagnosticRecord.put("OPERATION_CODE", Values.value("0"));
+ }
+ if (!containsCurrentSchema) {
+ diagnosticRecord.put("CURRENT_SCHEMA", Values.value("/"));
+ }
+ diagnosticRecord = Collections.unmodifiableMap(diagnosticRecord);
+ }
+ } else {
+ diagnosticRecord = Map.ofEntries(
+ Map.entry("OPERATION", Values.value("")),
+ Map.entry("OPERATION_CODE", Values.value("0")),
+ Map.entry("CURRENT_SCHEMA", Values.value("/")));
+ }
+
+ var neo4jCode = value.get("neo4j_code").asString(null);
+
+ if (neo4jCode == null || neo4jCode.trim().isEmpty()) {
+ return new InternalGqlStatusObject(status, description, diagnosticRecord);
+ } else {
+ var title = value.get("title").asString();
+
+ var positionValue = diagnosticRecord.get("_position");
+ InputPosition position = null;
+ if (positionValue != null && TypeSystem.getDefault().MAP().isTypeOf(positionValue)) {
+ var offset = getAsInt(positionValue, "offset");
+ var line = getAsInt(positionValue, "line");
+ var column = getAsInt(positionValue, "column");
+ if (Stream.of(offset, line, column).allMatch(OptionalInt::isPresent)) {
+ position = new InternalInputPosition(offset.getAsInt(), line.getAsInt(), column.getAsInt());
+ }
+ }
+
+ var severityValue = diagnosticRecord.get("_severity");
+ String rawSeverity = null;
+ if (severityValue != null && TypeSystem.getDefault().STRING().isTypeOf(severityValue)) {
+ rawSeverity = severityValue.asString();
+ }
+ var severity = InternalNotificationSeverity.valueOf(rawSeverity).orElse(null);
+
+ var classificationValue = diagnosticRecord.get("_classification");
+ String rawClassification = null;
+ if (classificationValue != null && TypeSystem.getDefault().STRING().isTypeOf(classificationValue)) {
+ rawClassification = classificationValue.asString();
+ }
+ var classification = (NotificationClassification)
+ InternalNotification.valueOf(rawClassification).orElse(null);
+
+ return new InternalNotification(
+ status,
+ description,
+ diagnosticRecord,
+ neo4jCode,
+ title,
+ description,
+ severity,
+ rawSeverity,
+ classification,
+ rawClassification,
+ position);
+ }
+ }
+
+ private static OptionalInt getAsInt(MapAccessor mapAccessor, String key) {
+ var value = mapAccessor.get(key);
+ if (value != null && TypeSystem.getDefault().INTEGER().isTypeOf(value)) {
+ return OptionalInt.of(value.asInt());
+ } else {
+ return OptionalInt.empty();
}
- return Collections.emptyList();
}
private static long extractResultConsumedAfter(Map metadata, String key) {
@@ -222,4 +461,7 @@ public static Set extractBoltPatches(Map metadata) {
return Collections.emptySet();
}
}
+
+ private record GqlStatusObjectsAndNotifications(
+ Set gqlStatusObjects, List notifications) {}
}
diff --git a/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java b/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java
new file mode 100644
index 0000000000..272aeb4cfc
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [https://neo4j.com]
+ *
+ * Licensed 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.neo4j.driver.summary;
+
+import java.util.Map;
+import org.neo4j.driver.Value;
+import org.neo4j.driver.util.Preview;
+
+/**
+ * The GQL-status object as defined by the GQL standard.
+ * @since 5.22.0
+ * @see Notification Notification subtype of the GQL-status object
+ */
+@Preview(name = "GQL-status object")
+public interface GqlStatusObject {
+ /**
+ * Returns the GQLSTATUS as defined by the GQL standard.
+ * @return the GQLSTATUS value
+ */
+ String gqlStatus();
+
+ /**
+ * The GQLSTATUS description.
+ * @return the GQLSTATUS description
+ */
+ String statusDescription();
+
+ /**
+ * Returns the diagnostic record.
+ * @return the diagnostic record
+ */
+ Map diagnosticRecord();
+}
diff --git a/driver/src/main/java/org/neo4j/driver/summary/Notification.java b/driver/src/main/java/org/neo4j/driver/summary/Notification.java
index f3249eac0a..66c5a7ee61 100644
--- a/driver/src/main/java/org/neo4j/driver/summary/Notification.java
+++ b/driver/src/main/java/org/neo4j/driver/summary/Notification.java
@@ -18,8 +18,10 @@
import java.util.Optional;
import org.neo4j.driver.NotificationCategory;
+import org.neo4j.driver.NotificationClassification;
import org.neo4j.driver.NotificationSeverity;
import org.neo4j.driver.util.Immutable;
+import org.neo4j.driver.util.Preview;
/**
* Representation for notifications found when executing a query.
@@ -28,7 +30,7 @@
* @since 1.0
*/
@Immutable
-public interface Notification {
+public interface Notification extends GqlStatusObject {
/**
* Returns a notification code for the discovered issue.
* @return the notification code
@@ -38,6 +40,7 @@ public interface Notification {
/**
* Returns a short summary of the notification.
* @return the title of the notification.
+ * @see #gqlStatus()
*/
String title();
@@ -56,6 +59,19 @@ public interface Notification {
*/
InputPosition position();
+ /**
+ * Returns a position in the query where this notification points to.
+ *
+ * Not all notifications have a unique position to point to and in that case an empty {@link Optional} is returned.
+ *
+ * @return an {@link Optional} of the {@link InputPosition} if available or an empty {@link Optional} otherwise
+ * @since 5.22.0
+ */
+ @Preview(name = "GQL-status object")
+ default Optional inputPosition() {
+ return Optional.ofNullable(position());
+ }
+
/**
* The severity level of the notification.
*
@@ -68,25 +84,52 @@ default String severity() {
}
/**
- * Returns the severity level of the notification.
+ * Returns the severity level of the notification derived from the diagnostic record.
*
* @return the severity level of the notification
* @since 5.7
+ * @see #diagnosticRecord()
*/
default Optional severityLevel() {
return Optional.empty();
}
/**
- * Returns the raw severity level of the notification as a String returned by the server.
+ * Returns the raw severity level of the notification as a String value retrieved directly from the diagnostic
+ * record.
*
* @return the severity level of the notification
* @since 5.7
+ * @see #diagnosticRecord()
*/
default Optional rawSeverityLevel() {
return Optional.empty();
}
+ /**
+ * Returns {@link NotificationClassification} derived from the diagnostic record.
+ * @return an {@link Optional} of {@link NotificationClassification} or an empty {@link Optional} when the
+ * classification is either absent or unrecognised
+ * @since 5.22.0
+ * @see #diagnosticRecord()
+ */
+ @Preview(name = "GQL-status object")
+ default Optional classification() {
+ return Optional.empty();
+ }
+
+ /**
+ * Returns notification classification from the diagnostic record as a {@link String} value retrieved directly from
+ * the diagnostic record.
+ * @return an {@link Optional} of notification classification or an empty {@link Optional} when it is absent
+ * @since 5.22.0
+ * @see #diagnosticRecord()
+ */
+ @Preview(name = "GQL-status object")
+ default Optional rawClassification() {
+ return Optional.empty();
+ }
+
/**
* Returns the category of the notification.
*
diff --git a/driver/src/main/java/org/neo4j/driver/summary/ResultSummary.java b/driver/src/main/java/org/neo4j/driver/summary/ResultSummary.java
index f32d952112..fbe183e93d 100644
--- a/driver/src/main/java/org/neo4j/driver/summary/ResultSummary.java
+++ b/driver/src/main/java/org/neo4j/driver/summary/ResultSummary.java
@@ -17,9 +17,11 @@
package org.neo4j.driver.summary;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.neo4j.driver.Query;
import org.neo4j.driver.util.Immutable;
+import org.neo4j.driver.util.Preview;
/**
* The result summary of running a query. The result summary interface can be used to investigate
@@ -29,6 +31,7 @@
* The result summary is only available after all result records have been consumed.
*
* Keeping the result summary around does not influence the lifecycle of any associated session and/or transaction.
+ *
* @since 1.0
*/
@Immutable
@@ -82,12 +85,25 @@ public interface ResultSummary {
* in a client.
*
* Unlike failures or errors, notifications do not affect the execution of a query.
+ *
+ * Since {@link Notification} is a subtype of {@link GqlStatusObject}, the list of notifications is a subset of all
+ * GQL-status objects that are of {@link Notification} type. However, the order might be different.
*
* @return a list of notifications produced while executing the query. The list will be empty if no
* notifications produced while executing the query.
+ * @see #gqlStatusObjects()
*/
List notifications();
+ /**
+ * Returns a sequenced set of GQL-status objects resulting from the request execution.
+ *
+ * @return the sequenced set of GQL-status objects
+ * @since 5.22.0
+ */
+ @Preview(name = "GQL-status object")
+ Set gqlStatusObjects();
+
/**
* The time it took the server to make the result available for consumption.
*
@@ -106,12 +122,14 @@ public interface ResultSummary {
/**
* The basic information of the server where the result is obtained from
+ *
* @return basic information of the server where the result is obtained from
*/
ServerInfo server();
/**
* The basic information of the database where the result is obtained from
+ *
* @return the basic information of the database where the result is obtained from
*/
DatabaseInfo database();
diff --git a/driver/src/main/java/org/neo4j/driver/util/Preview.java b/driver/src/main/java/org/neo4j/driver/util/Preview.java
index 23f4a52629..3202775c5a 100644
--- a/driver/src/main/java/org/neo4j/driver/util/Preview.java
+++ b/driver/src/main/java/org/neo4j/driver/util/Preview.java
@@ -41,7 +41,7 @@
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Documented
-@Target({ElementType.TYPE, ElementType.METHOD})
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface Preview {
/**
* The feature name or a reference.
diff --git a/driver/src/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java
index 64773d17e7..2aed0268d6 100644
--- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java
+++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java
@@ -529,4 +529,38 @@ void shouldChangeTelemetryDisabled(boolean disabled) {
// Then
assertEquals(disabled, telemetryDisabled);
}
+
+ @Test
+ void shouldNotHaveMinimumNotificationSeverity() {
+ var config = Config.defaultConfig();
+
+ assertTrue(config.minimumNotificationSeverity().isEmpty());
+ }
+
+ @Test
+ void shouldSetMinimumNotificationSeverity() {
+ var config = Config.builder()
+ .withMinimumNotificationSeverity(NotificationSeverity.WARNING)
+ .build();
+
+ assertEquals(
+ NotificationSeverity.WARNING,
+ config.minimumNotificationSeverity().orElse(null));
+ }
+
+ @Test
+ void shouldNotHaveDisabledNotificationClassifications() {
+ var config = Config.defaultConfig();
+
+ assertTrue(config.disabledNotificationClassifications().isEmpty());
+ }
+
+ @Test
+ void shouldSetDisabledNotificationClassifications() {
+ var config = Config.builder()
+ .withDisabledNotificationClassifications(Set.of(NotificationClassification.SECURITY))
+ .build();
+
+ assertEquals(Set.of(NotificationClassification.SECURITY), config.disabledNotificationClassifications());
+ }
}
diff --git a/driver/src/test/java/org/neo4j/driver/SessionConfigTest.java b/driver/src/test/java/org/neo4j/driver/SessionConfigTest.java
index 5dc2ed6548..7808933c38 100644
--- a/driver/src/test/java/org/neo4j/driver/SessionConfigTest.java
+++ b/driver/src/test/java/org/neo4j/driver/SessionConfigTest.java
@@ -231,4 +231,38 @@ void shouldSerialize() throws Exception {
.disableCategories(Set.of(NotificationCategory.UNSUPPORTED, NotificationCategory.UNRECOGNIZED)),
config.notificationConfig());
}
+
+ @Test
+ void shouldNotHaveMinimumNotificationSeverity() {
+ var config = builder().build();
+
+ assertTrue(config.minimumNotificationSeverity().isEmpty());
+ }
+
+ @Test
+ void shouldSetMinimumNotificationSeverity() {
+ var config = Config.builder()
+ .withMinimumNotificationSeverity(NotificationSeverity.WARNING)
+ .build();
+
+ assertEquals(
+ NotificationSeverity.WARNING,
+ config.minimumNotificationSeverity().orElse(null));
+ }
+
+ @Test
+ void shouldNotHaveDisabledNotificationClassifications() {
+ var config = builder().build();
+
+ assertTrue(config.disabledNotificationClassifications().isEmpty());
+ }
+
+ @Test
+ void shouldSetDisabledNotificationClassifications() {
+ var config = Config.builder()
+ .withDisabledNotificationClassifications(Set.of(NotificationClassification.SECURITY))
+ .build();
+
+ assertEquals(Set.of(NotificationClassification.SECURITY), config.disabledNotificationClassifications());
+ }
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalNotificationCategoryTests.java b/driver/src/test/java/org/neo4j/driver/internal/InternalNotificationCategoryTests.java
deleted file mode 100644
index cb6df0bd5b..0000000000
--- a/driver/src/test/java/org/neo4j/driver/internal/InternalNotificationCategoryTests.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) "Neo4j"
- * Neo4j Sweden AB [https://neo4j.com]
- *
- * Licensed 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.neo4j.driver.internal;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.util.Arrays;
-import java.util.stream.Stream;
-import org.junit.jupiter.api.Named;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.neo4j.driver.NotificationCategory;
-
-class InternalNotificationCategoryTests {
-
- @ParameterizedTest
- @MethodSource("typeToCategoryMappings")
- void parseKnownCategories(TypeAndCategory typeAndCategory) {
- var parsedValue = InternalNotificationCategory.valueOf(typeAndCategory.type());
-
- assertTrue(parsedValue.isPresent());
- assertEquals(typeAndCategory.category(), parsedValue.get());
- }
-
- private static Stream typeToCategoryMappings() {
- return Arrays.stream(InternalNotificationCategory.Type.values()).map(type -> switch (type) {
- case HINT -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.HINT)));
- case UNRECOGNIZED -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.UNRECOGNIZED)));
- case UNSUPPORTED -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.UNSUPPORTED)));
- case PERFORMANCE -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.PERFORMANCE)));
- case DEPRECATION -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.DEPRECATION)));
- case SECURITY -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.SECURITY)));
- case TOPOLOGY -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.TOPOLOGY)));
- case GENERIC -> Arguments.of(
- Named.of(type.toString(), new TypeAndCategory(type.toString(), NotificationCategory.GENERIC)));
- });
- }
-
- private record TypeAndCategory(String type, NotificationCategory category) {}
-
- @Test
- void shouldReturnEmptyWhenNoMatchFound() {
- var unknownCategory = "something";
-
- var parsedValue = InternalNotificationCategory.valueOf(unknownCategory);
-
- System.out.println(parsedValue);
- }
-}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/AsyncResultCursorImplTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/AsyncResultCursorImplTest.java
index 300199fc88..1dc38f2de0 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/AsyncResultCursorImplTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/AsyncResultCursorImplTest.java
@@ -37,6 +37,7 @@
import static org.neo4j.driver.internal.util.Futures.failedFuture;
import static org.neo4j.driver.testutil.TestUtil.await;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -88,6 +89,7 @@ void shouldReturnSummary() {
null,
null,
emptyList(),
+ Collections.emptySet(),
42,
42);
when(pullAllHandler.consumeAsync()).thenReturn(completedFuture(summary));
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java
index a7dd582f35..e8513b72da 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java
@@ -30,7 +30,7 @@
import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3;
import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41;
import org.neo4j.driver.internal.messaging.v44.BoltProtocolV44;
-import org.neo4j.driver.internal.messaging.v54.BoltProtocolV54;
+import org.neo4j.driver.internal.messaging.v55.BoltProtocolV55;
class BoltProtocolUtilTest {
@Test
@@ -38,7 +38,7 @@ void shouldReturnHandshakeBuf() {
assertByteBufContains(
handshakeBuf(),
BOLT_MAGIC_PREAMBLE,
- (4 << 16) | BoltProtocolV54.VERSION.toInt(),
+ (5 << 16) | BoltProtocolV55.VERSION.toInt(),
(2 << 16) | BoltProtocolV44.VERSION.toInt(),
BoltProtocolV41.VERSION.toInt(),
BoltProtocolV3.VERSION.toInt());
@@ -46,7 +46,7 @@ void shouldReturnHandshakeBuf() {
@Test
void shouldReturnHandshakeString() {
- assertEquals("[0x6060b017, 263173, 132100, 260, 3]", handshakeString());
+ assertEquals("[0x6060b017, 328965, 132100, 260, 3]", handshakeString());
}
@Test
diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListenerTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListenerTest.java
index 8d093dd279..116984d584 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListenerTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListenerTest.java
@@ -93,7 +93,7 @@ void shouldWriteInitializationMessageInBoltV3WhenHandshakeCompleted() {
given(authContext.getAuthTokenManager()).willReturn(authTokenManager);
setAuthContext(channel, authContext);
testWritingOfInitializationMessage(
- new HelloMessage(USER_AGENT, null, authToken().toMap(), Collections.emptyMap(), false, null));
+ new HelloMessage(USER_AGENT, null, authToken().toMap(), Collections.emptyMap(), false, null, true));
then(authContext).should().initiateAuth(authToken);
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/SessionPullResponseCompletionListenerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/SessionPullResponseCompletionListenerTest.java
index 66eb4441d5..bfb0e4fef3 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/SessionPullResponseCompletionListenerTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/SessionPullResponseCompletionListenerTest.java
@@ -20,6 +20,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -33,6 +34,7 @@
import org.neo4j.driver.internal.handlers.SessionPullResponseCompletionListener;
import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4;
import org.neo4j.driver.internal.spi.Connection;
+import org.neo4j.driver.internal.util.QueryKeys;
import org.neo4j.driver.summary.ResultSummary;
class SessionPullResponseCompletionListenerTest extends BasicPullResponseHandlerTestBase {
@@ -95,6 +97,7 @@ private static BasicPullResponseHandler newSessionResponseHandler(
Consumer bookmarkConsumer,
BasicPullResponseHandler.State state) {
var runHandler = mock(RunResponseHandler.class);
+ given(runHandler.queryKeys()).willReturn(new QueryKeys(Collections.emptyList()));
var listener = new SessionPullResponseCompletionListener(conn, bookmarkConsumer);
var handler = new BasicPullResponseHandler(
mock(Query.class), runHandler, conn, BoltProtocolV4.METADATA_EXTRACTOR, listener);
diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/TransactionPullResponseCompletionListenerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/TransactionPullResponseCompletionListenerTest.java
index 862a559558..9be536c25d 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/TransactionPullResponseCompletionListenerTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/pulln/TransactionPullResponseCompletionListenerTest.java
@@ -20,6 +20,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,6 +34,7 @@
import org.neo4j.driver.internal.handlers.TransactionPullResponseCompletionListener;
import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4;
import org.neo4j.driver.internal.spi.Connection;
+import org.neo4j.driver.internal.util.QueryKeys;
import org.neo4j.driver.summary.ResultSummary;
public class TransactionPullResponseCompletionListenerTest extends BasicPullResponseHandlerTestBase {
@@ -96,6 +98,7 @@ private static BasicPullResponseHandler newTxResponseHandler(
UnmanagedTransaction tx,
BasicPullResponseHandler.State state) {
var runHandler = mock(RunResponseHandler.class);
+ given(runHandler.queryKeys()).willReturn(new QueryKeys(Collections.emptyList()));
var listener = new TransactionPullResponseCompletionListener(tx);
var handler = new BasicPullResponseHandler(
mock(Query.class), runHandler, conn, BoltProtocolV4.METADATA_EXTRACTOR, listener);
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java
index 551e78afee..00a4c573fc 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java
@@ -68,6 +68,7 @@ void shouldEncodeBeginMessage(AccessMode mode, String impersonatedUser, String t
impersonatedUser,
txType,
null,
+ true,
Logging.none()),
packer);
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java
index 91736c1af1..74db38ddc2 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java
@@ -40,7 +40,7 @@ void shouldEncodeHelloMessage() throws Exception {
authToken.put("username", value("bob"));
authToken.put("password", value("secret"));
- encoder.encode(new HelloMessage("MyDriver", BoltAgentUtil.VALUE, authToken, null, false, null), packer);
+ encoder.encode(new HelloMessage("MyDriver", BoltAgentUtil.VALUE, authToken, null, false, null, true), packer);
var order = inOrder(packer);
order.verify(packer).packStructHeader(1, HelloMessage.SIGNATURE);
@@ -61,7 +61,8 @@ void shouldEncodeHelloMessageWithRoutingContext() throws Exception {
routingContext.put("policy", "eu-fast");
encoder.encode(
- new HelloMessage("MyDriver", BoltAgentUtil.VALUE, authToken, routingContext, false, null), packer);
+ new HelloMessage("MyDriver", BoltAgentUtil.VALUE, authToken, routingContext, false, null, true),
+ packer);
var order = inOrder(packer);
order.verify(packer).packStructHeader(1, HelloMessage.SIGNATURE);
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java
index 3a321d5406..637f732458 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java
@@ -64,7 +64,16 @@ void shouldEncodeRunWithMetadataMessage(AccessMode mode) throws Exception {
var query = new Query("RETURN $answer", value(params));
encoder.encode(
autoCommitTxRunMessage(
- query, txTimeout, txMetadata, defaultDatabase(), mode, bookmarks, null, null, Logging.none()),
+ query,
+ txTimeout,
+ txMetadata,
+ defaultDatabase(),
+ mode,
+ bookmarks,
+ null,
+ null,
+ true,
+ Logging.none()),
packer);
var order = inOrder(packer);
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java
index c7421051f9..0bed53c98b 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java
@@ -39,8 +39,8 @@ void shouldHaveCorrectMetadata() {
authToken.put("user", value("Alice"));
authToken.put("credentials", value("SecretPassword"));
- var message =
- new HelloMessage("MyDriver/1.0.2", BoltAgentUtil.VALUE, authToken, Collections.emptyMap(), false, null);
+ var message = new HelloMessage(
+ "MyDriver/1.0.2", BoltAgentUtil.VALUE, authToken, Collections.emptyMap(), false, null, true);
Map expectedMetadata = new HashMap<>(authToken);
expectedMetadata.put("user_agent", value("MyDriver/1.0.2"));
@@ -59,7 +59,8 @@ void shouldHaveCorrectRoutingContext() {
routingContext.put("region", "China");
routingContext.put("speed", "Slow");
- var message = new HelloMessage("MyDriver/1.0.2", BoltAgentUtil.VALUE, authToken, routingContext, false, null);
+ var message =
+ new HelloMessage("MyDriver/1.0.2", BoltAgentUtil.VALUE, authToken, routingContext, false, null, true);
Map expectedMetadata = new HashMap<>(authToken);
expectedMetadata.put("user_agent", value("MyDriver/1.0.2"));
@@ -74,8 +75,8 @@ void shouldNotExposeCredentialsInToString() {
authToken.put(PRINCIPAL_KEY, value("Alice"));
authToken.put(CREDENTIALS_KEY, value("SecretPassword"));
- var message =
- new HelloMessage("MyDriver/1.0.2", BoltAgentUtil.VALUE, authToken, Collections.emptyMap(), false, null);
+ var message = new HelloMessage(
+ "MyDriver/1.0.2", BoltAgentUtil.VALUE, authToken, Collections.emptyMap(), false, null, true);
assertThat(message.toString(), not(containsString("SecretPassword")));
}
@@ -86,7 +87,7 @@ void shouldAcceptNullBoltAgent() {
authToken.put("user", value("Alice"));
authToken.put("credentials", value("SecretPassword"));
- var message = new HelloMessage("MyDriver/1.0.2", null, authToken, Collections.emptyMap(), false, null);
+ var message = new HelloMessage("MyDriver/1.0.2", null, authToken, Collections.emptyMap(), false, null, true);
var expectedMetadata = new HashMap<>(authToken);
expectedMetadata.put("user_agent", value("MyDriver/1.0.2"));
@@ -101,7 +102,8 @@ void shouldAcceptDetailedBoltAgent() {
authToken.put("credentials", value("SecretPassword"));
var boltAgent = new BoltAgent("1", "2", "3", "4");
- var message = new HelloMessage("MyDriver/1.0.2", boltAgent, authToken, Collections.emptyMap(), false, null);
+ var message =
+ new HelloMessage("MyDriver/1.0.2", boltAgent, authToken, Collections.emptyMap(), false, null, true);
var expectedMetadata = new HashMap<>(authToken);
expectedMetadata.put("user_agent", value("MyDriver/1.0.2"));
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilderTest.java
index 1323943f29..86a5806e15 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilderTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/TransactionMetadataBuilderTest.java
@@ -45,10 +45,10 @@
import org.neo4j.driver.Bookmark;
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
-import org.neo4j.driver.NotificationCategory;
-import org.neo4j.driver.NotificationConfig;
+import org.neo4j.driver.NotificationClassification;
import org.neo4j.driver.NotificationSeverity;
import org.neo4j.driver.Value;
+import org.neo4j.driver.internal.GqlNotificationConfig;
import org.neo4j.driver.internal.InternalBookmark;
public class TransactionMetadataBuilderTest {
@@ -66,7 +66,7 @@ void shouldHaveCorrectMetadata(AccessMode mode) {
var txTimeout = Duration.ofSeconds(7);
var metadata = buildMetadata(
- txTimeout, txMetadata, defaultDatabase(), mode, bookmarks, null, null, null, Logging.none());
+ txTimeout, txMetadata, defaultDatabase(), mode, bookmarks, null, null, null, true, Logging.none());
Map expectedMetadata = new HashMap<>();
expectedMetadata.put(
@@ -94,7 +94,16 @@ void shouldHaveCorrectMetadataForDatabaseName(String databaseName) {
var txTimeout = Duration.ofSeconds(7);
var metadata = buildMetadata(
- txTimeout, txMetadata, database(databaseName), WRITE, bookmarks, null, null, null, Logging.none());
+ txTimeout,
+ txMetadata,
+ database(databaseName),
+ WRITE,
+ bookmarks,
+ null,
+ null,
+ null,
+ true,
+ Logging.none());
Map expectedMetadata = new HashMap<>();
expectedMetadata.put(
@@ -109,12 +118,12 @@ void shouldHaveCorrectMetadataForDatabaseName(String databaseName) {
@Test
void shouldNotHaveMetadataForDatabaseNameWhenIsNull() {
var metadata = buildMetadata(
- null, null, defaultDatabase(), WRITE, Collections.emptySet(), null, null, null, Logging.none());
+ null, null, defaultDatabase(), WRITE, Collections.emptySet(), null, null, null, true, Logging.none());
assertTrue(metadata.isEmpty());
}
@Test
- void shouldIncludeNotificationConfig() {
+ void shouldIncludeGqlNotificationConfig() {
var metadata = buildMetadata(
null,
null,
@@ -123,9 +132,8 @@ void shouldIncludeNotificationConfig() {
Collections.emptySet(),
null,
null,
- NotificationConfig.defaultConfig()
- .enableMinimumSeverity(NotificationSeverity.WARNING)
- .disableCategories(Set.of(NotificationCategory.UNSUPPORTED)),
+ new GqlNotificationConfig(NotificationSeverity.WARNING, Set.of(NotificationClassification.UNSUPPORTED)),
+ true,
Logging.none());
var expectedMetadata = new HashMap();
@@ -152,6 +160,7 @@ void shouldRoundUpFractionalTimeoutAndLog(long nanosValue) {
null,
null,
null,
+ true,
logging);
// then
@@ -184,6 +193,7 @@ void shouldNotLogWhenRoundingDoesNotHappen() {
null,
null,
null,
+ true,
logging);
// then
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3Test.java
index 65fb78c6ab..09080adbc5 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3Test.java
@@ -207,6 +207,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -230,6 +231,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -252,6 +254,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -267,7 +270,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -583,7 +586,7 @@ private static ResponseHandlers verifyRunInvoked(
RunWithMetadataMessage expectedMessage;
if (session) {
expectedMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, defaultDatabase(), mode, bookmarks, null, null, Logging.none());
+ QUERY, config, defaultDatabase(), mode, bookmarks, null, null, true, Logging.none());
} else {
expectedMessage = RunWithMetadataMessage.unmanagedTxRunMessage(QUERY);
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java
index 3b7bc3191e..16ccc29162 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java
@@ -102,7 +102,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -113,6 +114,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -123,6 +125,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -135,6 +138,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -145,6 +149,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
PULL_ALL,
@@ -161,6 +166,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -171,6 +177,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/BoltProtocolV4Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/BoltProtocolV4Test.java
index 52a6ba121e..c199e067ad 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/BoltProtocolV4Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/BoltProtocolV4Test.java
@@ -200,6 +200,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -223,6 +224,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -245,6 +247,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -260,7 +263,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -581,7 +584,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmarks, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmarks, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -601,8 +604,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/MessageWriterV4Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/MessageWriterV4Test.java
index 5e7660192f..017bba3aa8 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/MessageWriterV4Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v4/MessageWriterV4Test.java
@@ -110,7 +110,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -121,6 +122,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -131,6 +133,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -144,6 +147,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -154,6 +158,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -167,6 +172,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -177,6 +183,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/BoltProtocolV41Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/BoltProtocolV41Test.java
index b0e5d2ff09..f81a02e6d5 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/BoltProtocolV41Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/BoltProtocolV41Test.java
@@ -205,6 +205,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -228,6 +229,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -250,6 +252,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -265,7 +268,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -577,7 +580,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmarks, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmarks, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -597,8 +600,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/MessageWriterV41Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/MessageWriterV41Test.java
index 6d42281b22..7eb8ce186d 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/MessageWriterV41Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v41/MessageWriterV41Test.java
@@ -109,7 +109,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -120,6 +121,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -130,6 +132,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -143,6 +146,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -153,6 +157,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -166,6 +171,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -176,6 +182,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java
index 3ad79fb776..93a9617e1c 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java
@@ -205,6 +205,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -228,6 +229,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -250,6 +252,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -265,7 +268,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -578,7 +581,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmarks, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmarks, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -598,8 +601,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/MessageWriterV42Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/MessageWriterV42Test.java
index 51034a07a9..656d7c8c05 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/MessageWriterV42Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/MessageWriterV42Test.java
@@ -109,7 +109,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -120,6 +121,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -130,6 +132,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -143,6 +146,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -153,6 +157,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -166,6 +171,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -176,6 +182,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/BoltProtocolV43Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/BoltProtocolV43Test.java
index b12f3f3dc6..e078e7352a 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/BoltProtocolV43Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/BoltProtocolV43Test.java
@@ -204,6 +204,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -227,6 +228,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -249,6 +251,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -264,7 +267,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -580,7 +583,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmarks, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmarks, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -600,8 +603,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/MessageWriterV43Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/MessageWriterV43Test.java
index d9a852640a..d8e13aaab6 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/MessageWriterV43Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v43/MessageWriterV43Test.java
@@ -114,7 +114,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -125,6 +126,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -135,6 +137,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -148,6 +151,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -158,6 +162,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -171,6 +176,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -181,6 +187,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))),
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/BoltProtocolV44Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/BoltProtocolV44Test.java
index 83aef37628..62e7c1cb45 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/BoltProtocolV44Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/BoltProtocolV44Test.java
@@ -204,6 +204,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -227,6 +228,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -249,6 +251,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -264,7 +267,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -578,7 +581,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmarks, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmarks, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -598,8 +601,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/MessageWriterV44Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/MessageWriterV44Test.java
index 7096fc98ee..4ba729c892 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/MessageWriterV44Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v44/MessageWriterV44Test.java
@@ -114,7 +114,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -125,6 +126,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -135,6 +137,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -148,6 +151,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -158,6 +162,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -171,6 +176,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -181,6 +187,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))),
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/BoltProtocolV5Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/BoltProtocolV5Test.java
index be6f6874c8..e6bf61f501 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/BoltProtocolV5Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/BoltProtocolV5Test.java
@@ -204,6 +204,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -227,6 +228,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -249,6 +251,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -264,7 +267,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -578,7 +581,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmark, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmark, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -598,8 +601,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/MessageWriterV5Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/MessageWriterV5Test.java
index e2f871f929..a472cf7fb5 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/MessageWriterV5Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v5/MessageWriterV5Test.java
@@ -114,7 +114,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -125,6 +126,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -135,6 +137,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -148,6 +151,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -158,6 +162,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -171,6 +176,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -181,6 +187,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))),
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51Test.java
index d34fbdea40..72732704f7 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51Test.java
@@ -176,6 +176,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -199,6 +200,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -221,6 +223,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -236,7 +239,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -550,7 +553,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmark, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmark, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -570,8 +573,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/MessageWriterV51Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/MessageWriterV51Test.java
index 75f96116ed..385e0a4ecf 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/MessageWriterV51Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v51/MessageWriterV51Test.java
@@ -109,7 +109,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -120,6 +121,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -130,6 +132,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -143,6 +146,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -153,6 +157,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -166,6 +171,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -176,6 +182,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))),
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52Test.java
index 35b54f5dde..6f7cf193b4 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v52/BoltProtocolV52Test.java
@@ -177,6 +177,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -200,6 +201,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -222,6 +224,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -237,7 +240,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -551,7 +554,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmark, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmark, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -571,8 +574,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53Test.java
index 46e1dd7afa..73fb0e5a86 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v53/BoltProtocolV53Test.java
@@ -184,6 +184,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -207,6 +208,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -229,6 +231,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -244,7 +247,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -558,7 +561,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmark, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmark, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -578,8 +581,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/BoltProtocolV54Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/BoltProtocolV54Test.java
index 14035d6e30..4655cc67ee 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/BoltProtocolV54Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/BoltProtocolV54Test.java
@@ -185,6 +185,7 @@ void shouldBeginTransactionWithoutBookmark() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -208,6 +209,7 @@ void shouldBeginTransactionWithBookmarks() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -230,6 +232,7 @@ void shouldBeginTransactionWithConfig() {
null,
null,
null,
+ true,
Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
@@ -245,7 +248,7 @@ void shouldBeginTransactionWithBookmarksAndConfig() {
verify(connection)
.writeAndFlush(
eq(new BeginMessage(
- bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, Logging.none())),
+ bookmarks, txConfig, defaultDatabase(), WRITE, null, null, null, true, Logging.none())),
any(BeginTxResponseHandler.class));
assertNull(await(stage));
}
@@ -567,7 +570,7 @@ private ResponseHandler verifySessionRunInvoked(
AccessMode mode,
DatabaseName databaseName) {
var runMessage = RunWithMetadataMessage.autoCommitTxRunMessage(
- QUERY, config, databaseName, mode, bookmark, null, null, Logging.none());
+ QUERY, config, databaseName, mode, bookmark, null, null, true, Logging.none());
return verifyRunInvoked(connection, runMessage);
}
@@ -587,8 +590,8 @@ private ResponseHandler verifyRunInvoked(Connection connection, RunWithMetadataM
private void verifyBeginInvoked(
Connection connection, Set bookmarks, TransactionConfig config, DatabaseName databaseName) {
var beginHandlerCaptor = ArgumentCaptor.forClass(ResponseHandler.class);
- var beginMessage =
- new BeginMessage(bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, Logging.none());
+ var beginMessage = new BeginMessage(
+ bookmarks, config, databaseName, AccessMode.WRITE, null, null, null, true, Logging.none());
verify(connection).writeAndFlush(eq(beginMessage), beginHandlerCaptor.capture());
assertThat(beginHandlerCaptor.getValue(), instanceOf(BeginTxResponseHandler.class));
}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/MessageWriterV54Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/MessageWriterV54Test.java
index c2fa17bcc0..129932b480 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/MessageWriterV54Test.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v54/MessageWriterV54Test.java
@@ -110,7 +110,8 @@ protected Stream supportedMessages() {
((InternalAuthToken) basic("neo4j", "neo4j")).toMap(),
Collections.emptyMap(),
false,
- null),
+ null,
+ true),
GOODBYE,
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -121,6 +122,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
new BeginMessage(
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx123")),
@@ -131,6 +133,7 @@ protected Stream supportedMessages() {
null,
null,
null,
+ true,
Logging.none()),
COMMIT,
ROLLBACK,
@@ -144,6 +147,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN 1"),
@@ -154,6 +158,7 @@ protected Stream supportedMessages() {
Collections.singleton(InternalBookmark.parse("neo4j:bookmark:v1:tx1")),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN 1")),
@@ -167,6 +172,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
autoCommitTxRunMessage(
new Query("RETURN $x", singletonMap("x", value(ZonedDateTime.now()))),
@@ -177,6 +183,7 @@ protected Stream supportedMessages() {
Collections.emptySet(),
null,
null,
+ true,
Logging.none()),
unmanagedTxRunMessage(new Query("RETURN $x", singletonMap("x", point(42, 1, 2, 3)))),
diff --git a/driver/src/test/java/org/neo4j/driver/internal/reactive/util/ListBasedPullHandler.java b/driver/src/test/java/org/neo4j/driver/internal/reactive/util/ListBasedPullHandler.java
index 755734af74..08d214a188 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/reactive/util/ListBasedPullHandler.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/reactive/util/ListBasedPullHandler.java
@@ -20,10 +20,12 @@
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.util.Collections;
import java.util.List;
import org.neo4j.driver.Query;
import org.neo4j.driver.Record;
@@ -31,6 +33,7 @@
import org.neo4j.driver.internal.handlers.PullResponseCompletionListener;
import org.neo4j.driver.internal.handlers.RunResponseHandler;
import org.neo4j.driver.internal.handlers.pulln.BasicPullResponseHandler;
+import org.neo4j.driver.internal.messaging.v5.BoltProtocolV5;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.util.MetadataExtractor;
import org.neo4j.driver.internal.util.QueryKeys;
@@ -63,12 +66,16 @@ private ListBasedPullHandler(List list, Throwable error) {
mock(PullResponseCompletionListener.class));
this.list = list;
this.error = error;
- when(super.metadataExtractor.extractSummary(any(Query.class), any(Connection.class), anyLong(), any()))
+ when(super.metadataExtractor.extractSummary(
+ any(Query.class), any(Connection.class), anyLong(), any(), anyBoolean(), any()))
.thenReturn(mock(ResultSummary.class));
if (list.size() > 1) {
var record = list.get(0);
when(super.runResponseHandler.queryKeys()).thenReturn(new QueryKeys(record.keys()));
+ } else {
+ when(super.runResponseHandler.queryKeys()).thenReturn(new QueryKeys(Collections.emptyList()));
}
+ when(super.connection.protocol()).thenReturn(BoltProtocolV5.INSTANCE);
}
@Override
diff --git a/driver/src/test/java/org/neo4j/driver/internal/summary/InternalNotificationTest.java b/driver/src/test/java/org/neo4j/driver/internal/summary/InternalNotificationTest.java
deleted file mode 100644
index 6c753203d0..0000000000
--- a/driver/src/test/java/org/neo4j/driver/internal/summary/InternalNotificationTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) "Neo4j"
- * Neo4j Sweden AB [https://neo4j.com]
- *
- * Licensed 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.neo4j.driver.internal.summary;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.nullValue;
-
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.jupiter.api.Test;
-import org.neo4j.driver.NotificationCategory;
-import org.neo4j.driver.NotificationSeverity;
-import org.neo4j.driver.Value;
-import org.neo4j.driver.internal.value.IntegerValue;
-import org.neo4j.driver.internal.value.MapValue;
-import org.neo4j.driver.internal.value.StringValue;
-
-class InternalNotificationTest {
- @Test
- @SuppressWarnings({"deprecation", "OptionalGetWithoutIsPresent"})
- void shouldHandleNotificationWithPosition() {
- // GIVEN
- Map map = new HashMap<>();
- map.put("description", new StringValue("A description"));
- map.put("code", new StringValue("Neo.DummyNotification"));
- map.put("title", new StringValue("A title"));
- map.put("severity", new StringValue("WARNING"));
- map.put("category", new StringValue("DEPRECATION"));
- Map position = new HashMap<>();
- position.put("offset", new IntegerValue(0));
- position.put("column", new IntegerValue(1));
- position.put("line", new IntegerValue(2));
- map.put("position", new MapValue(position));
- Value value = new MapValue(map);
-
- // WHEN
- var notification = InternalNotification.VALUE_TO_NOTIFICATION.apply(value);
-
- // THEN
- assertThat(notification.description(), equalTo("A description"));
- assertThat(notification.code(), equalTo("Neo.DummyNotification"));
- assertThat(notification.title(), equalTo("A title"));
- assertThat(notification.severity(), equalTo("WARNING"));
- assertThat(notification.severityLevel().get(), equalTo(NotificationSeverity.WARNING));
- assertThat(notification.rawSeverityLevel().get(), equalTo("WARNING"));
- assertThat(notification.category().get(), equalTo(NotificationCategory.DEPRECATION));
- assertThat(notification.rawCategory().get(), equalTo("DEPRECATION"));
- var pos = notification.position();
- assertThat(pos.offset(), equalTo(0));
- assertThat(pos.column(), equalTo(1));
- assertThat(pos.line(), equalTo(2));
- }
-
- @Test
- void shouldHandleNotificationWithoutPosition() {
- // GIVEN
- Map map = new HashMap<>();
- map.put("description", new StringValue("A description"));
- map.put("code", new StringValue("Neo.DummyNotification"));
- map.put("title", new StringValue("A title"));
- Value value = new MapValue(map);
-
- // WHEN
- var notification = InternalNotification.VALUE_TO_NOTIFICATION.apply(value);
-
- // THEN
- assertThat(notification.description(), equalTo("A description"));
- assertThat(notification.code(), equalTo("Neo.DummyNotification"));
- assertThat(notification.title(), equalTo("A title"));
- assertThat(notification.position(), nullValue());
- }
-}
diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java
index 8a7f5bf714..115f660a8c 100644
--- a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java
+++ b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java
@@ -56,6 +56,7 @@
import org.neo4j.driver.internal.messaging.v43.BoltProtocolV43;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.summary.InternalInputPosition;
+import org.neo4j.driver.summary.Notification;
import org.neo4j.driver.summary.ResultSummary;
class MetadataExtractorTest {
@@ -104,7 +105,7 @@ void shouldBuildResultSummaryWithQuery() {
var query =
new Query("UNWIND range(10, 100) AS x CREATE (:Node {name: $name, x: x})", singletonMap("name", "Apa"));
- var summary = extractor.extractSummary(query, connectionMock(), 42, emptyMap());
+ var summary = extractor.extractSummary(query, connectionMock(), 42, emptyMap(), true, null);
assertEquals(query, summary.query());
}
@@ -113,7 +114,7 @@ void shouldBuildResultSummaryWithQuery() {
void shouldBuildResultSummaryWithServerAddress() {
var connection = connectionMock(new BoltServerAddress("server:42"));
- var summary = extractor.extractSummary(query(), connection, 42, emptyMap());
+ var summary = extractor.extractSummary(query(), connection, 42, emptyMap(), true, null);
assertEquals("server:42", summary.server().address());
}
@@ -145,7 +146,7 @@ void shouldBuildResultSummaryWithCounters() {
var metadata = singletonMap("stats", stats);
- var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata);
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
assertEquals(42, summary.counters().nodesCreated());
assertEquals(4242, summary.counters().nodesDeleted());
@@ -162,24 +163,27 @@ void shouldBuildResultSummaryWithCounters() {
@Test
void shouldBuildResultSummaryWithoutCounters() {
- var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap());
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap(), true, null);
assertEquals(EMPTY_STATS, summary.counters());
}
@Test
void shouldBuildResultSummaryWithPlan() {
var plan = value(parameters(
- "operatorType", "Projection",
- "args", parameters("n", 42),
- "identifiers", values("a", "b"),
+ "operatorType",
+ "Projection",
+ "args",
+ parameters("n", 42),
+ "identifiers",
+ values("a", "b"),
"children",
- values(parameters(
- "operatorType", "AllNodeScan",
- "args", parameters("x", 4242),
- "identifiers", values("n", "t", "f")))));
+ values(parameters(
+ "operatorType", "AllNodeScan",
+ "args", parameters("x", 4242),
+ "identifiers", values("n", "t", "f")))));
var metadata = singletonMap("plan", plan);
- var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata);
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
assertTrue(summary.hasPlan());
assertEquals("Projection", summary.plan().operatorType());
@@ -198,7 +202,7 @@ void shouldBuildResultSummaryWithPlan() {
@Test
void shouldBuildResultSummaryWithoutPlan() {
- var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap());
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap(), true, null);
assertFalse(summary.hasPlan());
assertNull(summary.plan());
}
@@ -206,22 +210,28 @@ void shouldBuildResultSummaryWithoutPlan() {
@Test
void shouldBuildResultSummaryWithProfiledPlan() {
var profile = value(parameters(
- "operatorType", "ProduceResult",
- "args", parameters("a", 42),
- "identifiers", values("a", "b"),
- "rows", value(424242),
- "dbHits", value(242424),
- "time", value(999),
+ "operatorType",
+ "ProduceResult",
+ "args",
+ parameters("a", 42),
+ "identifiers",
+ values("a", "b"),
+ "rows",
+ value(424242),
+ "dbHits",
+ value(242424),
+ "time",
+ value(999),
"children",
- values(parameters(
- "operatorType", "LabelScan",
- "args", parameters("x", 1),
- "identifiers", values("y", "z"),
- "rows", value(2),
- "dbHits", value(4)))));
+ values(parameters(
+ "operatorType", "LabelScan",
+ "args", parameters("x", 1),
+ "identifiers", values("y", "z"),
+ "rows", value(2),
+ "dbHits", value(4)))));
var metadata = singletonMap("profile", profile);
- var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata);
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
assertTrue(summary.hasPlan());
assertTrue(summary.hasProfile());
@@ -249,7 +259,7 @@ void shouldBuildResultSummaryWithProfiledPlan() {
@Test
void shouldBuildResultSummaryWithoutProfiledPlan() {
- var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap());
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap(), true, null);
assertFalse(summary.hasProfile());
assertNull(summary.profile());
}
@@ -258,30 +268,30 @@ void shouldBuildResultSummaryWithoutProfiledPlan() {
@SuppressWarnings({"deprecation", "OptionalGetWithoutIsPresent"})
void shouldBuildResultSummaryWithNotifications() {
var notification1 = parameters(
- "description", "Almost bad thing",
- "code", "Neo.DummyNotification",
- "title", "A title",
- "severity", "WARNING",
- "category", "DEPRECATION",
+ "description",
+ "Almost bad thing",
+ "code",
+ "Neo.DummyNotification",
+ "title",
+ "A title",
+ "severity",
+ "WARNING",
+ "category",
+ "DEPRECATION",
"position",
- parameters(
- "offset", 42,
- "line", 4242,
- "column", 424242));
+ parameters(
+ "offset", 42,
+ "line", 4242,
+ "column", 424242));
var notification2 = parameters(
"description", "Almost good thing",
"code", "Neo.GoodNotification",
"title", "Good",
- "severity", "INFO",
- "position",
- parameters(
- "offset", 1,
- "line", 2,
- "column", 3));
+ "severity", "INFO");
var notifications = value(notification1, notification2);
var metadata = singletonMap("notifications", notifications);
- var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata);
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
assertEquals(2, summary.notifications().size());
var firstNotification = summary.notifications().get(0);
@@ -298,17 +308,131 @@ void shouldBuildResultSummaryWithNotifications() {
NotificationCategory.DEPRECATION, firstNotification.category().get());
assertEquals("DEPRECATION", firstNotification.rawCategory().get());
assertEquals(new InternalInputPosition(42, 4242, 424242), firstNotification.position());
+ assertEquals(
+ Map.of(
+ "OPERATION", Values.value(""),
+ "OPERATION_CODE", Values.value("0"),
+ "CURRENT_SCHEMA", Values.value("/"),
+ "_severity", Values.value("WARNING"),
+ "_classification", Values.value("DEPRECATION"),
+ "_position",
+ parameters(
+ "offset", 42,
+ "line", 4242,
+ "column", 424242)),
+ firstNotification.diagnosticRecord());
assertEquals("Almost good thing", secondNotification.description());
assertEquals("Neo.GoodNotification", secondNotification.code());
assertEquals("Good", secondNotification.title());
assertEquals("INFO", secondNotification.severity());
- assertEquals(new InternalInputPosition(1, 2, 3), secondNotification.position());
+ assertTrue(secondNotification.inputPosition().isEmpty());
+ assertNull(secondNotification.position());
+ assertEquals(
+ Map.of(
+ "OPERATION", Values.value(""),
+ "OPERATION_CODE", Values.value("0"),
+ "CURRENT_SCHEMA", Values.value("/"),
+ "_severity", Values.value("INFO")),
+ secondNotification.diagnosticRecord());
+
+ assertEquals(2, summary.gqlStatusObjects().size());
+ var gqlStatusObjectsIterator = summary.gqlStatusObjects().iterator();
+ var firstGqlStatusObject = (Notification) gqlStatusObjectsIterator.next();
+ var secondGqlStatusObject = (Notification) gqlStatusObjectsIterator.next();
+ assertEquals(firstNotification, firstGqlStatusObject);
+ assertEquals(secondNotification, secondGqlStatusObject);
+ }
+
+ @Test
+ @SuppressWarnings({"deprecation", "OptionalGetWithoutIsPresent"})
+ void shouldBuildResultSummaryWithGqlStatusObjects() {
+ var gqlStatusObject1 = parameters(
+ "gql_status",
+ "gql_status",
+ "status_description",
+ "status_description",
+ "neo4j_code",
+ "neo4j_code",
+ "title",
+ "title",
+ "diagnostic_record",
+ parameters(
+ "_severity",
+ "WARNING",
+ "_classification",
+ "SECURITY",
+ "_position",
+ parameters(
+ "offset", 42,
+ "line", 4242,
+ "column", 424242)));
+ var gqlStatusObject2 = parameters(
+ "gql_status",
+ "gql_status",
+ "status_description",
+ "status_description",
+ "diagnostic_record",
+ parameters(
+ "_severity", "WARNING",
+ "_classification", "SECURITY"));
+ var gqlStatusObjects = value(gqlStatusObject1, gqlStatusObject2);
+ var metadata = singletonMap("statuses", gqlStatusObjects);
+
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, false, null);
+
+ assertEquals(2, summary.gqlStatusObjects().size());
+ var gqlStatusObjectsIterator = summary.gqlStatusObjects().iterator();
+ var firstGqlStatusObject = (Notification) gqlStatusObjectsIterator.next();
+ var secondGqlStatusObject = gqlStatusObjectsIterator.next();
+
+ assertEquals("gql_status", firstGqlStatusObject.gqlStatus());
+ assertEquals("status_description", firstGqlStatusObject.statusDescription());
+ assertEquals("status_description", firstGqlStatusObject.description());
+ assertEquals("neo4j_code", firstGqlStatusObject.code());
+ assertEquals("title", firstGqlStatusObject.title());
+ assertEquals("WARNING", firstGqlStatusObject.severity());
+ assertEquals(
+ NotificationSeverity.WARNING,
+ firstGqlStatusObject.severityLevel().get());
+ assertEquals("WARNING", firstGqlStatusObject.rawSeverityLevel().get());
+ assertEquals(
+ NotificationCategory.SECURITY, firstGqlStatusObject.category().get());
+ assertEquals("SECURITY", firstGqlStatusObject.rawCategory().get());
+ assertEquals(new InternalInputPosition(42, 4242, 424242), firstGqlStatusObject.position());
+ assertEquals(
+ Map.of(
+ "OPERATION", Values.value(""),
+ "OPERATION_CODE", Values.value("0"),
+ "CURRENT_SCHEMA", Values.value("/"),
+ "_severity", Values.value("WARNING"),
+ "_classification", Values.value("SECURITY"),
+ "_position",
+ parameters(
+ "offset", 42,
+ "line", 4242,
+ "column", 424242)),
+ firstGqlStatusObject.diagnosticRecord());
+
+ assertFalse(secondGqlStatusObject instanceof Notification);
+ assertEquals("gql_status", secondGqlStatusObject.gqlStatus());
+ assertEquals("status_description", secondGqlStatusObject.statusDescription());
+ assertEquals(
+ Map.of(
+ "OPERATION", Values.value(""),
+ "OPERATION_CODE", Values.value("0"),
+ "CURRENT_SCHEMA", Values.value("/"),
+ "_severity", Values.value("WARNING"),
+ "_classification", Values.value("SECURITY")),
+ secondGqlStatusObject.diagnosticRecord());
+
+ assertEquals(1, summary.notifications().size());
+ assertEquals(firstGqlStatusObject, summary.notifications().get(0));
}
@Test
void shouldBuildResultSummaryWithoutNotifications() {
- var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap());
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap(), true, null);
assertEquals(0, summary.notifications().size());
}
@@ -316,7 +440,7 @@ void shouldBuildResultSummaryWithoutNotifications() {
void shouldBuildResultSummaryWithResultAvailableAfter() {
var value = 42_000;
- var summary = extractor.extractSummary(query(), connectionMock(), value, emptyMap());
+ var summary = extractor.extractSummary(query(), connectionMock(), value, emptyMap(), true, null);
assertEquals(42, summary.resultAvailableAfter(TimeUnit.SECONDS));
assertEquals(value, summary.resultAvailableAfter(TimeUnit.MILLISECONDS));
@@ -327,7 +451,7 @@ void shouldBuildResultSummaryWithResultConsumedAfter() {
var value = 42_000;
var metadata = singletonMap(RESULT_CONSUMED_AFTER_KEY, value(value));
- var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata);
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
assertEquals(42, summary.resultConsumedAfter(TimeUnit.SECONDS));
assertEquals(value, summary.resultConsumedAfter(TimeUnit.MILLISECONDS));
@@ -335,7 +459,7 @@ void shouldBuildResultSummaryWithResultConsumedAfter() {
@Test
void shouldBuildResultSummaryWithoutResultConsumedAfter() {
- var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap());
+ var summary = extractor.extractSummary(query(), connectionMock(), 42, emptyMap(), true, null);
assertEquals(-1, summary.resultConsumedAfter(TimeUnit.SECONDS));
assertEquals(-1, summary.resultConsumedAfter(TimeUnit.MILLISECONDS));
}
@@ -430,7 +554,7 @@ void shouldFailToExtractServerVersionFromNonNeo4jProduct() {
private ResultSummary createWithQueryType(Value typeValue) {
var metadata = singletonMap("type", typeValue);
- return extractor.extractSummary(query(), connectionMock(), 42, metadata);
+ return extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
}
private static Query query() {
diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java
index 3fea70b749..2b7814d32a 100644
--- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java
+++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java
@@ -41,6 +41,7 @@ public class GetFeatures implements TestkitRequest {
"Feature:Bolt:5.2",
"Feature:Bolt:5.3",
"Feature:Bolt:5.4",
+ "Feature:Bolt:5.5",
"AuthorizationExpiredTreatment",
"ConfHint:connection.recv_timeout_seconds",
"Feature:Auth:Bearer",
@@ -69,7 +70,8 @@ public class GetFeatures implements TestkitRequest {
"Feature:Auth:Managed",
"Feature:API:Driver.SupportsSessionAuth",
"Feature:API:RetryableExceptions",
- "Feature:API:SSLClientCertificate"));
+ "Feature:API:SSLClientCertificate",
+ "Feature:API:Summary:GqlStatusObjects"));
private static final Set SYNC_FEATURES = new HashSet<>(Arrays.asList(
"Feature:Bolt:3.0",
diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java
index bbeb178a3b..a745e7511e 100644
--- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java
+++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java
@@ -49,12 +49,11 @@
import org.neo4j.driver.ClientCertificateManagers;
import org.neo4j.driver.ClientCertificates;
import org.neo4j.driver.Config;
-import org.neo4j.driver.NotificationConfig;
+import org.neo4j.driver.NotificationClassification;
import org.neo4j.driver.internal.BoltServerAddress;
import org.neo4j.driver.internal.DefaultDomainNameResolver;
import org.neo4j.driver.internal.DomainNameResolver;
import org.neo4j.driver.internal.DriverFactory;
-import org.neo4j.driver.internal.InternalNotificationCategory;
import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.internal.SecuritySettings;
import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancer;
@@ -101,8 +100,14 @@ public TestkitResponse process(TestkitState testkitState) {
Optional.ofNullable(data.connectionAcquisitionTimeoutMs)
.ifPresent(timeout -> configBuilder.withConnectionAcquisitionTimeout(timeout, TimeUnit.MILLISECONDS));
Optional.ofNullable(data.telemetryDisabled).ifPresent(configBuilder::withTelemetryDisabled);
- configBuilder.withNotificationConfig(
- toNotificationConfig(data.notificationsMinSeverity, data.notificationsDisabledCategories));
+ Optional.ofNullable(data.notificationsMinSeverity)
+ .flatMap(InternalNotificationSeverity::valueOf)
+ .ifPresent(configBuilder::withMinimumNotificationSeverity);
+ Optional.ofNullable(data.notificationsDisabledCategories)
+ .map(categories -> categories.stream()
+ .map(NotificationClassification::valueOf)
+ .collect(Collectors.toSet()))
+ .ifPresent(configBuilder::withDisabledNotificationClassifications);
configBuilder.withDriverMetrics();
var clientCertificateManager = Optional.ofNullable(data.getClientCertificateProviderId())
.map(testkitState::getClientCertificateManager)
@@ -272,23 +277,6 @@ private SecuritySettings.SecuritySettingsBuilder configureSecuritySettingsBuilde
return securitySettingsBuilder;
}
- public static NotificationConfig toNotificationConfig(
- String minimumSeverityString, Set disabledCategoryStrings) {
- var config = NotificationConfig.defaultConfig();
- config = Optional.ofNullable(minimumSeverityString)
- .flatMap(InternalNotificationSeverity::valueOf)
- .map(config::enableMinimumSeverity)
- .orElse(config);
- config = Optional.ofNullable(disabledCategoryStrings)
- .map(categories -> categories.stream()
- .map(InternalNotificationCategory::valueOf)
- .map(opt -> opt.orElse(null))
- .collect(Collectors.toSet()))
- .map(config::disableCategories)
- .orElse(config);
- return config;
- }
-
@Setter
@Getter
public static class NewDriverBody {
diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java
index 059be648c6..4da49ed7a1 100644
--- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java
+++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java
@@ -16,8 +16,6 @@
*/
package neo4j.org.testkit.backend.messages.requests;
-import static neo4j.org.testkit.backend.messages.requests.NewDriver.toNotificationConfig;
-
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -39,9 +37,11 @@
import neo4j.org.testkit.backend.messages.responses.TestkitResponse;
import org.neo4j.driver.AccessMode;
import org.neo4j.driver.AuthToken;
+import org.neo4j.driver.NotificationClassification;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.async.AsyncSession;
import org.neo4j.driver.internal.InternalBookmark;
+import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.reactive.ReactiveSession;
import org.neo4j.driver.reactive.RxSession;
import reactor.core.publisher.Mono;
@@ -107,8 +107,14 @@ private TestkitResponse createSessionStateAndResponse(
.map(testkitState::getBookmarkManager)
.ifPresent(builder::withBookmarkManager);
- builder.withNotificationConfig(
- toNotificationConfig(data.notificationsMinSeverity, data.notificationsDisabledCategories));
+ Optional.ofNullable(data.notificationsMinSeverity)
+ .flatMap(InternalNotificationSeverity::valueOf)
+ .ifPresent(builder::withMinimumNotificationSeverity);
+ Optional.ofNullable(data.notificationsDisabledCategories)
+ .map(categories -> categories.stream()
+ .map(NotificationClassification::valueOf)
+ .collect(Collectors.toSet()))
+ .ifPresent(builder::withDisabledNotificationClassifications);
var userSwitchAuthToken = data.getAuthorizationToken() != null
? AuthTokenUtil.parseAuthToken(data.getAuthorizationToken())
diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SummaryUtil.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SummaryUtil.java
index 07c7625898..d5d4ce81aa 100644
--- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SummaryUtil.java
+++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SummaryUtil.java
@@ -18,13 +18,14 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import neo4j.org.testkit.backend.messages.responses.Summary;
-import org.neo4j.driver.internal.InternalNotificationCategory;
import org.neo4j.driver.internal.InternalNotificationSeverity;
import org.neo4j.driver.summary.InputPosition;
+import org.neo4j.driver.summary.Notification;
import org.neo4j.driver.summary.Plan;
import org.neo4j.driver.summary.ProfiledPlan;
import org.neo4j.driver.summary.QueryType;
@@ -72,20 +73,48 @@ public static Summary.SummaryBody toSummaryBody(org.neo4j.driver.summary.ResultS
.map(InternalNotificationSeverity.Type::toString)
.orElse("UNKNOWN"))
.rawSeverityLevel(s.rawSeverityLevel().orElse(null))
- .category(s.category()
- .map(InternalNotificationCategory.class::cast)
- .map(InternalNotificationCategory::type)
- .map(InternalNotificationCategory.Type::toString)
- .orElse("UNKNOWN"))
+ .category(s.category().map(Objects::toString).orElse("UNKNOWN"))
.rawCategory(s.rawCategory().orElse(null))
.build())
.collect(Collectors.toList());
+ var gqlStatusObjects = summary.gqlStatusObjects().stream()
+ .map(gqlStatusObject -> {
+ var builder = Summary.GqlStatusObject.builder()
+ .gqlStatus(gqlStatusObject.gqlStatus())
+ .statusDescription(gqlStatusObject.statusDescription())
+ .diagnosticRecord(gqlStatusObject.diagnosticRecord());
+ if (gqlStatusObject instanceof Notification notification) {
+ builder = builder.position(toInputPosition(notification.position()))
+ .severity(notification
+ .severityLevel()
+ .map(InternalNotificationSeverity.class::cast)
+ .map(InternalNotificationSeverity::type)
+ .map(InternalNotificationSeverity.Type::toString)
+ .orElse("UNKNOWN"))
+ .rawSeverity(notification.rawSeverityLevel().orElse(null))
+ .classification(notification
+ .classification()
+ .map(Objects::toString)
+ .orElse("UNKNOWN"))
+ .rawClassification(
+ notification.rawClassification().orElse(null))
+ .notification(true);
+ } else {
+ builder = builder.position(null)
+ .severity("UNKNOWN")
+ .classification("UNKNOWN")
+ .diagnosticRecord(gqlStatusObject.diagnosticRecord());
+ }
+ return builder.build();
+ })
+ .toList();
return Summary.SummaryBody.builder()
.serverInfo(serverInfo)
.counters(counters)
.query(query)
.database(summary.database().name())
.notifications(notifications)
+ .gqlStatusObjects(gqlStatusObjects)
.plan(toPlan(summary.plan()))
.profile(toProfile(summary.profile()))
.queryType(toQueryType(summary.queryType()))
diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java
index 5b584d521c..296b1e4a9f 100644
--- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java
+++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java
@@ -16,6 +16,7 @@
*/
package neo4j.org.testkit.backend.messages.responses;
+import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Map;
import lombok.Builder;
@@ -46,6 +47,8 @@ public static class SummaryBody {
private List notifications;
+ private List gqlStatusObjects;
+
private Plan plan;
private Profile profile;
@@ -129,6 +132,29 @@ public static class Notification {
private String rawCategory;
}
+ @Getter
+ @Builder
+ public static class GqlStatusObject {
+ private String gqlStatus;
+
+ private String statusDescription;
+
+ private InputPosition position;
+
+ private String severity;
+
+ private String rawSeverity;
+
+ private String classification;
+
+ private String rawClassification;
+
+ @JsonProperty("isNotification")
+ private boolean notification;
+
+ private Map diagnosticRecord;
+ }
+
@Getter
@Builder
public static class InputPosition {
diff --git a/testkit-tests/pom.xml b/testkit-tests/pom.xml
index 55a8d3280c..b7285a5cab 100644
--- a/testkit-tests/pom.xml
+++ b/testkit-tests/pom.xml
@@ -20,7 +20,7 @@
${project.basedir}/..
https://github.com/neo4j-drivers/testkit.git
- 5.0
+ 022-gql-notifications
--tests TESTKIT_TESTS INTEGRATION_TESTS STUB_TESTS STRESS_TESTS TLS_TESTS
7200000