Skip to content

Commit a7efcf7

Browse files
authored
Introduce GqlStatusObject support as notifications to ResultSummary (#1194)
**⚠️ This API is released as preview.** Introduces `ResultSummary.gqlStatusObjects` as preview feature. `GqlStatusObject` is a GQL compliant `Notification` object and status of query execution, this new object includes `gqlStatus` and `statusDescription`. `ResultSummary.gqlStatusObjects` always contains at least 1 status representing the `Success`, `No Data` or `Omitted Result`. When discarding records in a RxSession while connected to a non-GQL-aware server, the driver might not be able to tell apart `Success` and `No Data`. 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`) ### Migrating from Notification Most of the properties present in the `Notification` are present in the new object, except `code` and `title`. The `GqlStatusObject.gqlStatus` is equivalent of `code` in the `Notification`, but with values compliant with GQL. The properties `GqlStatusObject.classification` and `GqlStatusObject.rawClassification` are equivalent to `Notification.category` and `Notification.rawCategory`. The name change is needed because `category` has a different meaning in GQL. ### Configuration Filtering `gqlStatusObjects` can be done using in the same way as filtering `notifications`. However, non-notification status can not be filtered (such as `Success` or `No Data`). The property `disabledClassifications` was added to `NotificationFilter` for being named consistently with GQL. This property is equivalent to `disabledCategories` and it be can used interchangeably. However, they can not be used at the same time. An exception will be raised in this scenario. **⚠️ This API is released as preview.**
1 parent 22019bb commit a7efcf7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+6363
-692
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import BoltProtocolV5x4 from './bolt-protocol-v5x4'
18+
19+
import transformersFactories from './bolt-protocol-v5x5.transformer'
20+
import Transformer from './transformer'
21+
import RequestMessage from './request-message'
22+
import { LoginObserver, ResultStreamObserver } from './stream-observers'
23+
24+
import { internal } from 'neo4j-driver-core'
25+
26+
const {
27+
constants: { BOLT_PROTOCOL_V5_5, FETCH_ALL }
28+
} = internal
29+
30+
const DEFAULT_DIAGNOSTIC_RECORD = Object.freeze({
31+
OPERATION: '',
32+
OPERATION_CODE: '0',
33+
CURRENT_SCHEMA: '/'
34+
})
35+
36+
export default class BoltProtocol extends BoltProtocolV5x4 {
37+
get version () {
38+
return BOLT_PROTOCOL_V5_5
39+
}
40+
41+
get transformer () {
42+
if (this._transformer === undefined) {
43+
this._transformer = new Transformer(Object.values(transformersFactories).map(create => create(this._config, this._log)))
44+
}
45+
return this._transformer
46+
}
47+
48+
/**
49+
* Initialize a connection with the server
50+
*
51+
* @param {Object} args The params
52+
* @param {string} args.userAgent The user agent
53+
* @param {any} args.authToken The auth token
54+
* @param {NotificationFilter} args.notificationFilter The notification filters.
55+
* @param {function(error)} args.onError On error callback
56+
* @param {function(onComplete)} args.onComplete On complete callback
57+
* @returns {LoginObserver} The Login observer
58+
*/
59+
initialize ({ userAgent, boltAgent, authToken, notificationFilter, onError, onComplete } = {}) {
60+
const state = {}
61+
const observer = new LoginObserver({
62+
onError: error => this._onLoginError(error, onError),
63+
onCompleted: metadata => {
64+
state.metadata = metadata
65+
return this._onLoginCompleted(metadata)
66+
}
67+
})
68+
69+
this.write(
70+
RequestMessage.hello5x5(userAgent, boltAgent, notificationFilter, this._serversideRouting),
71+
observer,
72+
false
73+
)
74+
75+
return this.logon({
76+
authToken,
77+
onComplete: metadata => onComplete({ ...metadata, ...state.metadata }),
78+
onError,
79+
flush: true
80+
})
81+
}
82+
83+
beginTransaction ({
84+
bookmarks,
85+
txConfig,
86+
database,
87+
mode,
88+
impersonatedUser,
89+
notificationFilter,
90+
beforeError,
91+
afterError,
92+
beforeComplete,
93+
afterComplete
94+
} = {}) {
95+
const observer = new ResultStreamObserver({
96+
server: this._server,
97+
beforeError,
98+
afterError,
99+
beforeComplete,
100+
afterComplete
101+
})
102+
observer.prepareToHandleSingleResponse()
103+
104+
this.write(
105+
RequestMessage.begin5x5({ bookmarks, txConfig, database, mode, impersonatedUser, notificationFilter }),
106+
observer,
107+
true
108+
)
109+
110+
return observer
111+
}
112+
113+
run (
114+
query,
115+
parameters,
116+
{
117+
bookmarks,
118+
txConfig,
119+
database,
120+
mode,
121+
impersonatedUser,
122+
notificationFilter,
123+
beforeKeys,
124+
afterKeys,
125+
beforeError,
126+
afterError,
127+
beforeComplete,
128+
afterComplete,
129+
flush = true,
130+
reactive = false,
131+
fetchSize = FETCH_ALL,
132+
highRecordWatermark = Number.MAX_VALUE,
133+
lowRecordWatermark = Number.MAX_VALUE
134+
} = {}
135+
) {
136+
const observer = new ResultStreamObserver({
137+
server: this._server,
138+
reactive,
139+
fetchSize,
140+
moreFunction: this._requestMore.bind(this),
141+
discardFunction: this._requestDiscard.bind(this),
142+
beforeKeys,
143+
afterKeys,
144+
beforeError,
145+
afterError,
146+
beforeComplete,
147+
afterComplete,
148+
highRecordWatermark,
149+
lowRecordWatermark,
150+
enrichMetadata: BoltProtocol._enrichMetadata
151+
})
152+
153+
const flushRun = reactive
154+
this.write(
155+
RequestMessage.runWithMetadata5x5(query, parameters, {
156+
bookmarks,
157+
txConfig,
158+
database,
159+
mode,
160+
impersonatedUser,
161+
notificationFilter
162+
}),
163+
observer,
164+
flushRun && flush
165+
)
166+
167+
if (!reactive) {
168+
this.write(RequestMessage.pull({ n: fetchSize }), observer, flush)
169+
}
170+
171+
return observer
172+
}
173+
174+
/**
175+
*
176+
* @param {object} metadata
177+
* @returns {object}
178+
*/
179+
static _enrichMetadata (metadata) {
180+
if (Array.isArray(metadata.statuses)) {
181+
metadata.statuses = metadata.statuses.map(status => ({
182+
...status,
183+
diagnostic_record: status.diagnostic_record !== null ? { ...DEFAULT_DIAGNOSTIC_RECORD, ...status.diagnostic_record } : null
184+
}))
185+
}
186+
187+
return metadata
188+
}
189+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import v5x3 from './bolt-protocol-v5x3.transformer'
19+
20+
export default {
21+
...v5x3
22+
}

packages/bolt-connection/src/bolt/create.js

+9
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import BoltProtocolV5x1 from './bolt-protocol-v5x1'
2929
import BoltProtocolV5x2 from './bolt-protocol-v5x2'
3030
import BoltProtocolV5x3 from './bolt-protocol-v5x3'
3131
import BoltProtocolV5x4 from './bolt-protocol-v5x4'
32+
import BoltProtocolV5x5 from './bolt-protocol-v5x5'
3233
// eslint-disable-next-line no-unused-vars
3334
import { Chunker, Dechunker } from '../channel'
3435
import ResponseHandler from './response-handler'
@@ -229,6 +230,14 @@ function createProtocol (
229230
log,
230231
onProtocolError,
231232
serversideRouting)
233+
case 5.5:
234+
return new BoltProtocolV5x5(server,
235+
chunker,
236+
packingConfig,
237+
createResponseHandler,
238+
log,
239+
onProtocolError,
240+
serversideRouting)
232241
default:
233242
throw newError('Unknown Bolt protocol version: ' + version)
234243
}

packages/bolt-connection/src/bolt/handshake.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function parseNegotiatedResponse (buffer, log) {
7676
*/
7777
function newHandshakeBuffer () {
7878
return createHandshakeMessage([
79-
[version(5, 4), version(5, 0)],
79+
[version(5, 5), version(5, 0)],
8080
[version(4, 4), version(4, 2)],
8181
version(4, 1),
8282
version(3, 0)

0 commit comments

Comments
 (0)