notifications) {}
+
+ private record GqlStatusObjectAndNotification(GqlStatusObject gqlStatusObject, Notification notification) {}
}
diff --git a/driver/src/main/java/org/neo4j/driver/summary/GqlNotification.java b/driver/src/main/java/org/neo4j/driver/summary/GqlNotification.java
new file mode 100644
index 0000000000..161d6a12e3
--- /dev/null
+++ b/driver/src/main/java/org/neo4j/driver/summary/GqlNotification.java
@@ -0,0 +1,73 @@
+/*
+ * 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.Optional;
+import org.neo4j.driver.NotificationClassification;
+import org.neo4j.driver.NotificationSeverity;
+import org.neo4j.driver.util.Preview;
+
+/**
+ * A notification subtype of the {@link GqlStatusObject}.
+ * @since 5.28.6
+ * @see GqlStatusObject
+ */
+@Preview(name = "GQL-status object")
+public interface GqlNotification extends GqlStatusObject {
+
+ /**
+ * 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
+ */
+ Optional inputPosition();
+
+ /**
+ * Returns the severity level of the notification derived from the diagnostic record.
+ *
+ * @return the severity level of the notification
+ * @see #diagnosticRecord()
+ */
+ Optional severityLevel();
+
+ /**
+ * 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
+ * @see #diagnosticRecord()
+ */
+ Optional rawSeverityLevel();
+
+ /**
+ * 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
+ * @see #diagnosticRecord()
+ */
+ Optional classification();
+
+ /**
+ * 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
+ * @see #diagnosticRecord()
+ */
+ Optional rawClassification();
+}
diff --git a/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java b/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java
index 272aeb4cfc..314c5354de 100644
--- a/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java
+++ b/driver/src/main/java/org/neo4j/driver/summary/GqlStatusObject.java
@@ -23,7 +23,7 @@
/**
* The GQL-status object as defined by the GQL standard.
* @since 5.22.0
- * @see Notification Notification subtype of the GQL-status object
+ * @see GqlNotification Notification subtype of the GQL-status object
*/
@Preview(name = "GQL-status object")
public interface GqlStatusObject {
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 66c5a7ee61..f3249eac0a 100644
--- a/driver/src/main/java/org/neo4j/driver/summary/Notification.java
+++ b/driver/src/main/java/org/neo4j/driver/summary/Notification.java
@@ -18,10 +18,8 @@
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.
@@ -30,7 +28,7 @@
* @since 1.0
*/
@Immutable
-public interface Notification extends GqlStatusObject {
+public interface Notification {
/**
* Returns a notification code for the discovered issue.
* @return the notification code
@@ -40,7 +38,6 @@ public interface Notification extends GqlStatusObject {
/**
* Returns a short summary of the notification.
* @return the title of the notification.
- * @see #gqlStatus()
*/
String title();
@@ -59,19 +56,6 @@ public interface Notification extends GqlStatusObject {
*/
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.
*
@@ -84,52 +68,25 @@ default String severity() {
}
/**
- * Returns the severity level of the notification derived from the diagnostic record.
+ * Returns the severity level of the notification.
*
* @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 value retrieved directly from the diagnostic
- * record.
+ * Returns the raw severity level of the notification as a String returned by the server.
*
* @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 fbe183e93d..dc6a2f0b1f 100644
--- a/driver/src/main/java/org/neo4j/driver/summary/ResultSummary.java
+++ b/driver/src/main/java/org/neo4j/driver/summary/ResultSummary.java
@@ -85,13 +85,9 @@ 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();
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 e82cc799f1..b8207aabf9 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
@@ -51,6 +51,7 @@
import org.neo4j.driver.exceptions.value.Uncoercible;
import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnection;
import org.neo4j.driver.internal.summary.InternalInputPosition;
+import org.neo4j.driver.summary.GqlNotification;
import org.neo4j.driver.summary.Notification;
import org.neo4j.driver.summary.ResultSummary;
@@ -243,9 +244,13 @@ void shouldBuildResultSummaryWithNotifications() {
var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, true, null);
+ assertEquals(2, summary.gqlStatusObjects().size());
assertEquals(2, summary.notifications().size());
+ var gqlStatusObjectsIterator = summary.gqlStatusObjects().iterator();
var firstNotification = summary.notifications().get(0);
+ var firstGqlStatusObject = (GqlNotification) gqlStatusObjectsIterator.next();
var secondNotification = summary.notifications().get(1);
+ var secondGqlStatusObject = (GqlNotification) gqlStatusObjectsIterator.next();
assertEquals("Almost bad thing", firstNotification.description());
assertEquals("Neo.DummyNotification", firstNotification.code());
@@ -258,6 +263,19 @@ void shouldBuildResultSummaryWithNotifications() {
NotificationCategory.DEPRECATION, firstNotification.category().get());
assertEquals("DEPRECATION", firstNotification.rawCategory().get());
assertEquals(new InternalInputPosition(42, 4242, 424242), firstNotification.position());
+
+ assertEquals("Almost bad thing", firstGqlStatusObject.statusDescription());
+ assertEquals(
+ NotificationSeverity.WARNING,
+ firstGqlStatusObject.severityLevel().get());
+ assertEquals("WARNING", firstGqlStatusObject.rawSeverityLevel().get());
+ assertEquals(
+ NotificationCategory.DEPRECATION,
+ firstGqlStatusObject.classification().get());
+ assertEquals("DEPRECATION", firstGqlStatusObject.rawClassification().get());
+ assertEquals(
+ new InternalInputPosition(42, 4242, 424242),
+ firstGqlStatusObject.inputPosition().get());
assertEquals(
Map.of(
"OPERATION",
@@ -275,28 +293,27 @@ void shouldBuildResultSummaryWithNotifications() {
"offset", 42,
"line", 4242,
"column", 424242)),
- firstNotification.diagnosticRecord());
+ firstGqlStatusObject.diagnosticRecord());
assertEquals("Almost good thing", secondNotification.description());
assertEquals("Neo.GoodNotification", secondNotification.code());
assertEquals("Good", secondNotification.title());
assertEquals("INFO", secondNotification.severity());
- assertTrue(secondNotification.inputPosition().isEmpty());
assertNull(secondNotification.position());
+
+ assertEquals("Almost good thing", secondGqlStatusObject.statusDescription());
+ assertFalse(secondGqlStatusObject.severityLevel().isPresent());
+ assertEquals("INFO", secondGqlStatusObject.rawSeverityLevel().get());
+ assertFalse(secondGqlStatusObject.classification().isPresent());
+ assertFalse(secondGqlStatusObject.rawClassification().isPresent());
+ assertTrue(secondGqlStatusObject.inputPosition().isEmpty());
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);
+ secondGqlStatusObject.diagnosticRecord());
}
@Test
@@ -339,24 +356,25 @@ void shouldBuildResultSummaryWithGqlStatusObjects() {
var summary = extractor.extractSummary(query(), connectionMock(), 42, metadata, false, null);
assertEquals(2, summary.gqlStatusObjects().size());
+ assertEquals(1, summary.notifications().size());
var gqlStatusObjectsIterator = summary.gqlStatusObjects().iterator();
- var firstGqlStatusObject = (Notification) gqlStatusObjectsIterator.next();
+ var firstGqlStatusObject = (GqlNotification) gqlStatusObjectsIterator.next();
+ var firstNotification = summary.notifications().get(0);
var secondGqlStatusObject = gqlStatusObjectsIterator.next();
assertEquals("gql_status", firstGqlStatusObject.gqlStatus());
assertEquals("status_description", firstGqlStatusObject.statusDescription());
- assertEquals("notification_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());
+ NotificationCategory.SECURITY,
+ firstGqlStatusObject.classification().get());
+ assertEquals("SECURITY", firstGqlStatusObject.rawClassification().get());
+ assertEquals(
+ new InternalInputPosition(42, 4242, 424242),
+ firstGqlStatusObject.inputPosition().get());
assertEquals(
Map.of(
"OPERATION",
@@ -376,6 +394,17 @@ void shouldBuildResultSummaryWithGqlStatusObjects() {
"column", 424242)),
firstGqlStatusObject.diagnosticRecord());
+ assertEquals("notification_description", firstNotification.description());
+ assertEquals("neo4j_code", firstNotification.code());
+ assertEquals("title", firstNotification.title());
+ assertEquals("WARNING", firstNotification.severity());
+ assertEquals(
+ NotificationSeverity.WARNING, firstNotification.severityLevel().get());
+ assertEquals("WARNING", firstNotification.rawSeverityLevel().get());
+ assertEquals(NotificationCategory.SECURITY, firstNotification.category().get());
+ assertEquals("SECURITY", firstNotification.rawCategory().get());
+ assertEquals(new InternalInputPosition(42, 4242, 424242), firstNotification.position());
+
assertFalse(secondGqlStatusObject instanceof Notification);
assertEquals("gql_status", secondGqlStatusObject.gqlStatus());
assertEquals("status_description", secondGqlStatusObject.statusDescription());
@@ -387,9 +416,6 @@ void shouldBuildResultSummaryWithGqlStatusObjects() {
"_severity", Values.value("WARNING"),
"_classification", Values.value("SECURITY")),
secondGqlStatusObject.diagnosticRecord());
-
- assertEquals(1, summary.notifications().size());
- assertEquals(firstGqlStatusObject, summary.notifications().get(0));
}
@Test
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 d5d4ce81aa..54720edcca 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
@@ -24,8 +24,8 @@
import java.util.stream.Collectors;
import neo4j.org.testkit.backend.messages.responses.Summary;
import org.neo4j.driver.internal.InternalNotificationSeverity;
+import org.neo4j.driver.summary.GqlNotification;
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;
@@ -83,8 +83,9 @@ public static Summary.SummaryBody toSummaryBody(org.neo4j.driver.summary.ResultS
.gqlStatus(gqlStatusObject.gqlStatus())
.statusDescription(gqlStatusObject.statusDescription())
.diagnosticRecord(gqlStatusObject.diagnosticRecord());
- if (gqlStatusObject instanceof Notification notification) {
- builder = builder.position(toInputPosition(notification.position()))
+ if (gqlStatusObject instanceof GqlNotification notification) {
+ builder = builder.position(toInputPosition(
+ notification.inputPosition().orElse(null)))
.severity(notification
.severityLevel()
.map(InternalNotificationSeverity.class::cast)