Skip to content

Commit f0646a0

Browse files
authored
Fix Integer primitive type representation (#1045)
Given the scenario where: ```javascript const one = neo4j.int(1) const two = neo4j.int(2) ``` The following operations was resulting in string concatenation: ```javascript console.log( one + two ) // '12' console.log( 1 + one ) // '11' console.log( one.add(two).toInt() ) // 3, which is correct console.log( '1' + one ) // '11', correct ``` This is issue is solved by defining the method `Integer.valueOf` which defines the primitive type representation. The primitive representation of `Integer` is set as `BigInt`. This way: ```javascript console.log( one + two ) // 3n console.log( 1 + one ) // thrown an exception since we can not add bigint to number console.log( 1n + one ) // 2n console.log( -one ) // -1n console.log( '1' + one ) // '11', correct ```
1 parent 7f51f7f commit f0646a0

File tree

4 files changed

+122
-1
lines changed

4 files changed

+122
-1
lines changed

packages/core/src/integer.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,21 @@ class Integer {
197197
}
198198
}
199199

200+
/**
201+
* Converts the Integer to it primitive value.
202+
*
203+
* @since 5.4.0
204+
* @returns {bigint}
205+
*
206+
* @see {@link Integer#toBigInt}
207+
* @see {@link Integer#toInt}
208+
* @see {@link Integer#toNumber}
209+
* @see {@link Integer#toString}
210+
*/
211+
valueOf (): bigint {
212+
return this.toBigInt()
213+
}
214+
200215
/**
201216
* Gets the high 32 bits as a signed integer.
202217
* @returns {number} Signed high bits

packages/core/test/integer.test.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,97 @@ describe('Integer', () => {
370370
fc.assert(fc.property(fc.integer(), i => i.toString() === int(i).toString()))
371371
})
372372

373+
test('Integer.valueOf should be equivalent to the Integer.toBigInt', () => {
374+
fc.assert(
375+
fc.property(
376+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
377+
num => int(num).toBigInt() === int(num).valueOf()
378+
)
379+
)
380+
})
381+
382+
test('Integer should concatenate with a string', () => {
383+
fc.assert(
384+
fc.property(
385+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
386+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
387+
num => 'string' + int(num) + 'str' === 'string' + int(num).toString() + 'str'
388+
)
389+
)
390+
})
391+
392+
test('Integer should be able to be used in the string interpolation', () => {
393+
fc.assert(
394+
fc.property(
395+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
396+
num => `string${int(num)}str` === 'string' + int(num).toString() + 'str'
397+
)
398+
)
399+
})
400+
401+
test('Integer should be able to use + operator as bigint', () => {
402+
fc.assert(
403+
fc.property(
404+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
405+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
406+
(num1, num2) =>
407+
// @ts-expect-error
408+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
409+
num1 + int(num2) === num1 + num2 &&
410+
// @ts-expect-error
411+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
412+
int(num1) + num2 === num1 + num2 &&
413+
// @ts-expect-error
414+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
415+
int(num1) + int(num2) === num1 + num2
416+
))
417+
})
418+
419+
test('Integer should be able to use - operator as bigint', () => {
420+
fc.assert(
421+
fc.property(
422+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
423+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
424+
(num1, num2) =>
425+
// @ts-expect-error
426+
num1 - int(num2) === num1 - num2 &&
427+
// @ts-expect-error
428+
int(num1) - num2 === num1 - num2 &&
429+
// @ts-expect-error
430+
int(num1) - int(num2) === num1 - num2
431+
))
432+
})
433+
434+
test('Integer should be able to use * operator as bigint', () => {
435+
fc.assert(
436+
fc.property(
437+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
438+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
439+
(num1, num2) =>
440+
// @ts-expect-error
441+
num1 * int(num2) === num1 * num2 &&
442+
// @ts-expect-error
443+
int(num1) * num2 === num1 * num2 &&
444+
// @ts-expect-error
445+
int(num1) * int(num2) === num1 * num2
446+
))
447+
})
448+
449+
test('Integer should be able to use / operator as bigint', () => {
450+
fc.assert(
451+
fc.property(
452+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
453+
fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }).filter(n => n !== BigInt(0)),
454+
(num1, num2) =>
455+
// @ts-expect-error
456+
num1 / int(num2) === num1 / num2 &&
457+
// @ts-expect-error
458+
int(num1) / num2 === num1 / num2 &&
459+
// @ts-expect-error
460+
int(num1) / int(num2) === num1 / num2
461+
))
462+
})
463+
373464
test('int(string) should match int(Integer)', () => {
374465
fc.assert(fc.property(fc.integer(), i => int(i).equals(int(i.toString()))))
375466
})

packages/neo4j-driver-deno/lib/core/integer.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,21 @@ class Integer {
197197
}
198198
}
199199

200+
/**
201+
* Converts the Integer to it primitive value.
202+
*
203+
* @since 5.4.0
204+
* @returns {bigint}
205+
*
206+
* @see {@link Integer#toBigInt}
207+
* @see {@link Integer#toInt}
208+
* @see {@link Integer#toNumber}
209+
* @see {@link Integer#toString}
210+
*/
211+
valueOf (): bigint {
212+
return this.toBigInt()
213+
}
214+
200215
/**
201216
* Gets the high 32 bits as a signed integer.
202217
* @returns {number} Signed high bits

packages/neo4j-driver/test/internal/routing-table.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ describe('#unit RoutingTable', () => {
265265
}))
266266

267267
it('should return Integer.MAX_VALUE as expirationTime when ttl overflowed', async () => {
268-
const ttl = int(Integer.MAX_VALUE - 2)
268+
const ttl = int(Integer.MAX_VALUE - 2n)
269269
const routers = ['router:7699']
270270
const readers = ['reader1:7699', 'reader2:7699']
271271
const writers = ['writer1:7693', 'writer2:7692', 'writer3:7629']

0 commit comments

Comments
 (0)