This is an automated email from the ASF dual-hosted git repository. michaelsmolina pushed a commit to branch 4.0 in repository https://gitbox.apache.org/repos/asf/superset.git
commit 2ff3dcfd310a29ffc3edf065dd3a6bec4a9a552e Author: Spencer Torres <[email protected]> AuthorDate: Sat Apr 6 01:46:12 2024 -0400 fix(frontend): allow "constructor" property in response data (#25407) (cherry picked from commit a1983e468ba1a1b0fdbef9d8d5206e61be0b7141) --- .../src/connection/callApi/parseResponse.ts | 6 +++++- .../test/connection/callApi/parseResponse.test.ts | 12 ++++++++++-- superset-frontend/src/components/FilterableTable/index.tsx | 7 ++++++- superset/sql_parse.py | 2 +- tests/integration_tests/databases/api_tests.py | 14 +++++++------- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts b/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts index 82060d379b..52dc348084 100644 --- a/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts +++ b/superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts @@ -16,11 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -import JSONbig from 'json-bigint'; +import _JSONbig from 'json-bigint'; import { cloneDeepWith } from 'lodash'; import { ParseMethod, TextResponse, JsonResponse } from '../types'; +const JSONbig = _JSONbig({ + constructorAction: 'preserve', +}); + export default async function parseResponse<T extends ParseMethod = 'json'>( apiPromise: Promise<Response>, parseMethod?: T, diff --git a/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts b/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts index e13964ecf7..b08b5b8cb8 100644 --- a/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/connection/callApi/parseResponse.test.ts @@ -139,8 +139,12 @@ describe('parseResponse()', () => { it('resolves to big number value if `parseMethod=json-bigint`', async () => { const mockBigIntUrl = '/mock/get/bigInt'; - const mockGetBigIntPayload = - '{ "value": 9223372036854775807, "minus": { "value": -483729382918228373892, "str": "something" }, "number": 1234, "floatValue": { "plus": 0.3452211361231223, "minus": -0.3452211361231223 } }'; + const mockGetBigIntPayload = `{ + "value": 9223372036854775807, "minus": { "value": -483729382918228373892, "str": "something" }, + "number": 1234, "floatValue": { "plus": 0.3452211361231223, "minus": -0.3452211361231223 }, + "string.constructor": "data.constructor", + "constructor": "constructor" + }`; fetchMock.get(mockBigIntUrl, mockGetBigIntPayload); const responseBigNumber = await parseResponse( callApi({ url: mockBigIntUrl, method: 'GET' }), @@ -167,6 +171,10 @@ describe('parseResponse()', () => { expect(Math.abs(responseBigNumber.json.floatValue.minus)).toEqual( responseBigNumber.json.floatValue.plus, ); + expect(responseBigNumber.json['string.constructor']).toEqual( + 'data.constructor', + ); + expect(responseBigNumber.json.constructor).toEqual('constructor'); }); it('rejects if request.ok=false', async () => { diff --git a/superset-frontend/src/components/FilterableTable/index.tsx b/superset-frontend/src/components/FilterableTable/index.tsx index d731313bde..0ae4406de2 100644 --- a/superset-frontend/src/components/FilterableTable/index.tsx +++ b/superset-frontend/src/components/FilterableTable/index.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import JSONbig from 'json-bigint'; +import _JSONbig from 'json-bigint'; import React, { useEffect, useRef, useState, useMemo } from 'react'; import { getMultipleTextDimensions, styled } from '@superset-ui/core'; import { useDebounceValue } from 'src/hooks/useDebounceValue'; @@ -24,6 +24,11 @@ import { useCellContentParser } from './useCellContentParser'; import { renderResultCell } from './utils'; import { Table, TableSize } from '../Table'; +const JSONbig = _JSONbig({ + storeAsString: true, + constructorAction: 'preserve', +}); + const SCROLL_BAR_HEIGHT = 15; // This regex handles all possible number formats in javascript, including ints, floats, // exponential notation, NaN, and Infinity. diff --git a/superset/sql_parse.py b/superset/sql_parse.py index 9ef32899a5..d2e20f9cba 100644 --- a/superset/sql_parse.py +++ b/superset/sql_parse.py @@ -31,7 +31,7 @@ from jinja2 import nodes from sqlalchemy import and_ from sqlglot import exp, parse, parse_one from sqlglot.dialects import Dialects -from sqlglot.errors import SqlglotError +from sqlglot.errors import ParseError, SqlglotError from sqlglot.optimizer.scope import Scope, ScopeType, traverse_scope from sqlparse import keywords from sqlparse.lexer import Lexer diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py index 973772a4dc..5d644efa36 100644 --- a/tests/integration_tests/databases/api_tests.py +++ b/tests/integration_tests/databases/api_tests.py @@ -1479,7 +1479,7 @@ class TestDatabaseApi(SupersetTestCase): "indexes": [], "name": "wrong_table", "primaryKey": {"constrained_columns": None, "name": None}, - "selectStar": "SELECT\n *\nFROM wrong_table\nLIMIT 100\nOFFSET 0", + "selectStar": "SELECT *\nFROM wrong_table\nLIMIT 100\nOFFSET 0", }, ) elif example_db.backend == "mysql": @@ -2490,9 +2490,9 @@ class TestDatabaseApi(SupersetTestCase): uri = "api/v1/database/import/" masked_database_config = database_config.copy() - masked_database_config[ - "sqlalchemy_uri" - ] = "postgresql://username:XXXXXXXXXX@host:12345/db" + masked_database_config["sqlalchemy_uri"] = ( + "postgresql://username:XXXXXXXXXX@host:12345/db" + ) buf = BytesIO() with ZipFile(buf, "w") as bundle: @@ -2547,9 +2547,9 @@ class TestDatabaseApi(SupersetTestCase): uri = "api/v1/database/import/" masked_database_config = database_config.copy() - masked_database_config[ - "sqlalchemy_uri" - ] = "vertica+vertica_python://hackathon:XXXXXXXXXX@host:5433/dbname?ssl=1" + masked_database_config["sqlalchemy_uri"] = ( + "vertica+vertica_python://hackathon:XXXXXXXXXX@host:5433/dbname?ssl=1" + ) buf = BytesIO() with ZipFile(buf, "w") as bundle:
