From 1d6ef0c19ea78c14d430ef9b455593dc233e369f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Mu=C3=B1oz?= Date: Thu, 10 Oct 2024 12:13:53 +0200 Subject: [PATCH 1/3] Handle BigInt numbers from API --- packages/react-api/package.json | 3 ++- packages/react-api/src/api/common.js | 6 +++++- yarn.lock | 7 +++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 2231919cd..8f289ab3e 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -65,7 +65,8 @@ "webpack-cli": "^4.5.0" }, "dependencies": { - "@babel/runtime": "^7.13.9" + "@babel/runtime": "^7.13.9", + "json-bigint": "^1.0.0" }, "peerDependencies": { "@carto/react-core": "^3.1.0-alpha.1", diff --git a/packages/react-api/src/api/common.js b/packages/react-api/src/api/common.js index 7bd3522d0..57c27a35d 100644 --- a/packages/react-api/src/api/common.js +++ b/packages/react-api/src/api/common.js @@ -1,4 +1,5 @@ import { InvalidColumnError } from '@carto/react-core/'; +import JSONbig from 'json-bigint'; /** * Return more descriptive error from API @@ -51,7 +52,10 @@ export async function makeCall({ url, credentials, opts }) { signal: opts?.abortController?.signal, ...opts?.otherOptions }); - data = await response.json(); + + // Parse with JSONbig to automatically handle large numbers as BigInt + const text = await response.text(); + data = JSONbig.parse(text); } catch (error) { if (error.name === 'AbortError') throw error; diff --git a/yarn.lock b/yarn.lock index a115fe5f6..8a10ff0d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12430,6 +12430,13 @@ json-bigint@^0.3.0: dependencies: bignumber.js "^9.0.0" +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" From 91917987b5f39d0fd1b56459819254e7178470ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Mu=C3=B1oz?= Date: Thu, 10 Oct 2024 15:03:22 +0200 Subject: [PATCH 2/3] Use JSON Reviver instead of json-bigint library --- packages/react-api/__tests__/api/lds.test.js | 2 +- .../react-api/__tests__/api/stats.test.js | 23 +++++++++++++++---- packages/react-api/package.json | 3 +-- packages/react-api/src/api/common.js | 12 ++++++++-- yarn.lock | 7 ------ 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/react-api/__tests__/api/lds.test.js b/packages/react-api/__tests__/api/lds.test.js index 7c222baf5..4f1f04f26 100644 --- a/packages/react-api/__tests__/api/lds.test.js +++ b/packages/react-api/__tests__/api/lds.test.js @@ -18,7 +18,7 @@ describe('lds', () => { const fetchMock = (global.fetch = jest.fn().mockImplementation(async () => { return { ok: true, - json: async () => [{ value: [someCoordinates] }] + text: async () => JSON.stringify({ value: [someCoordinates] }) }; })); diff --git a/packages/react-api/__tests__/api/stats.test.js b/packages/react-api/__tests__/api/stats.test.js index a3e0a21ee..ec488c4f0 100644 --- a/packages/react-api/__tests__/api/stats.test.js +++ b/packages/react-api/__tests__/api/stats.test.js @@ -86,7 +86,7 @@ describe('stats', () => { const fetchMock = (global.fetch = jest.fn().mockImplementation(async () => { return { ok: true, - json: async () => TABLE_TEST.output + text: async () => JSON.stringify(TABLE_TEST.output) }; })); @@ -117,7 +117,7 @@ describe('stats', () => { const fetchMock = (global.fetch = jest.fn().mockImplementation(async () => { return { ok: true, - json: async () => QUERY_TEST.output + text: async () => JSON.stringify(QUERY_TEST.output) }; })); @@ -149,7 +149,7 @@ describe('stats', () => { const fetchMock = (global.fetch = jest.fn().mockImplementation(async () => { return { ok: true, - json: async () => QUERY_TEST.output + text: async () => JSON.stringify(QUERY_TEST.output) }; })); @@ -187,7 +187,7 @@ describe('stats', () => { const fetchMock = (global.fetch = jest.fn().mockImplementation(async () => { return { ok: true, - json: async () => QUERY_TEST.output + text: async () => JSON.stringify(QUERY_TEST.output) }; })); @@ -225,5 +225,20 @@ describe('stats', () => { expect(res).toEqual(TILESET_TEST.output); expect(mockedGetTileJson).toBeCalledWith({ source: TILESET_TEST.input.source }); }); + + test('BigInt numbers are correctly parsed', async () => { + const jsonWithBigInt = '{"rows": [{"quadbin":5256683984082960383}]}'; + + const fetchMock = (global.fetch = jest.fn().mockImplementation(async () => { + return { + ok: true, + text: async () => jsonWithBigInt + }; + })); + + const res = await getStats({ source: QUERY_SOURCE, column: 'injuries' }); + + expect(res.rows[0].quadbin).toEqual(BigInt(5256683984082960383)); + }); }); }); diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 8f289ab3e..2231919cd 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -65,8 +65,7 @@ "webpack-cli": "^4.5.0" }, "dependencies": { - "@babel/runtime": "^7.13.9", - "json-bigint": "^1.0.0" + "@babel/runtime": "^7.13.9" }, "peerDependencies": { "@carto/react-core": "^3.1.0-alpha.1", diff --git a/packages/react-api/src/api/common.js b/packages/react-api/src/api/common.js index 57c27a35d..1133aad2c 100644 --- a/packages/react-api/src/api/common.js +++ b/packages/react-api/src/api/common.js @@ -1,5 +1,14 @@ import { InvalidColumnError } from '@carto/react-core/'; import JSONbig from 'json-bigint'; +import JSON5 from 'json5'; + +// Widgets API may return BigInt values, and JSON.parse does not handle them properly, so we need to use a reviver +const bigIntReviver = (key, value) => { + if (typeof value === 'number' && value > Number.MAX_SAFE_INTEGER) { + return BigInt(value); + } + return value; +}; /** * Return more descriptive error from API @@ -53,9 +62,8 @@ export async function makeCall({ url, credentials, opts }) { ...opts?.otherOptions }); - // Parse with JSONbig to automatically handle large numbers as BigInt const text = await response.text(); - data = JSONbig.parse(text); + data = JSON.parse(text, bigIntReviver); } catch (error) { if (error.name === 'AbortError') throw error; diff --git a/yarn.lock b/yarn.lock index 8a10ff0d3..a115fe5f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12430,13 +12430,6 @@ json-bigint@^0.3.0: dependencies: bignumber.js "^9.0.0" -json-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" - integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== - dependencies: - bignumber.js "^9.0.0" - json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" From 6a75fc40d89177c8a9d2f079f9aa170144caf0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Mu=C3=B1oz?= Date: Thu, 10 Oct 2024 15:31:09 +0200 Subject: [PATCH 3/3] Fix ESLint rule and wrong imports --- .eslintrc.json | 5 ++++- packages/react-api/src/api/common.js | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 5e603ecd1..7571aa1f1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,6 @@ { - "extends": "react-app" + "extends": "react-app", + "env": { + "es2020": true + } } diff --git a/packages/react-api/src/api/common.js b/packages/react-api/src/api/common.js index 1133aad2c..0b46d328a 100644 --- a/packages/react-api/src/api/common.js +++ b/packages/react-api/src/api/common.js @@ -1,6 +1,4 @@ import { InvalidColumnError } from '@carto/react-core/'; -import JSONbig from 'json-bigint'; -import JSON5 from 'json5'; // Widgets API may return BigInt values, and JSON.parse does not handle them properly, so we need to use a reviver const bigIntReviver = (key, value) => {