Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADR 022: GQL compliant notifications #1060

Merged
merged 22 commits into from
Jun 25, 2024

Conversation

robsdedude
Copy link
Member

@robsdedude robsdedude commented May 23, 2024

GQL Summary Statuses

This PR introduces GQL compliant status objects to the ResultSummary.

⚠️ This feature is still in PREVIEW.
It might be changed without following the deprecation policy.

Deprecations

SummaryNotificationPosition has been deprecated in favor of SummaryInputPosition.

New GQL Status Objects

A new property ResultSummary.gql_status_objects has been introduced. It returns a sequence of GqlStatusObjects. These objects contain information about the execution of the query including notifications as they exist now (see SummaryNotification) but also an outcome status like 00000 for "success", 02000 for "no data", and 00001 for "omitted result".

Eventually, this API is planned to supersede the current notifications API.

The GqlStatusObjects will be presented in the following order:

  • A "no data" (02xxx) has precedence over a warning;
  • A "warning" (01xxx) has precedence over a success.
  • A "success" (00xxx) has precedence over anything informational (03xxx).

Notification Filtering

Some status objects are notifications (vendor-specific definition). Those notifications can be identified using GqlStatusObject.is_notification. They contain additional information like a classification, severity, and position. Further, those notifications can be configured to be suppressed in the DBMS saving bandwidth not having to send them to the client as well as compute not having to check for those conditions.
For this, the following driver config options can be used:

  • notifications_min_severity (already existing)
  • notifications_disabled_classifications (new, same as the existing notifications_disabled_categories).
    If both options are provided, they are merged into a single list of disabled classifications/categories.

All filter config options will affect both the current notifications API as well as the notifications among the GQL status objects.

Polyfilling

There are now two APIs to access notifications: the old notifications API and the new GQL status API. To provide an easy migration path the driver will, depending on if the server is GQL aware or not (i.e., recent or old neo4j version), polyfill the API not supported by the server on a best-effort basis. In particular, GQL status objects have a GQLSTATUS code that has not counterpart in non-GQL-aware neo4j versions. Therefore, the driver will fill the GQLSTATUS with either 01N42 for warning notifications and 03N42 for informational notifications. Further, such status codes might be used by the server in the transition phase towards full GQL compliance. They indicate a lack of a final status code and will likely change in the future.

A list of all possible GQLSTATUS codes is not yet available as the server-side of this change is still very actively being worked on.

Example Usage

with neo4j.GraphDatabase.driver(
    URI,
    auth=AUTH,
    notifications_disabled_classifications=[
        # Remove this filter entry to get an additional notification
        # about the usage of a cartesian product.
        neo4j.NotificationClassification.PERFORMANCE
    ],
) as driver:
    _, summary, _ = driver.execute_query(
        "MATCH (n:Foo), (m) RETURN n.nope, m"
    )
    assert isinstance(summary, neo4j.ResultSummary)
    for status in summary.gql_status_objects:
        # The GQLSTATUS code of the status object.
        print("GQLSTATUS:", status.gql_status)
        # A description of the status for human consumption.
        print("description:", status.status_description)

        # Whether the status is a notification and can be filtered.
        print("is notification:", status.is_notification)

        # Notification and thus vendor-specific fields.
        # These fields are only meaningful for notifications.
        if status.is_notification:
            # The position in the query that caused the notification.
            print("position:", status.position)
            # The notification's classification.
            # This is the counterpart to `neo4j.NotificationCategory`,
            # however, the term category is already used for a different
            # context in the context of GQL
            print("classification:", status.classification)
            print("unparsed classification:", status.raw_classification)
            # The notification's severity.
            print("severity:", status.severity)
            print("unparsed severity:", status.raw_severity)

        # Any raw extra information provided by the DBMS:
        print("diagnostic record:", status.diagnostic_record)
        print("=" * 80)

Which, when run against an empty 5.19 DBMS, gives the following output

GQLSTATUS: 02000
description: note: no data
is notification: False
diagnostic record: {'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/'}
================================================================================
GQLSTATUS: 01N42
description: One of the labels in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing label name is: Foo)
is notification: True
position: line: 1, column: 10, offset: 9
classification: NotificationClassification.UNRECOGNIZED
unparsed classification: UNRECOGNIZED
severity: NotificationSeverity.WARNING
unparsed severity: WARNING
diagnostic record: {'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/', '_classification': 'UNRECOGNIZED', '_severity': 'WARNING', '_position': {'column': 10, 'offset': 9, 'line': 1}}
================================================================================
GQLSTATUS: 01N42
description: One of the property names in your query is not available in the database, make sure you didn't misspell it or that the label is available when you run this statement in your application (the missing property name is: nope)
is notification: True
position: line: 1, column: 29, offset: 28
classification: NotificationClassification.UNRECOGNIZED
unparsed classification: UNRECOGNIZED
severity: NotificationSeverity.WARNING
unparsed severity: WARNING
diagnostic record: {'OPERATION': '', 'OPERATION_CODE': '0', 'CURRENT_SCHEMA': '/', '_classification': 'UNRECOGNIZED', '_severity': 'WARNING', '_position': {'column': 29, 'offset': 28, 'line': 1}}
================================================================================

Depends on:

@robsdedude robsdedude marked this pull request as ready for review June 13, 2024 15:47
Copy link
Contributor

@bigmontz bigmontz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the version is wrong and there are some leftovers

docs/source/api.rst Outdated Show resolved Hide resolved
docs/source/api.rst Outdated Show resolved Hide resolved
docs/source/api.rst Outdated Show resolved Hide resolved
src/neo4j/_api.py Outdated Show resolved Hide resolved
src/neo4j/_api.py Outdated Show resolved Hide resolved
src/neo4j/_work/summary.py Outdated Show resolved Hide resolved
src/neo4j/_work/summary.py Outdated Show resolved Hide resolved
src/neo4j/_work/summary.py Outdated Show resolved Hide resolved
src/neo4j/_work/summary.py Show resolved Hide resolved
testkitbackend/_async/requests.py Show resolved Hide resolved
Copy link
Contributor

@bigmontz bigmontz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛎️

@akollegger
Copy link
Member

Does GQL require an api with "GQL" in all the names?

@robsdedude robsdedude merged commit fae56a3 into neo4j:5.0 Jun 25, 2024
20 checks passed
@robsdedude robsdedude deleted the 022-gql-notifications branch June 25, 2024 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants