From 2f9edd3b0e2a286775aa04074410895ac8fd40bb Mon Sep 17 00:00:00 2001 From: "JUST.in DO IT" Date: Wed, 12 Mar 2025 09:47:41 -0700 Subject: [PATCH] fix(dashboard): Support bigint value in native filters (#32549) (cherry picked from commit e7721a8c4d283bdc8e048875c1062f04d1597072) --- .../src/connection/callApi/parseResponse.ts | 19 ++++++++++++----- .../superset-ui-core/src/query/types/Query.ts | 6 +++--- .../src/query/types/QueryResponse.ts | 2 +- .../formatters/finestTemporalGrain.test.ts | 8 +++++++ .../formatters/finestTemporalGrain.ts | 4 ++++ .../src/BigNumber/BigNumberViz.tsx | 1 + .../src/Heatmap/transformProps.ts | 2 +- .../plugins/plugin-chart-echarts/src/types.ts | 2 +- .../plugin-chart-echarts/src/utils/series.ts | 2 +- .../plugin-chart-echarts/test/index.test.ts | 2 +- .../Select/SelectFilterPlugin.test.tsx | 21 +++++++++++++++++++ superset-frontend/src/filters/utils.ts | 3 +++ 12 files changed, 59 insertions(+), 13 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 52dc3480841..931aeecbdd8 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 @@ -57,11 +57,20 @@ export default async function parseResponse( const json = JSONbig.parse(rawData); const result: JsonResponse = { response, - // `json-bigint` could not handle floats well, see sidorares/json-bigint#62 - // TODO: clean up after json-bigint>1.0.1 is released - json: cloneDeepWith(json, (value: any) => - value?.isInteger?.() === false ? Number(value) : undefined, - ), + json: cloneDeepWith(json, (value: any) => { + // `json-bigint` could not handle floats well, see sidorares/json-bigint#62 + // TODO: clean up after json-bigint>1.0.1 is released + if (value?.isInteger?.() === false) { + return Number(value); + } + if ( + value?.isGreaterThan?.(Number.MAX_SAFE_INTEGER) || + value?.isLessThan?.(Number.MIN_SAFE_INTEGER) + ) { + return BigInt(value); + } + return undefined; + }), }; return result as ReturnType; } diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts b/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts index 4a5f2a68590..49fc4b4363c 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/Query.ts @@ -31,7 +31,7 @@ import { Maybe } from '../../types'; import { PostProcessingRule } from './PostProcessing'; import { JsonObject } from '../../connection'; import { TimeGranularity } from '../../time-format'; -import { GenericDataType } from './QueryResponse'; +import { GenericDataType, DataRecordValue } from './QueryResponse'; export type BaseQueryObjectFilterClause = { col: QueryFormColumn; @@ -41,13 +41,13 @@ export type BaseQueryObjectFilterClause = { export type BinaryQueryObjectFilterClause = BaseQueryObjectFilterClause & { op: BinaryOperator; - val: string | number | boolean; + val: DataRecordValue; formattedVal?: string; }; export type SetQueryObjectFilterClause = BaseQueryObjectFilterClause & { op: SetOperator; - val: (string | number | boolean)[]; + val: DataRecordValue[]; formattedVal?: string[]; }; diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts index b2a3c08cdfe..2e8943cff17 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts @@ -33,7 +33,7 @@ export enum GenericDataType { /** * Primitive types for data field values. */ -export type DataRecordValue = number | string | boolean | Date | null; +export type DataRecordValue = number | string | boolean | Date | null | bigint; export interface DataRecord { [key: string]: DataRecordValue; diff --git a/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.test.ts b/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.test.ts index 6e4f07df4b8..0afd7e850f4 100644 --- a/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.test.ts +++ b/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.test.ts @@ -60,4 +60,12 @@ test('finestTemporalGrain', () => { expect(localTimeFormatter(new Date('2003-01-01 00:00:00Z').getTime())).toBe( '2002-12-31 19:00', ); + + const bigIntFormatter = finestTemporalGrain([ + BigInt(1234567890123456789n), + BigInt(1234567890123456789n), + ]); + expect(bigIntFormatter(new Date('2003-01-01 00:00:00Z').getTime())).toBe( + '2003', + ); }); diff --git a/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.ts b/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.ts index c03b7ec1593..c3213f1cf93 100644 --- a/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.ts +++ b/superset-frontend/packages/superset-ui-core/src/time-format/formatters/finestTemporalGrain.ts @@ -48,7 +48,11 @@ export default function finestTemporalGrain( } = useLocalTime ? localTimeUtils : utcUtils; let formatFunc = formatYear; + values.forEach((value: any) => { + if (typeof value === 'bigint') { + return; + } if (formatFunc === formatYear && isNotFirstMonth(value)) { formatFunc = formatMonth; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx index d7882ccdb6c..d95ae633af0 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx @@ -98,6 +98,7 @@ class BigNumberVis extends PureComponent { !formatTime || !showTimestamp || typeof timestamp === 'string' || + typeof timestamp === 'bigint' || typeof timestamp === 'boolean' ) return null; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts index 5a3cd758700..b4b826f3961 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts @@ -148,7 +148,7 @@ export default function transformProps( if (!value) { return NULL_STRING; } - if (typeof value === 'boolean') { + if (typeof value === 'boolean' || typeof value === 'bigint') { return String(value); } return value; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts index 02adce8cc57..294437c7454 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts @@ -183,7 +183,7 @@ export class EchartsChartPlugin< super({ ...restProps, metadata: new ChartMetadata({ - parseMethod: 'json', + parseMethod: 'json-bigint', ...metadata, }), }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts index bbf222a2a5a..ef10fb9d3ba 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts @@ -363,7 +363,7 @@ export function formatSeriesName( if (name === undefined || name === null) { return NULL_STRING; } - if (typeof name === 'boolean') { + if (typeof name === 'boolean' || typeof name === 'bigint') { return name.toString(); } if (name instanceof Date || coltype === GenericDataType.Temporal) { diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/index.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/index.test.ts index 7061dc89076..da0e8d2cb10 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/index.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/index.test.ts @@ -125,6 +125,6 @@ test('@superset-ui/plugin-chart-echarts-parsemethod-validation', () => { ]; plugins.forEach(plugin => { - expect(plugin.metadata.parseMethod).toEqual('json'); + expect(plugin.metadata.parseMethod).toEqual('json-bigint'); }); }); diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx index b66642caf68..f73ee6b5787 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx @@ -239,4 +239,25 @@ describe('SelectFilterPlugin', () => { // One call for the search term and other for the empty search expect(setDataMask).toHaveBeenCalledTimes(2); }); + + test('Select big int value', async () => { + const bigValue = 1100924931345932234n; + render( + // @ts-ignore + , + ); + userEvent.click(screen.getByRole('combobox')); + expect(await screen.findByRole('combobox')).toBeInTheDocument(); + await userEvent.type(screen.getByRole('combobox'), '1'); + expect(screen.queryByLabelText(String(bigValue))).toBeInTheDocument(); + }); }); diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts index 859f68f9cea..e08f5b93b77 100644 --- a/superset-frontend/src/filters/utils.ts +++ b/superset-frontend/src/filters/utils.ts @@ -117,6 +117,9 @@ export function getDataRecordFormatter({ if (typeof value === 'string') { return value; } + if (typeof value === 'bigint') { + return String(value); + } if (timeFormatter && dtype === GenericDataType.Temporal) { return timeFormatter(value); }