Skip to content

Commit c9a1bbc

Browse files
committed
Add support for BigInt
Recent V8 release adds a new type - BigInt. It is thus available in latest NodeJS (v10+) and Chrome (v67+). Driver could use this type instead of the custom Integer to represent lossy integer numbers. This is configurable because BigInt and Number are not fully compatible, so driver can't always return BitInts. For example `BigInt(1) / Number(1)` results in a TypeError, as well as `JSON.stringify({v: BigInt(1)})`. The configuration property is `useBigInt` and it's `false` by default, in manner to break drivers user on update. This configuration take precedence over `disableLosslessIntegers`
1 parent 4aad3bf commit c9a1bbc

35 files changed

+837
-243
lines changed

bolt-connection/jest.config.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ module.exports = {
137137
// snapshotSerializers: [],
138138

139139
// The test environment that will be used for testing
140-
testEnvironment: 'node'
140+
testEnvironment: 'node',
141141

142142
// Options that will be passed to the testEnvironment
143143
// testEnvironmentOptions: {},
@@ -172,9 +172,9 @@ module.exports = {
172172
// timers: "real",
173173

174174
// A map from regular expressions to paths to transformers
175-
// transform: {
176-
// "^.+\\.(ts|tsx)$": "ts-jest"
177-
// }
175+
transform: {
176+
'^.+\\.(ts|tsx|js)$': 'ts-jest'
177+
}
178178
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
179179
// transformIgnorePatterns: [
180180
// "/node_modules/",

bolt-connection/package-lock.json

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bolt-connection/src/bolt/bolt-protocol-v1.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,25 @@ export default class BoltProtocol {
5252
* @constructor
5353
* @param {Object} server the server informatio.
5454
* @param {Chunker} chunker the chunker.
55-
* @param {boolean} disableLosslessIntegers if this connection should convert all received integers to native JS numbers.
55+
* @param {Object} packstreamConfig Packstream configuration
56+
* @param {boolean} packstreamConfig.disableLosslessIntegers if this connection should convert all received integers to native JS numbers.
57+
* @param {boolean} packstreamConfig.useBigInt if this connection should convert all received integers to native BigInt numbers.
5658
* @param {CreateResponseHandler} createResponseHandler Function which creates the response handler
5759
* @param {Logger} log the logger
5860
* @param {OnProtocolError} onProtocolError handles protocol errors
5961
*/
6062
constructor (
6163
server,
6264
chunker,
63-
disableLosslessIntegers,
65+
{ disableLosslessIntegers, useBigInt } = {},
6466
createResponseHandler = () => null,
6567
log,
6668
onProtocolError
6769
) {
6870
this._server = server || {}
6971
this._chunker = chunker
7072
this._packer = this._createPacker(chunker)
71-
this._unpacker = this._createUnpacker(disableLosslessIntegers)
73+
this._unpacker = this._createUnpacker(disableLosslessIntegers, useBigInt)
7274
this._responseHandler = createResponseHandler(this)
7375
this._log = log
7476
this._onProtocolError = onProtocolError
@@ -317,8 +319,8 @@ export default class BoltProtocol {
317319
return new v1.Packer(chunker)
318320
}
319321

320-
_createUnpacker (disableLosslessIntegers) {
321-
return new v1.Unpacker(disableLosslessIntegers)
322+
_createUnpacker (disableLosslessIntegers, useBigInt) {
323+
return new v1.Unpacker(disableLosslessIntegers, useBigInt)
322324
}
323325

324326
/**

bolt-connection/src/bolt/bolt-protocol-v2.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ export default class BoltProtocol extends BoltProtocolV1 {
2929
return new v2.Packer(chunker)
3030
}
3131

32-
_createUnpacker (disableLosslessIntegers) {
33-
return new v2.Unpacker(disableLosslessIntegers)
32+
_createUnpacker (disableLosslessIntegers, useBigInt) {
33+
return new v2.Unpacker(disableLosslessIntegers, useBigInt)
3434
}
3535

3636
get version () {

bolt-connection/src/bolt/bolt-protocol-v4x1.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export default class BoltProtocol extends BoltProtocolV4 {
3030
* @constructor
3131
* @param {Object} server the server informatio.
3232
* @param {Chunker} chunker the chunker.
33-
* @param {boolean} disableLosslessIntegers if this connection should convert all received integers to native JS numbers.
33+
* @param {Object} packstreamConfig Packstream configuration
34+
* @param {boolean} packstreamConfig.disableLosslessIntegers if this connection should convert all received integers to native JS numbers.
35+
* @param {boolean} packstreamConfig.useBigInt if this connection should convert all received integers to native BigInt numbers.
3436
* @param {CreateResponseHandler} createResponseHandler Function which creates the response handler
3537
* @param {Logger} log the logger
3638
* @param {Object} serversideRouting
@@ -39,7 +41,7 @@ export default class BoltProtocol extends BoltProtocolV4 {
3941
constructor (
4042
server,
4143
chunker,
42-
disableLosslessIntegers,
44+
packstreamConfig,
4345
createResponseHandler = () => null,
4446
log,
4547
onProtocolError,
@@ -48,7 +50,7 @@ export default class BoltProtocol extends BoltProtocolV4 {
4850
super(
4951
server,
5052
chunker,
51-
disableLosslessIntegers,
53+
packstreamConfig,
5254
createResponseHandler,
5355
log,
5456
onProtocolError

bolt-connection/src/bolt/create.js

+11-9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import ResponseHandler from './response-handler'
3939
* @param {Logger} config.log The logger
4040
* @param {ResponseHandler~Observer} config.observer Observer
4141
* @param {boolean} config.disableLosslessIntegers Disable the lossless integers
42+
* @param {boolean} packstreamConfig.useBigInt if this connection should convert all received integers to native BigInt numbers.
4243
* @param {boolean} config.serversideRouting It's using server side routing
4344
*/
4445
export default function create ({
@@ -47,6 +48,7 @@ export default function create ({
4748
dechunker,
4849
channel,
4950
disableLosslessIntegers,
51+
useBigInt,
5052
serversideRouting,
5153
server, // server info
5254
log,
@@ -77,7 +79,7 @@ export default function create ({
7779
version,
7880
server,
7981
chunker,
80-
disableLosslessIntegers,
82+
{ disableLosslessIntegers, useBigInt },
8183
serversideRouting,
8284
createResponseHandler,
8385
observer.onProtocolError.bind(observer),
@@ -89,7 +91,7 @@ function createProtocol (
8991
version,
9092
server,
9193
chunker,
92-
disableLosslessIntegers,
94+
packingConfig,
9395
serversideRouting,
9496
createResponseHandler,
9597
onProtocolError,
@@ -100,7 +102,7 @@ function createProtocol (
100102
return new BoltProtocolV1(
101103
server,
102104
chunker,
103-
disableLosslessIntegers,
105+
packingConfig,
104106
createResponseHandler,
105107
log,
106108
onProtocolError
@@ -109,7 +111,7 @@ function createProtocol (
109111
return new BoltProtocolV2(
110112
server,
111113
chunker,
112-
disableLosslessIntegers,
114+
packingConfig,
113115
createResponseHandler,
114116
log,
115117
onProtocolError
@@ -118,7 +120,7 @@ function createProtocol (
118120
return new BoltProtocolV3(
119121
server,
120122
chunker,
121-
disableLosslessIntegers,
123+
packingConfig,
122124
createResponseHandler,
123125
log,
124126
onProtocolError
@@ -127,7 +129,7 @@ function createProtocol (
127129
return new BoltProtocolV4x0(
128130
server,
129131
chunker,
130-
disableLosslessIntegers,
132+
packingConfig,
131133
createResponseHandler,
132134
log,
133135
onProtocolError
@@ -136,7 +138,7 @@ function createProtocol (
136138
return new BoltProtocolV4x1(
137139
server,
138140
chunker,
139-
disableLosslessIntegers,
141+
packingConfig,
140142
createResponseHandler,
141143
log,
142144
onProtocolError,
@@ -146,7 +148,7 @@ function createProtocol (
146148
return new BoltProtocolV4x2(
147149
server,
148150
chunker,
149-
disableLosslessIntegers,
151+
packingConfig,
150152
createResponseHandler,
151153
log,
152154
onProtocolError,
@@ -156,7 +158,7 @@ function createProtocol (
156158
return new BoltProtocolV4x3(
157159
server,
158160
chunker,
159-
disableLosslessIntegers,
161+
packingConfig,
160162
createResponseHandler,
161163
log,
162164
onProtocolError,

bolt-connection/src/connection/connection-channel.js

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export function createChannelConnection (
6262
chunker,
6363
dechunker,
6464
disableLosslessIntegers: config.disableLosslessIntegers,
65+
useBigInt: config.useBigInt,
6566
serversideRouting,
6667
server: conn.server,
6768
log,

bolt-connection/src/packstream/packstream-v1.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ class Packer {
126126
return () => this.packFloat(x)
127127
} else if (typeof x === 'string') {
128128
return () => this.packString(x)
129+
} else if (typeof x === 'bigint') {
130+
return () => this.packInteger(int(x))
129131
} else if (isInt(x)) {
130132
return () => this.packInteger(x)
131133
} else if (x instanceof Int8Array) {
@@ -368,9 +370,11 @@ class Unpacker {
368370
/**
369371
* @constructor
370372
* @param {boolean} disableLosslessIntegers if this unpacker should convert all received integers to native JS numbers.
373+
* @param {boolean} useBigInt if this unpacker should convert all received integers to Bigint
371374
*/
372-
constructor (disableLosslessIntegers = false) {
375+
constructor (disableLosslessIntegers = false, useBigInt = false) {
373376
this._disableLosslessIntegers = disableLosslessIntegers
377+
this._useBigInt = useBigInt
374378
}
375379

376380
unpack (buffer) {
@@ -389,8 +393,12 @@ class Unpacker {
389393

390394
const numberOrInteger = this._unpackNumberOrInteger(marker, buffer)
391395
if (numberOrInteger !== null) {
392-
if (this._disableLosslessIntegers && isInt(numberOrInteger)) {
393-
return numberOrInteger.toNumberOrInfinity()
396+
if (isInt(numberOrInteger)) {
397+
if (this._useBigInt) {
398+
return numberOrInteger.toBigInt()
399+
} else if (this._disableLosslessIntegers) {
400+
return numberOrInteger.toNumberOrInfinity()
401+
}
394402
}
395403
return numberOrInteger
396404
}

bolt-connection/src/packstream/packstream-v2.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,10 @@ export class Unpacker extends v1.Unpacker {
106106
/**
107107
* @constructor
108108
* @param {boolean} disableLosslessIntegers if this unpacker should convert all received integers to native JS numbers.
109+
* @param {boolean} useBigInt if this unpacker should convert all received integers to Bigint
109110
*/
110-
constructor (disableLosslessIntegers = false) {
111-
super(disableLosslessIntegers)
111+
constructor (disableLosslessIntegers = false, useBigInt = false) {
112+
super(disableLosslessIntegers, useBigInt)
112113
}
113114

114115
_unpackUnknownStruct (signature, structSize, buffer) {
@@ -584,15 +585,15 @@ function unpackDateTimeWithZoneId (
584585
}
585586

586587
function convertIntegerPropsIfNeeded (obj, disableLosslessIntegers) {
587-
if (!disableLosslessIntegers) {
588-
return obj
589-
}
588+
// if (!disableLosslessIntegers) {
589+
// return obj
590+
// }
590591

591592
const clone = Object.create(Object.getPrototypeOf(obj))
592593
for (const prop in obj) {
593594
if (obj.hasOwnProperty(prop)) {
594595
const value = obj[prop]
595-
clone[prop] = isInt(value) ? value.toNumberOrInfinity() : value
596+
clone[prop] = isInt(value) ? value.toBigInt() : value
596597
}
597598
}
598599
Object.freeze(clone)

test/internal/bolt/bolt-protocol-v1.test.js renamed to bolt-connection/test/bolt/bolt-protocol-v1.test.js

+28-8
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@
1717
* limitations under the License.
1818
*/
1919

20-
import BoltProtocolV1 from '../../../bolt-connection/lib/bolt/bolt-protocol-v1'
21-
import RequestMessage from '../../../bolt-connection/lib/bolt/request-message'
22-
import { WRITE } from '../../../src/driver'
23-
import utils from '../test-utils'
24-
import { LoginObserver } from '../../../bolt-connection/lib/bolt/stream-observers'
20+
import BoltProtocolV1 from '../../src/bolt/bolt-protocol-v1'
21+
import RequestMessage from '../../src/bolt/request-message'
2522
import { internal } from 'neo4j-driver-core'
23+
import utils from '../test-utils'
24+
import { LoginObserver } from '../../src/bolt/stream-observers'
2625

2726
const {
2827
bookmark: { Bookmark },
@@ -31,7 +30,7 @@ const {
3130

3231
describe('#unit BoltProtocolV1', () => {
3332
beforeEach(() => {
34-
jasmine.addMatchers(utils.matchers)
33+
expect.extend(utils.matchers)
3534
})
3635

3736
it('should not change metadata', () => {
@@ -97,7 +96,7 @@ describe('#unit BoltProtocolV1', () => {
9796
const observer = protocol.run(query, parameters, {
9897
bookmark: Bookmark.empty(),
9998
txConfig: TxConfig.empty(),
100-
mode: WRITE
99+
mode: 'WRITE'
101100
})
102101

103102
protocol.verifyMessageCount(2)
@@ -135,7 +134,7 @@ describe('#unit BoltProtocolV1', () => {
135134
const observer = protocol.beginTransaction({
136135
bookmark: bookmark,
137136
txConfig: TxConfig.empty(),
138-
mode: WRITE
137+
mode: 'WRITE'
139138
})
140139

141140
protocol.verifyMessageCount(2)
@@ -275,4 +274,25 @@ describe('#unit BoltProtocolV1', () => {
275274
})
276275
})
277276
})
277+
278+
describe('unpacker configuration', () => {
279+
test.each([
280+
[false, false],
281+
[false, true],
282+
[true, false],
283+
[true, true]
284+
])(
285+
'should create unpacker with disableLosslessIntegers=%p and useBigInt=%p',
286+
(disableLosslessIntegers, useBigInt) => {
287+
const protocol = new BoltProtocolV1(null, null, {
288+
disableLosslessIntegers,
289+
useBigInt
290+
})
291+
expect(protocol._unpacker._disableLosslessIntegers).toBe(
292+
disableLosslessIntegers
293+
)
294+
expect(protocol._unpacker._useBigInt).toBe(useBigInt)
295+
}
296+
)
297+
})
278298
})

test/internal/bolt/bolt-protocol-v2.test.js renamed to bolt-connection/test/bolt/bolt-protocol-v2.test.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,38 @@
1717
* limitations under the License.
1818
*/
1919

20-
import BoltProtocolV2 from '../../../bolt-connection/lib/bolt/bolt-protocol-v2'
20+
import BoltProtocolV2 from '../../src/bolt/bolt-protocol-v2'
2121
import utils from '../test-utils'
2222

2323
describe('#unit BoltProtocolV2', () => {
2424
beforeEach(() => {
25-
jasmine.addMatchers(utils.matchers)
25+
expect.extend(utils.matchers)
2626
})
2727

2828
it('should return correct bolt version number', () => {
2929
const protocol = new BoltProtocolV2(null, null, false)
3030

3131
expect(protocol.version).toBe(2)
3232
})
33+
34+
describe('unpacker configuration', () => {
35+
test.each([
36+
[false, false],
37+
[false, true],
38+
[true, false],
39+
[true, true]
40+
])(
41+
'should create unpacker with disableLosslessIntegers=%p and useBigInt=%p',
42+
(disableLosslessIntegers, useBigInt) => {
43+
const protocol = new BoltProtocolV2(null, null, {
44+
disableLosslessIntegers,
45+
useBigInt
46+
})
47+
expect(protocol._unpacker._disableLosslessIntegers).toBe(
48+
disableLosslessIntegers
49+
)
50+
expect(protocol._unpacker._useBigInt).toBe(useBigInt)
51+
}
52+
)
53+
})
3354
})

0 commit comments

Comments
 (0)