Skip to content

Commit 8376736

Browse files
committed
Add supportsMultiDb function on driver
1 parent 98f3c45 commit 8376736

19 files changed

+294
-21
lines changed

src/driver.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ class Driver {
103103
return connectivityVerifier.verify({ database })
104104
}
105105

106+
/**
107+
* Returns whether the server supports multi database capabilities based on the handshaked protocol
108+
* version.
109+
*
110+
* Note that this function call _always_ causes a round-trip to the server.
111+
*
112+
* @returns {Promise<boolean>} promise resolved with a boolean or rejected with error.
113+
*/
114+
supportsMultiDb () {
115+
const connectionProvider = this._getOrCreateConnectionProvider()
116+
return connectionProvider.supportsMultiDb()
117+
}
118+
106119
/**
107120
* Acquire a session to communicate with the database. The session will
108121
* borrow connections from the underlying connection pool as required and

src/internal/bolt-protocol-v1.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,24 @@
1616
* See the License for the specific language governing permissions and
1717
* limitations under the License.
1818
*/
19-
import RequestMessage from './request-message'
20-
import * as v1 from './packstream-v1'
21-
import Bookmark from './bookmark'
22-
import TxConfig from './tx-config'
23-
import { ACCESS_MODE_WRITE } from './constants'
24-
import Connection from './connection'
25-
import { Chunker } from './chunking'
26-
import { Packer } from './packstream-v1'
2719
import {
2820
assertDatabaseIsEmpty,
2921
assertTxConfigIsEmpty
3022
} from './bolt-protocol-util'
23+
import Bookmark from './bookmark'
24+
import { Chunker } from './chunking'
25+
import Connection from './connection'
26+
import { ACCESS_MODE_WRITE, BOLT_PROTOCOL_V1 } from './constants'
27+
import * as v1 from './packstream-v1'
28+
import { Packer } from './packstream-v1'
29+
import RequestMessage from './request-message'
3130
import {
32-
ResultStreamObserver,
3331
LoginObserver,
3432
ResetObserver,
33+
ResultStreamObserver,
3534
StreamObserver
3635
} from './stream-observers'
36+
import TxConfig from './tx-config'
3737

3838
export default class BoltProtocol {
3939
/**
@@ -48,6 +48,13 @@ export default class BoltProtocol {
4848
this._unpacker = this._createUnpacker(disableLosslessIntegers)
4949
}
5050

51+
/**
52+
* Returns the numerical version identifier for this protocol
53+
*/
54+
get version () {
55+
return BOLT_PROTOCOL_V1
56+
}
57+
5158
/**
5259
* Get the packer.
5360
* @return {Packer} the protocol's packer.

src/internal/bolt-protocol-v2.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
import BoltProtocolV1 from './bolt-protocol-v1'
2020
import * as v2 from './packstream-v2'
21+
import { BOLT_PROTOCOL_V2 } from './constants'
2122

2223
export default class BoltProtocol extends BoltProtocolV1 {
2324
_createPacker (chunker) {
@@ -27,4 +28,8 @@ export default class BoltProtocol extends BoltProtocolV1 {
2728
_createUnpacker (disableLosslessIntegers) {
2829
return new v2.Unpacker(disableLosslessIntegers)
2930
}
31+
32+
get version () {
33+
return BOLT_PROTOCOL_V2
34+
}
3035
}

src/internal/bolt-protocol-v3.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ import {
2424
LoginObserver,
2525
ResultStreamObserver
2626
} from './stream-observers'
27+
import { BOLT_PROTOCOL_V3 } from './constants'
2728

2829
const noOpObserver = new StreamObserver()
2930

3031
export default class BoltProtocol extends BoltProtocolV2 {
32+
get version () {
33+
return BOLT_PROTOCOL_V3
34+
}
35+
3136
transformMetadata (metadata) {
3237
if ('t_first' in metadata) {
3338
// Bolt V3 uses shorter key 't_first' to represent 'result_available_after'

src/internal/bolt-protocol-v4.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@
1919
import BoltProtocolV3 from './bolt-protocol-v3'
2020
import RequestMessage from './request-message'
2121
import { ResultStreamObserver } from './stream-observers'
22+
import { BOLT_PROTOCOL_V4 } from './constants'
2223

2324
export default class BoltProtocol extends BoltProtocolV3 {
25+
get version () {
26+
return BOLT_PROTOCOL_V4
27+
}
28+
2429
beginTransaction ({
2530
bookmark,
2631
txConfig,

src/internal/connection-provider-direct.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import PooledConnectionProvider from './connection-provider-pooled'
2121
import DelegateConnection from './connection-delegate'
22+
import ChannelConnection from './connection-channel'
23+
import { BOLT_PROTOCOL_V4 } from './constants'
2224

2325
export default class DirectConnectionProvider extends PooledConnectionProvider {
2426
constructor ({ id, config, log, address, userAgent, authToken }) {
@@ -36,4 +38,26 @@ export default class DirectConnectionProvider extends PooledConnectionProvider {
3638
.acquire(this._address)
3739
.then(connection => new DelegateConnection(connection, null))
3840
}
41+
42+
async supportsMultiDb () {
43+
const connection = ChannelConnection.create(
44+
this._address,
45+
this._config,
46+
this._createConnectionErrorHandler(),
47+
this._log
48+
)
49+
50+
try {
51+
await connection._negotiateProtocol()
52+
53+
const protocol = connection.protocol()
54+
if (protocol) {
55+
return protocol.version >= BOLT_PROTOCOL_V4
56+
}
57+
58+
return false
59+
} finally {
60+
await connection.close()
61+
}
62+
}
3963
}

src/internal/connection-provider-routing.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ import ConnectionErrorHandler from './connection-error-handler'
3131
import DelegateConnection from './connection-delegate'
3232
import LeastConnectedLoadBalancingStrategy from './least-connected-load-balancing-strategy'
3333
import Bookmark from './bookmark'
34+
import ChannelConnection from './connection-channel'
3435
import { int } from '../integer'
3536
import { ConsoleReporter } from 'jasmine'
37+
import { BOLT_PROTOCOL_V4 } from './constants'
3638

3739
const UNAUTHORIZED_ERROR_CODE = 'Neo.ClientError.Security.Unauthorized'
3840
const DATABASE_NOT_FOUND_ERROR_CODE =
@@ -151,6 +153,41 @@ export default class RoutingConnectionProvider extends PooledConnectionProvider
151153
}
152154
}
153155

156+
async supportsMultiDb () {
157+
const addresses = await this._resolveSeedRouter(this._seedRouter)
158+
159+
let lastError
160+
for (let i = 0; i < addresses.length; i++) {
161+
const connection = ChannelConnection.create(
162+
addresses[i],
163+
this._config,
164+
this._createConnectionErrorHandler(),
165+
this._log
166+
)
167+
168+
try {
169+
await connection._negotiateProtocol()
170+
171+
const protocol = connection.protocol()
172+
if (protocol) {
173+
return protocol.version >= BOLT_PROTOCOL_V4
174+
}
175+
176+
return false
177+
} catch (error) {
178+
lastError = error
179+
} finally {
180+
await connection.close()
181+
}
182+
}
183+
184+
if (lastError) {
185+
throw lastError
186+
}
187+
188+
return false
189+
}
190+
154191
forget (address, database) {
155192
if (database || database === '') {
156193
this._routingTables[database].forget(address)

src/internal/connection-provider.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ export default class ConnectionProvider {
3838
throw new Error('not implemented')
3939
}
4040

41+
/**
42+
* This method checks whether the backend database supports multi database functionality
43+
* by checking protocol handshake result.
44+
*
45+
* @returns {Promise<boolean>}
46+
*/
47+
supportsMultiDb () {
48+
throw new Error('not implemented')
49+
}
50+
4151
/**
4252
* Closes this connection provider along with its internals (connections, pools, etc.)
4353
*

src/internal/constants.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,16 @@
2020
const ACCESS_MODE_READ = 'READ'
2121
const ACCESS_MODE_WRITE = 'WRITE'
2222

23-
export { ACCESS_MODE_READ, ACCESS_MODE_WRITE }
23+
const BOLT_PROTOCOL_V1 = 1
24+
const BOLT_PROTOCOL_V2 = 2
25+
const BOLT_PROTOCOL_V3 = 3
26+
const BOLT_PROTOCOL_V4 = 4
27+
28+
export {
29+
ACCESS_MODE_READ,
30+
ACCESS_MODE_WRITE,
31+
BOLT_PROTOCOL_V1,
32+
BOLT_PROTOCOL_V2,
33+
BOLT_PROTOCOL_V3,
34+
BOLT_PROTOCOL_V4
35+
}

test/internal/bolt-protocol-v1.test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('#unit BoltProtocolV1', () => {
5757
const recorder = new utils.MessageRecordingConnection()
5858
const protocol = new BoltProtocolV1(recorder, null, false)
5959

60-
const onError = error => {}
60+
const onError = _error => {}
6161
const onComplete = () => {}
6262
const clientName = 'js-driver/1.2.3'
6363
const authToken = { username: 'neo4j', password: 'secret' }
@@ -166,6 +166,12 @@ describe('#unit BoltProtocolV1', () => {
166166
expect(recorder.flushes).toEqual([false, true])
167167
})
168168

169+
it('should return correct bolt version number', () => {
170+
const protocol = new BoltProtocolV1(null, null, false)
171+
172+
expect(protocol.version).toBe(1)
173+
})
174+
169175
describe('Bolt V3', () => {
170176
/**
171177
* @param {function(protocol: BoltProtocolV1)} fn
@@ -202,7 +208,7 @@ describe('#unit BoltProtocolV1', () => {
202208

203209
describe('run', () => {
204210
function verifyRun (txConfig) {
205-
verifyError((protocol, observer) =>
211+
verifyError((protocol, _observer) =>
206212
protocol.run('statement', {}, { txConfig })
207213
)
208214
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
20+
import BoltProtocolV2 from '../../src/internal/bolt-protocol-v2'
21+
import utils from './test-utils'
22+
23+
describe('#unit BoltProtocolV2', () => {
24+
beforeEach(() => {
25+
jasmine.addMatchers(utils.matchers)
26+
})
27+
28+
it('should return correct bolt version number', () => {
29+
const protocol = new BoltProtocolV2(null, null, false)
30+
31+
expect(protocol.version).toBe(2)
32+
})
33+
})

test/internal/bolt-protocol-v3.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ describe('#unit BoltProtocolV3', () => {
145145
expect(recorder.flushes).toEqual([true])
146146
})
147147

148+
it('should return correct bolt version number', () => {
149+
const protocol = new BoltProtocolV3(null, null, false)
150+
151+
expect(protocol.version).toBe(3)
152+
})
153+
148154
describe('Bolt V4', () => {
149155
/**
150156
* @param {function(protocol: BoltProtocolV3)} fn

test/internal/bolt-protocol-v4.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,10 @@ describe('#unit BoltProtocolV4', () => {
9494
expect(recorder.observers).toEqual([observer])
9595
expect(recorder.flushes).toEqual([true])
9696
})
97+
98+
it('should return correct bolt version number', () => {
99+
const protocol = new BoltProtocolV4(null, null, false)
100+
101+
expect(protocol.version).toBe(4)
102+
})
97103
})

test/internal/node/direct.driver.boltkit.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,42 @@ describe('#stub-direct direct driver with stub server', () => {
411411
it('v3', () => verifyFailureOnCommit('v3'))
412412
})
413413

414+
describe('should report whether multi db is supported', () => {
415+
async function verifySupportsMultiDb (version, expected) {
416+
if (!boltStub.supported) {
417+
return
418+
}
419+
420+
const server = await boltStub.start(
421+
`./test/resources/boltstub/${version}/supports_multi_db.script`,
422+
9001
423+
)
424+
425+
const driver = boltStub.newDriver('bolt://127.0.0.1:9001')
426+
427+
await expectAsync(driver.supportsMultiDb()).toBeResolvedTo(expected)
428+
429+
await driver.close()
430+
await server.exit()
431+
}
432+
433+
it('v1', () => verifySupportsMultiDb('v1', false))
434+
it('v2', () => verifySupportsMultiDb('v2', false))
435+
it('v3', () => verifySupportsMultiDb('v3', false))
436+
it('v4', () => verifySupportsMultiDb('v4', true))
437+
it('on error', async () => {
438+
const driver = boltStub.newDriver('bolt://127.0.0.1:9001')
439+
440+
await expectAsync(driver.supportsMultiDb()).toBeRejectedWith(
441+
jasmine.objectContaining({
442+
code: SERVICE_UNAVAILABLE
443+
})
444+
)
445+
446+
await driver.close()
447+
})
448+
})
449+
414450
function connectionPool (driver, key) {
415451
return driver._connectionProvider._connectionPool._pools[key]
416452
}

0 commit comments

Comments
 (0)