Skip to content

Commit 25b8cea

Browse files
committed
Add initial Bolt V4 support
1 parent 066a410 commit 25b8cea

16 files changed

+743
-174
lines changed

src/internal/bolt-protocol-util.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Copyright (c) 2002-2019 "Neo4j,"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
import { newError } from '../error'
20+
21+
/**
22+
* @param {TxConfig} txConfig the auto-commit transaction configuration.
23+
* @param {Connection} connection the connection.
24+
* @param {StreamObserver} observer the response observer.
25+
*/
26+
function assertTxConfigIsEmpty (txConfig, connection, observer) {
27+
if (txConfig && !txConfig.isEmpty()) {
28+
const error = newError(
29+
'Driver is connected to the database that does not support transaction configuration. ' +
30+
'Please upgrade to neo4j 3.5.0 or later in order to use this functionality'
31+
)
32+
33+
// unsupported API was used, consider this a fatal error for the current connection
34+
connection._handleFatalError(error)
35+
observer.onError(error)
36+
throw error
37+
}
38+
}
39+
40+
/**
41+
* Asserts that the passed-in database name is empty.
42+
* @param {string} db
43+
* @param {Connection} connection
44+
* @param {StreamObserver} observer
45+
*/
46+
function assertDbIsEmpty (db, connection, observer) {
47+
if (db) {
48+
const error = newError(
49+
'Driver is connected to the database that does not support multiple databases. ' +
50+
'Please upgrade to neo4j 4.0.0 or later in order to use this functionality'
51+
)
52+
53+
// unsupported API was used, consider this a fatal error for the current connection
54+
connection._handleFatalError(error)
55+
observer.onError(error)
56+
throw error
57+
}
58+
}
59+
60+
export { assertDbIsEmpty, assertTxConfigIsEmpty }

src/internal/bolt-protocol-v1.js

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
*/
1919
import RequestMessage from './request-message'
2020
import * as v1 from './packstream-v1'
21-
import { newError } from '../error'
2221
import Bookmark from './bookmark'
2322
import TxConfig from './tx-config'
2423
import { ACCESS_MODE_WRITE } from './constants'
24+
import { assertDbIsEmpty, assertTxConfigIsEmpty } from './bolt-protocol-util'
2525

2626
export default class BoltProtocol {
2727
/**
@@ -78,13 +78,15 @@ export default class BoltProtocol {
7878

7979
/**
8080
* Begin an explicit transaction.
81+
* @param {StreamObserver} observer the response observer.
8182
* @param {Bookmark} bookmark the bookmark.
8283
* @param {TxConfig} txConfig the configuration.
84+
* @param {string} db the target database name.
8385
* @param {string} mode the access mode.
84-
* @param {StreamObserver} observer the response observer.
8586
*/
86-
beginTransaction (bookmark, txConfig, mode, observer) {
87+
beginTransaction (observer, { bookmark, txConfig, db, mode }) {
8788
assertTxConfigIsEmpty(txConfig, this._connection, observer)
89+
assertDbIsEmpty(db, this._connection, observer)
8890

8991
const runMessage = RequestMessage.run(
9092
'BEGIN',
@@ -103,14 +105,11 @@ export default class BoltProtocol {
103105
commitTransaction (observer) {
104106
// WRITE access mode is used as a place holder here, it has
105107
// no effect on behaviour for Bolt V1 & V2
106-
this.run(
107-
'COMMIT',
108-
{},
109-
Bookmark.empty(),
110-
TxConfig.empty(),
111-
ACCESS_MODE_WRITE,
112-
observer
113-
)
108+
this.run('COMMIT', {}, observer, {
109+
bookmark: Bookmark.empty(),
110+
txConfig: TxConfig.empty(),
111+
mode: ACCESS_MODE_WRITE
112+
})
114113
}
115114

116115
/**
@@ -120,28 +119,28 @@ export default class BoltProtocol {
120119
rollbackTransaction (observer) {
121120
// WRITE access mode is used as a place holder here, it has
122121
// no effect on behaviour for Bolt V1 & V2
123-
this.run(
124-
'ROLLBACK',
125-
{},
126-
Bookmark.empty(),
127-
TxConfig.empty(),
128-
ACCESS_MODE_WRITE,
129-
observer
130-
)
122+
this.run('ROLLBACK', {}, observer, {
123+
bookmark: Bookmark.empty(),
124+
txConfig: TxConfig.empty(),
125+
mode: ACCESS_MODE_WRITE
126+
})
131127
}
132128

133129
/**
134130
* Send a Cypher statement through the underlying connection.
135131
* @param {string} statement the cypher statement.
136132
* @param {object} parameters the statement parameters.
133+
* @param {StreamObserver} observer the response observer.
137134
* @param {Bookmark} bookmark the bookmark.
138135
* @param {TxConfig} txConfig the auto-commit transaction configuration.
136+
* @param {string} db the target database name.
139137
* @param {string} mode the access mode.
140-
* @param {StreamObserver} observer the response observer.
141138
*/
142-
run (statement, parameters, bookmark, txConfig, mode, observer) {
143-
// bookmark and mode are ignored in this versioon of the protocol
139+
run (statement, parameters, observer, { bookmark, txConfig, db, mode }) {
140+
// bookmark and mode are ignored in this version of the protocol
144141
assertTxConfigIsEmpty(txConfig, this._connection, observer)
142+
// passing in a db name on this protocol version throws an error
143+
assertDbIsEmpty(db, this._connection, observer)
145144

146145
const runMessage = RequestMessage.run(statement, parameters)
147146
const pullAllMessage = RequestMessage.pullAll()
@@ -167,22 +166,3 @@ export default class BoltProtocol {
167166
return new v1.Unpacker(disableLosslessIntegers)
168167
}
169168
}
170-
171-
/**
172-
* @param {TxConfig} txConfig the auto-commit transaction configuration.
173-
* @param {Connection} connection the connection.
174-
* @param {StreamObserver} observer the response observer.
175-
*/
176-
function assertTxConfigIsEmpty (txConfig, connection, observer) {
177-
if (!txConfig.isEmpty()) {
178-
const error = newError(
179-
'Driver is connected to the database that does not support transaction configuration. ' +
180-
'Please upgrade to neo4j 3.5.0 or later in order to use this functionality'
181-
)
182-
183-
// unsupported API was used, consider this a fatal error for the current connection
184-
connection._handleFatalError(error)
185-
observer.onError(error)
186-
throw error
187-
}
188-
}

src/internal/bolt-protocol-v3.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
import BoltProtocolV2 from './bolt-protocol-v2'
2020
import RequestMessage from './request-message'
21+
import { assertDbIsEmpty } from './bolt-protocol-util'
2122

2223
export default class BoltProtocol extends BoltProtocolV2 {
2324
transformMetadata (metadata) {
@@ -47,9 +48,10 @@ export default class BoltProtocol extends BoltProtocolV2 {
4748
this._connection.write(message, observer, true)
4849
}
4950

50-
beginTransaction (bookmark, txConfig, mode, observer) {
51+
beginTransaction (observer, { bookmark, txConfig, db, mode }) {
52+
assertDbIsEmpty(db, this._connection, observer)
5153
prepareToHandleSingleResponse(observer)
52-
const message = RequestMessage.begin(bookmark, txConfig, mode)
54+
const message = RequestMessage.begin({ bookmark, txConfig, mode })
5355
this._connection.write(message, observer, true)
5456
}
5557

@@ -65,14 +67,15 @@ export default class BoltProtocol extends BoltProtocolV2 {
6567
this._connection.write(message, observer, true)
6668
}
6769

68-
run (statement, parameters, bookmark, txConfig, mode, observer) {
69-
const runMessage = RequestMessage.runWithMetadata(
70-
statement,
71-
parameters,
70+
run (statement, parameters, observer, { bookmark, txConfig, db, mode }) {
71+
// passing in a db name on this protocol version throws an error
72+
assertDbIsEmpty(db, this._connection, observer)
73+
74+
const runMessage = RequestMessage.runWithMetadata(statement, parameters, {
7275
bookmark,
7376
txConfig,
7477
mode
75-
)
78+
})
7679
const pullAllMessage = RequestMessage.pullAll()
7780

7881
this._connection.write(runMessage, observer, false)

src/internal/bolt-protocol-v4.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright (c) 2002-2019 "Neo4j,"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
import BoltProtocolV3 from './bolt-protocol-v3'
20+
import RequestMessage from './request-message'
21+
22+
export default class BoltProtocol extends BoltProtocolV3 {
23+
beginTransaction (observer, { bookmark, txConfig, db, mode }) {
24+
const message = RequestMessage.begin({ bookmark, txConfig, db, mode })
25+
this._connection.write(message, observer, true)
26+
}
27+
28+
run (statement, parameters, observer, { bookmark, txConfig, db, mode }) {
29+
const runMessage = RequestMessage.runWithMetadata(statement, parameters, {
30+
bookmark,
31+
txConfig,
32+
db,
33+
mode
34+
})
35+
const pullMessage = RequestMessage.pull()
36+
37+
this._connection.write(runMessage, observer, false)
38+
this._connection.write(pullMessage, observer, true)
39+
}
40+
}

src/internal/protocol-handshaker.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { newError } from '../error'
2222
import BoltProtocolV1 from './bolt-protocol-v1'
2323
import BoltProtocolV2 from './bolt-protocol-v2'
2424
import BoltProtocolV3 from './bolt-protocol-v3'
25+
import BoltProtocolV4 from './bolt-protocol-v4'
2526

2627
const HTTP_MAGIC_PREAMBLE = 1213486160 // == 0x48545450 == "HTTP"
2728
const BOLT_MAGIC_PREAMBLE = 0x6060b017
@@ -90,6 +91,12 @@ export default class ProtocolHandshaker {
9091
this._chunker,
9192
this._disableLosslessIntegers
9293
)
94+
case 4:
95+
return new BoltProtocolV4(
96+
this._connection,
97+
this._chunker,
98+
this._disableLosslessIntegers
99+
)
93100
case HTTP_MAGIC_PREAMBLE:
94101
throw newError(
95102
'Server responded HTTP. Make sure you are not trying to connect to the http endpoint ' +
@@ -112,10 +119,10 @@ function newHandshakeBuffer () {
112119
handshakeBuffer.writeInt32(BOLT_MAGIC_PREAMBLE)
113120

114121
// proposed versions
122+
handshakeBuffer.writeInt32(4)
115123
handshakeBuffer.writeInt32(3)
116124
handshakeBuffer.writeInt32(2)
117125
handshakeBuffer.writeInt32(1)
118-
handshakeBuffer.writeInt32(0)
119126

120127
// reset the reader position
121128
handshakeBuffer.reset()

0 commit comments

Comments
 (0)