Skip to content

Commit 9aed9ac

Browse files
authored
feat(client-core): castNumerics option (#7123)
1 parent 675a0a0 commit 9aed9ac

File tree

5 files changed

+71
-21
lines changed

5 files changed

+71
-21
lines changed

packages/cubejs-client-core/index.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,13 @@ declare module '@cubejs-client/core' {
9696
*/
9797
subscribe?: boolean;
9898
/**
99-
* A Cube.js API instance. If not provided will be taken from `CubeProvider`
99+
* A Cube API instance. If not provided will be taken from `CubeProvider`
100100
*/
101101
cubejsApi?: CubejsApi;
102+
/**
103+
* If enabled, all members of the 'number' type will be automatically converted to numerical values on the client side
104+
*/
105+
castNumerics?: boolean;
102106
/**
103107
* Function that receives `ProgressResult` on each `Continue wait` message.
104108
*/

packages/cubejs-client-core/src/index.js

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -257,24 +257,51 @@ class CubejsApi {
257257
* @returns ResultSet
258258
* @private
259259
*/
260-
loadResponseInternal(response) {
260+
loadResponseInternal(response, options = {}) {
261261
if (
262-
response.results.length &&
263-
response.results[0].query.responseFormat &&
264-
response.results[0].query.responseFormat === ResultType.COMPACT
262+
response.results.length
265263
) {
266-
response.results.forEach((result, j) => {
267-
const data = [];
268-
result.data.dataset.forEach((r) => {
269-
const row = {};
270-
result.data.members.forEach((m, i) => {
271-
row[m] = r[i];
264+
if (options.castNumerics) {
265+
response.results.forEach((result) => {
266+
const numericMembers = Object.entries({
267+
...result.annotation.measures,
268+
...result.annotation.dimensions,
269+
}).map(([k, v]) => {
270+
if (v.type === 'number') {
271+
return k;
272+
}
273+
274+
return undefined;
275+
}).filter(Boolean);
276+
277+
result.data = result.data.map((row) => {
278+
numericMembers.forEach((key) => {
279+
if (row[key] != null) {
280+
row[key] = Number(row[key]);
281+
}
282+
});
283+
284+
return row;
272285
});
273-
data.push(row);
274286
});
275-
response.results[j].data = data;
276-
});
287+
}
288+
289+
if (response.results[0].query.responseFormat &&
290+
response.results[0].query.responseFormat === ResultType.COMPACT) {
291+
response.results.forEach((result, j) => {
292+
const data = [];
293+
result.data.dataset.forEach((r) => {
294+
const row = {};
295+
result.data.members.forEach((m, i) => {
296+
row[m] = r[i];
297+
});
298+
data.push(row);
299+
});
300+
response.results[j].data = data;
301+
});
302+
}
277303
}
304+
278305
return new ResultSet(response, {
279306
parseDateMeasures: this.parseDateMeasures
280307
});
@@ -293,7 +320,7 @@ class CubejsApi {
293320
query,
294321
queryType: 'multi',
295322
}),
296-
this.loadResponseInternal.bind(this),
323+
(response) => this.loadResponseInternal(response, options),
297324
options,
298325
callback
299326
);
@@ -312,7 +339,7 @@ class CubejsApi {
312339
query,
313340
queryType: 'multi',
314341
}),
315-
this.loadResponseInternal.bind(this),
342+
(response) => this.loadResponseInternal(response, options),
316343
{ ...options, subscribe: true },
317344
callback
318345
);

packages/cubejs-client-react/index.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@ declare module '@cubejs-client/react' {
3434
QueryRecordType,
3535
} from '@cubejs-client/core';
3636

37+
type CubeProviderOptions = {
38+
castNumerics?: boolean;
39+
}
40+
3741
type CubeProviderProps = {
3842
cubejsApi: CubejsApi | null;
43+
options?: CubeProviderOptions;
3944
children: React.ReactNode;
4045
};
4146

@@ -69,6 +74,7 @@ declare module '@cubejs-client/react' {
6974

7075
type CubeContextProps = {
7176
cubejsApi: CubejsApi;
77+
options?: CubeProviderOptions;
7278
};
7379

7480
/**
@@ -466,6 +472,10 @@ declare module '@cubejs-client/react' {
466472
* When `true` the resultSet will be reset to `null` first
467473
*/
468474
resetResultSetOnChange?: boolean;
475+
/**
476+
* If enabled, all members of the 'number' type will be automatically converted to numerical values on the client side
477+
*/
478+
castNumerics?: boolean;
469479
};
470480

471481
type UseCubeQueryResult<TData> = {
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import React from 'react';
22
import CubeContext from './CubeContext';
33

4-
export default function CubeProvider({ cubejsApi, children }) {
5-
return <CubeContext.Provider value={{ cubejsApi }}>{children}</CubeContext.Provider>;
4+
export default function CubeProvider({ cubejsApi, children, options = {} }) {
5+
return (
6+
<CubeContext.Provider value={{
7+
cubejsApi,
8+
options
9+
}}
10+
>
11+
{children}
12+
</CubeContext.Provider>
13+
);
614
}

packages/cubejs-client-react/src/hooks/cube-query.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export function useCubeQuery(query, options = {}) {
2424
const cubejsApi = options.cubejsApi || context?.cubejsApi;
2525

2626
if (!cubejsApi) {
27-
throw new Error('Cube.js API client is not provided');
27+
throw new Error('Cube API client is not provided');
2828
}
2929

3030
if (resetResultSetOnChange) {
@@ -33,12 +33,13 @@ export function useCubeQuery(query, options = {}) {
3333

3434
setError(null);
3535
setLoading(true);
36-
36+
3737
try {
3838
const response = await cubejsApi.load(query, {
3939
mutexObj: mutexRef.current,
4040
mutexKey: 'query',
4141
progressCallback,
42+
castNumerics: Boolean(typeof options.castNumerics === 'boolean' ? options.castNumerics : context?.options?.castNumerics)
4243
});
4344

4445
if (isMounted()) {
@@ -64,7 +65,7 @@ export function useCubeQuery(query, options = {}) {
6465
const cubejsApi = options.cubejsApi || context?.cubejsApi;
6566

6667
if (!cubejsApi) {
67-
throw new Error('Cube.js API client is not provided');
68+
throw new Error('Cube API client is not provided');
6869
}
6970

7071
async function loadQuery() {

0 commit comments

Comments
 (0)