From daa869baf08b72369ffa8a49136dc5299b6a4b9b Mon Sep 17 00:00:00 2001 From: Antonio Barcelos Date: Mon, 2 Jan 2023 13:08:48 +0100 Subject: [PATCH 1/5] Fix Integer primitive type representation Given the scenarion 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 ``` --- packages/core/src/integer.ts | 15 ++++++++++ packages/core/test/integer.test.ts | 28 +++++++++++++++++++ .../neo4j-driver-deno/lib/core/integer.ts | 15 ++++++++++ 3 files changed, 58 insertions(+) diff --git a/packages/core/src/integer.ts b/packages/core/src/integer.ts index 458871e78..43536a245 100644 --- a/packages/core/src/integer.ts +++ b/packages/core/src/integer.ts @@ -197,6 +197,21 @@ class Integer { } } + /** + * Converts the Integer to it primitive value. + * + * @since 5.4.0 + * @returns {bigint} + * + * @see {@link Integer#toBigInt} + * @see {@link Integer#toInt} + * @see {@link Integer#toNumber} + * @see {@link Integer#toString} + */ + valueOf (): bigint { + return this.toBigInt() + } + /** * Gets the high 32 bits as a signed integer. * @returns {number} Signed high bits diff --git a/packages/core/test/integer.test.ts b/packages/core/test/integer.test.ts index bacefcccd..5b5302033 100644 --- a/packages/core/test/integer.test.ts +++ b/packages/core/test/integer.test.ts @@ -370,6 +370,34 @@ describe('Integer', () => { fc.assert(fc.property(fc.integer(), i => i.toString() === int(i).toString())) }) + test('Integer.valueOf should be equivalent to the Integer.toBigInt', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + num => int(num).toBigInt() === int(num).valueOf() + ) + ) + }) + + test('Integer should concatenate with a string', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + num => 'string' + int(num) + 'str' === 'string' + int(num).toString() + 'str' + ) + ) + }) + + test('Integer should be able to used in the string interpolation', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + num => `string${int(num)}str` === 'string' + int(num).toString() + 'str' + ) + ) + }) + test('int(string) should match int(Integer)', () => { fc.assert(fc.property(fc.integer(), i => int(i).equals(int(i.toString())))) }) diff --git a/packages/neo4j-driver-deno/lib/core/integer.ts b/packages/neo4j-driver-deno/lib/core/integer.ts index 3f70960ed..13105c988 100644 --- a/packages/neo4j-driver-deno/lib/core/integer.ts +++ b/packages/neo4j-driver-deno/lib/core/integer.ts @@ -197,6 +197,21 @@ class Integer { } } + /** + * Converts the Integer to it primitive value. + * + * @since 5.4.0 + * @returns {bigint} + * + * @see {@link Integer#toBigInt} + * @see {@link Integer#toInt} + * @see {@link Integer#toNumber} + * @see {@link Integer#toString} + */ + valueOf (): bigint { + return this.toBigInt() + } + /** * Gets the high 32 bits as a signed integer. * @returns {number} Signed high bits From 00237c89288916d394b6597439a258881dc2359b Mon Sep 17 00:00:00 2001 From: Antonio Barcelos Date: Mon, 2 Jan 2023 14:25:45 +0100 Subject: [PATCH 2/5] Fix test code --- packages/neo4j-driver/test/internal/routing-table.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neo4j-driver/test/internal/routing-table.test.js b/packages/neo4j-driver/test/internal/routing-table.test.js index d88ba12cf..a58c0f503 100644 --- a/packages/neo4j-driver/test/internal/routing-table.test.js +++ b/packages/neo4j-driver/test/internal/routing-table.test.js @@ -265,7 +265,7 @@ describe('#unit RoutingTable', () => { })) it('should return Integer.MAX_VALUE as expirationTime when ttl overflowed', async () => { - const ttl = int(Integer.MAX_VALUE - 2) + const ttl = int(Integer.MAX_VALUE - 2n) const routers = ['router:7699'] const readers = ['reader1:7699', 'reader2:7699'] const writers = ['writer1:7693', 'writer2:7692', 'writer3:7629'] From f8fdb0ae1cf5101cadd963597f25d1a746835d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Barc=C3=A9los?= Date: Mon, 2 Jan 2023 14:47:23 +0100 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Florent Biville <445792+fbiville@users.noreply.github.com> --- packages/core/test/integer.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/test/integer.test.ts b/packages/core/test/integer.test.ts index 5b5302033..475a929a1 100644 --- a/packages/core/test/integer.test.ts +++ b/packages/core/test/integer.test.ts @@ -389,7 +389,7 @@ describe('Integer', () => { ) }) - test('Integer should be able to used in the string interpolation', () => { + test('Integer should be able to be used in the string interpolation', () => { fc.assert( fc.property( fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), From 2c2177a502da369e77aad2da10dc513839bbd80b Mon Sep 17 00:00:00 2001 From: Antonio Barcelos Date: Mon, 2 Jan 2023 18:32:30 +0100 Subject: [PATCH 4/5] Add tests tests for bigint operators --- packages/core/test/integer.test.ts | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/core/test/integer.test.ts b/packages/core/test/integer.test.ts index 475a929a1..8fafd1f96 100644 --- a/packages/core/test/integer.test.ts +++ b/packages/core/test/integer.test.ts @@ -398,6 +398,70 @@ describe('Integer', () => { ) }) + test('Integer should be able to use + operator as bigint', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + (num1, num2) => + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + num1 + int(num2) === num1 + num2 && + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + int(num1) + num2 === num1 + num2 && + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + int(num1) + int(num2) === num1 + num2 + )) + }) + + test('Integer should be able to use - operator as bigint', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + (num1, num2) => + // @ts-expect-error + num1 - int(num2) === num1 - num2 && + // @ts-expect-error + int(num1) - num2 === num1 - num2 && + // @ts-expect-error + int(num1) - int(num2) === num1 - num2 + )) + }) + + test('Integer should be able to use * operator as bigint', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + (num1, num2) => + // @ts-expect-error + num1 * int(num2) === num1 * num2 && + // @ts-expect-error + int(num1) * num2 === num1 * num2 && + // @ts-expect-error + int(num1) * int(num2) === num1 * num2 + )) + }) + + test('Integer should be able to use / operator as bigint', () => { + fc.assert( + fc.property( + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + (num1, num2) => + // @ts-expect-error + num1 / int(num2) === num1 / num2 && + // @ts-expect-error + int(num1) / num2 === num1 / num2 && + // @ts-expect-error + int(num1) / int(num2) === num1 / num2 + )) + }) + + test('int(string) should match int(Integer)', () => { fc.assert(fc.property(fc.integer(), i => int(i).equals(int(i.toString())))) }) From db0f859942d1273211ba00a29d187ec42a24a773 Mon Sep 17 00:00:00 2001 From: Antonio Barcelos Date: Mon, 2 Jan 2023 20:40:31 +0100 Subject: [PATCH 5/5] Filtering division by 0 --- packages/core/test/integer.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/test/integer.test.ts b/packages/core/test/integer.test.ts index 8fafd1f96..f3bc8a3d8 100644 --- a/packages/core/test/integer.test.ts +++ b/packages/core/test/integer.test.ts @@ -450,7 +450,7 @@ describe('Integer', () => { fc.assert( fc.property( fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), - fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }), + fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }).filter(n => n !== BigInt(0)), (num1, num2) => // @ts-expect-error num1 / int(num2) === num1 / num2 && @@ -461,7 +461,6 @@ describe('Integer', () => { )) }) - test('int(string) should match int(Integer)', () => { fc.assert(fc.property(fc.integer(), i => int(i).equals(int(i.toString())))) })