diff --git a/driver/clirr-ignored-differences.xml b/driver/clirr-ignored-differences.xml index 37976805c7..a0fa9252bf 100644 --- a/driver/clirr-ignored-differences.xml +++ b/driver/clirr-ignored-differences.xml @@ -645,4 +645,28 @@ java.lang.Object as(java.lang.Class) + + org/neo4j/driver/summary/Notification + 4001 + org/neo4j/driver/summary/GqlStatusObject + + + + org/neo4j/driver/summary/Notification + 7002 + java.util.Optional inputPosition() + + + + org/neo4j/driver/summary/Notification + 7002 + java.util.Optional classification() + + + + org/neo4j/driver/summary/Notification + 7002 + java.util.Optional rawClassification() + + diff --git a/driver/src/main/java/org/neo4j/driver/NotificationConfig.java b/driver/src/main/java/org/neo4j/driver/NotificationConfig.java index ff85533909..5224dfcc0f 100644 --- a/driver/src/main/java/org/neo4j/driver/NotificationConfig.java +++ b/driver/src/main/java/org/neo4j/driver/NotificationConfig.java @@ -21,7 +21,6 @@ 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. @@ -40,7 +39,6 @@ * @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/internal/summary/InternalGqlNotification.java b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlNotification.java new file mode 100644 index 0000000000..a469547e68 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlNotification.java @@ -0,0 +1,83 @@ +/* + * 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.Optional; +import org.neo4j.driver.NotificationClassification; +import org.neo4j.driver.NotificationSeverity; +import org.neo4j.driver.Value; +import org.neo4j.driver.summary.GqlNotification; +import org.neo4j.driver.summary.InputPosition; + +public class InternalGqlNotification extends InternalGqlStatusObject implements GqlNotification { + private final InputPosition position; + private final NotificationSeverity severityLevel; + private final String rawSeverityLevel; + private final NotificationClassification classification; + private final String rawClassification; + + public InternalGqlNotification( + String gqlStatus, + String statusDescription, + Map diagnosticRecord, + InputPosition position, + NotificationSeverity severityLevel, + String rawSeverityLevel, + NotificationClassification classification, + String rawClassification) { + super(gqlStatus, statusDescription, diagnosticRecord); + this.position = position; + this.severityLevel = severityLevel; + this.rawSeverityLevel = rawSeverityLevel; + this.classification = classification; + this.rawClassification = rawClassification; + } + + @Override + public Optional inputPosition() { + return Optional.ofNullable(position); + } + + @Override + public Optional severityLevel() { + return Optional.ofNullable(severityLevel); + } + + @Override + 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 String toString() { + return "InternalGqlNotification{" + "gqlStatus='" + + gqlStatus + '\'' + ", statusDescription='" + + statusDescription + '\'' + ", diagnosticRecord=" + + diagnosticRecord + '}'; + } +} 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 index 97919c2c20..666dded481 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlStatusObject.java +++ b/driver/src/main/java/org/neo4j/driver/internal/summary/InternalGqlStatusObject.java @@ -52,9 +52,9 @@ public class InternalGqlStatusObject implements GqlStatusObject { Map.entry("OPERATION", Values.value("")), Map.entry("OPERATION_CODE", Values.value("0")))); - private final String gqlStatus; - private final String statusDescription; - private final Map diagnosticRecord; + protected final String gqlStatus; + protected final String statusDescription; + protected final Map diagnosticRecord; public InternalGqlStatusObject(String gqlStatus, String statusDescription, Map diagnosticRecord) { this.gqlStatus = Objects.requireNonNull(gqlStatus); 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 faaa45f1de..f27dd14d2a 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 @@ -17,17 +17,14 @@ package org.neo4j.driver.internal.summary; import java.util.Arrays; -import java.util.Map; -import java.util.Objects; import java.util.Optional; import org.neo4j.driver.NotificationCategory; import org.neo4j.driver.NotificationClassification; import org.neo4j.driver.NotificationSeverity; -import org.neo4j.driver.Value; import org.neo4j.driver.summary.InputPosition; import org.neo4j.driver.summary.Notification; -public class InternalNotification extends InternalGqlStatusObject implements Notification { +public class InternalNotification implements Notification { public static Optional valueOf(String value) { return Arrays.stream(NotificationClassification.values()) .filter(type -> type.toString().equals(value)) @@ -50,52 +47,44 @@ public static Optional valueOf(String value) { private final String description; private final NotificationSeverity severityLevel; private final String rawSeverityLevel; - private final NotificationClassification classification; - private final String rawClassification; + private final NotificationCategory category; + private final String rawCategory; private final InputPosition position; public InternalNotification( - String gqlStatus, - String statusDescription, - Map diagnosticRecord, String code, String title, String description, NotificationSeverity severityLevel, String rawSeverityLevel, - NotificationClassification classification, - String rawClassification, + NotificationCategory category, + String rawCategory, InputPosition position) { - super(gqlStatus, statusDescription, diagnosticRecord); - this.code = Objects.requireNonNull(code); + this.code = code; this.title = title; this.description = description; this.severityLevel = severityLevel; this.rawSeverityLevel = rawSeverityLevel; - this.classification = classification; - this.rawClassification = rawClassification; + this.category = category; + this.rawCategory = rawCategory; 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,62 +100,21 @@ 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(classification); + return Optional.ofNullable(category); } @Override public Optional 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); + return Optional.ofNullable(rawCategory); } @Override public String toString() { var info = "code=" + code + ", title=" + title + ", description=" + description + ", severityLevel=" - + severityLevel + ", rawSeverityLevel=" + rawSeverityLevel + ", classification=" + classification - + ", rawClassification=" - + rawClassification; + + severityLevel + ", rawSeverityLevel=" + rawSeverityLevel + ", category=" + category + ", rawCategory=" + + rawCategory; return position == null ? info : info + ", position={" + position + "}"; } } 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 e2b20a71d3..8f795203c3 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 @@ -18,6 +18,8 @@ import static java.util.Collections.unmodifiableSet; import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.filtering; +import static java.util.stream.Collectors.mapping; import static java.util.stream.Collectors.teeing; import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toUnmodifiableList; @@ -30,6 +32,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.OptionalInt; import java.util.Set; import java.util.TreeSet; @@ -45,6 +48,7 @@ import org.neo4j.driver.internal.InternalNotificationSeverity; import org.neo4j.driver.internal.adaptedbolt.DriverBoltConnection; import org.neo4j.driver.internal.summary.InternalDatabaseInfo; +import org.neo4j.driver.internal.summary.InternalGqlNotification; import org.neo4j.driver.internal.summary.InternalGqlStatusObject; import org.neo4j.driver.internal.summary.InternalInputPosition; import org.neo4j.driver.internal.summary.InternalNotification; @@ -104,29 +108,38 @@ public ResultSummary extractSummary( Set gqlStatusObjects; List notifications; if (legacyNotifications) { - var gqlStatusObjectsAndNotifications = extractGqlStatusObjectsFromNotifications(metadata) + var gqlStatusObjectsAndNotifications = generateGqlStatusObjectsAndExtractNotifications(metadata) .collect(teeing( - collectingAndThen( - toCollection( - () -> (Set) new TreeSet<>(GQL_STATUS_OBJECT_COMPARATOR)), - set -> { - if (gqlStatusObject != null) { - set.add(gqlStatusObject); - } - return unmodifiableSet(set); - }), - toUnmodifiableList(), + mapping( + GqlStatusObjectAndNotification::gqlStatusObject, + collectingAndThen( + toCollection(() -> + (Set) new TreeSet<>(GQL_STATUS_OBJECT_COMPARATOR)), + set -> { + if (gqlStatusObject != null) { + set.add(gqlStatusObject); + } + return unmodifiableSet(set); + })), + mapping(GqlStatusObjectAndNotification::notification, 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(); + var gqlStatusObjectsAndNotifications = extractGqlStatusObjectsAndGenerateNotifications(metadata) + .collect(teeing( + mapping( + GqlStatusObjectAndNotification::gqlStatusObject, + collectingAndThen( + toCollection( + () -> (Set) new LinkedHashSet()), + Collections::unmodifiableSet)), + mapping( + GqlStatusObjectAndNotification::notification, + filtering(Objects::nonNull, toUnmodifiableList())), + GqlStatusObjectsAndNotifications::new)); + gqlStatusObjects = gqlStatusObjectsAndNotifications.gqlStatusObjects(); + notifications = gqlStatusObjectsAndNotifications.notifications(); } return new InternalResultSummary( query, @@ -200,7 +213,8 @@ private static ProfiledPlan extractProfiledPlan(Map metadata) { return null; } - private static Stream extractGqlStatusObjectsFromNotifications(Map metadata) { + private static Stream generateGqlStatusObjectsAndExtractNotifications( + Map metadata) { var notificationsValue = metadata.get("notifications"); if (notificationsValue != null && TypeSystem.getDefault().LIST().isTypeOf(notificationsValue)) { var iterable = notificationsValue.values(value -> { @@ -259,36 +273,37 @@ private static Stream extractGqlStatusObjectsFromNotifications(Map Values.value(position.column())))); } - return new InternalNotification( + var gqlNotification = new InternalGqlNotification( gqlStatusCode, gqlStatusDescription, Collections.unmodifiableMap(diagnosticRecord), - code, - title, - description, + position, severityLevel, rawSeverityLevel, (NotificationClassification) category, - rawCategory, - position); + rawCategory); + var notification = new InternalNotification( + code, title, description, severityLevel, rawSeverityLevel, category, rawCategory, position); + return new GqlStatusObjectAndNotification(gqlNotification, notification); }); - return StreamSupport.stream(iterable.spliterator(), false).map(Notification.class::cast); + return StreamSupport.stream(iterable.spliterator(), false); } else { return Stream.empty(); } } - private static Stream extractGqlStatusObjects(Map metadata) { + private static Stream extractGqlStatusObjectsAndGenerateNotifications( + Map metadata) { var statuses = metadata.get("statuses"); if (statuses != null && TypeSystem.getDefault().LIST().isTypeOf(statuses)) { - var iterable = statuses.values(MetadataExtractor::extractGqlStatusObject); + var iterable = statuses.values(MetadataExtractor::extractGqlStatusObjectAndGenerateNotification); return StreamSupport.stream(iterable.spliterator(), false); } else { return Stream.empty(); } } - private static GqlStatusObject extractGqlStatusObject(Value value) { + private static GqlStatusObjectAndNotification extractGqlStatusObjectAndGenerateNotification(Value value) { var status = value.get("gql_status").asString(); var description = value.get("status_description").asString(); Map diagnosticRecord; @@ -322,7 +337,8 @@ private static GqlStatusObject extractGqlStatusObject(Value value) { var neo4jCode = value.get("neo4j_code").asString(null); if (neo4jCode == null || neo4jCode.trim().isEmpty()) { - return new InternalGqlStatusObject(status, description, diagnosticRecord); + var gqlStatusObject = new InternalGqlStatusObject(status, description, diagnosticRecord); + return new GqlStatusObjectAndNotification(gqlStatusObject, null); } else { var title = value.get("title").asString(); var notificationDescription = @@ -354,10 +370,16 @@ private static GqlStatusObject extractGqlStatusObject(Value value) { var classification = (NotificationClassification) InternalNotification.valueOf(rawClassification).orElse(null); - return new InternalNotification( + var gqlNotification = new InternalGqlNotification( status, description, diagnosticRecord, + position, + severity, + rawSeverity, + classification, + rawClassification); + var notification = new InternalNotification( neo4jCode, title, notificationDescription, @@ -366,6 +388,7 @@ private static GqlStatusObject extractGqlStatusObject(Value value) { classification, rawClassification, position); + return new GqlStatusObjectAndNotification(gqlNotification, notification); } } @@ -388,4 +411,6 @@ private static long extractResultConsumedAfter(Map metadata, Stri private record GqlStatusObjectsAndNotifications( Set gqlStatusObjects, List 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)