Skip to content

Commit

Permalink
feat(client-core): castNumerics option (cube-js#7123)
Browse files Browse the repository at this point in the history
  • Loading branch information
vasilev-alex authored Sep 12, 2023
1 parent 675a0a0 commit 9aed9ac
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 21 deletions.
6 changes: 5 additions & 1 deletion packages/cubejs-client-core/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,13 @@ declare module '@cubejs-client/core' {
*/
subscribe?: boolean;
/**
* A Cube.js API instance. If not provided will be taken from `CubeProvider`
* A Cube API instance. If not provided will be taken from `CubeProvider`
*/
cubejsApi?: CubejsApi;
/**
* If enabled, all members of the 'number' type will be automatically converted to numerical values on the client side
*/
castNumerics?: boolean;
/**
* Function that receives `ProgressResult` on each `Continue wait` message.
*/
Expand Down
57 changes: 42 additions & 15 deletions packages/cubejs-client-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,24 +257,51 @@ class CubejsApi {
* @returns ResultSet
* @private
*/
loadResponseInternal(response) {
loadResponseInternal(response, options = {}) {
if (
response.results.length &&
response.results[0].query.responseFormat &&
response.results[0].query.responseFormat === ResultType.COMPACT
response.results.length
) {
response.results.forEach((result, j) => {
const data = [];
result.data.dataset.forEach((r) => {
const row = {};
result.data.members.forEach((m, i) => {
row[m] = r[i];
if (options.castNumerics) {
response.results.forEach((result) => {
const numericMembers = Object.entries({
...result.annotation.measures,
...result.annotation.dimensions,
}).map(([k, v]) => {
if (v.type === 'number') {
return k;
}

return undefined;
}).filter(Boolean);

result.data = result.data.map((row) => {
numericMembers.forEach((key) => {
if (row[key] != null) {
row[key] = Number(row[key]);
}
});

return row;
});
data.push(row);
});
response.results[j].data = data;
});
}

if (response.results[0].query.responseFormat &&
response.results[0].query.responseFormat === ResultType.COMPACT) {
response.results.forEach((result, j) => {
const data = [];
result.data.dataset.forEach((r) => {
const row = {};
result.data.members.forEach((m, i) => {
row[m] = r[i];
});
data.push(row);
});
response.results[j].data = data;
});
}
}

return new ResultSet(response, {
parseDateMeasures: this.parseDateMeasures
});
Expand All @@ -293,7 +320,7 @@ class CubejsApi {
query,
queryType: 'multi',
}),
this.loadResponseInternal.bind(this),
(response) => this.loadResponseInternal(response, options),
options,
callback
);
Expand All @@ -312,7 +339,7 @@ class CubejsApi {
query,
queryType: 'multi',
}),
this.loadResponseInternal.bind(this),
(response) => this.loadResponseInternal(response, options),
{ ...options, subscribe: true },
callback
);
Expand Down
10 changes: 10 additions & 0 deletions packages/cubejs-client-react/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ declare module '@cubejs-client/react' {
QueryRecordType,
} from '@cubejs-client/core';

type CubeProviderOptions = {
castNumerics?: boolean;
}

type CubeProviderProps = {
cubejsApi: CubejsApi | null;
options?: CubeProviderOptions;
children: React.ReactNode;
};

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

type CubeContextProps = {
cubejsApi: CubejsApi;
options?: CubeProviderOptions;
};

/**
Expand Down Expand Up @@ -466,6 +472,10 @@ declare module '@cubejs-client/react' {
* When `true` the resultSet will be reset to `null` first
*/
resetResultSetOnChange?: boolean;
/**
* If enabled, all members of the 'number' type will be automatically converted to numerical values on the client side
*/
castNumerics?: boolean;
};

type UseCubeQueryResult<TData> = {
Expand Down
12 changes: 10 additions & 2 deletions packages/cubejs-client-react/src/CubeProvider.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import React from 'react';
import CubeContext from './CubeContext';

export default function CubeProvider({ cubejsApi, children }) {
return <CubeContext.Provider value={{ cubejsApi }}>{children}</CubeContext.Provider>;
export default function CubeProvider({ cubejsApi, children, options = {} }) {
return (
<CubeContext.Provider value={{
cubejsApi,
options
}}
>
{children}
</CubeContext.Provider>
);
}
7 changes: 4 additions & 3 deletions packages/cubejs-client-react/src/hooks/cube-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function useCubeQuery(query, options = {}) {
const cubejsApi = options.cubejsApi || context?.cubejsApi;

if (!cubejsApi) {
throw new Error('Cube.js API client is not provided');
throw new Error('Cube API client is not provided');
}

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

setError(null);
setLoading(true);

try {
const response = await cubejsApi.load(query, {
mutexObj: mutexRef.current,
mutexKey: 'query',
progressCallback,
castNumerics: Boolean(typeof options.castNumerics === 'boolean' ? options.castNumerics : context?.options?.castNumerics)
});

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

if (!cubejsApi) {
throw new Error('Cube.js API client is not provided');
throw new Error('Cube API client is not provided');
}

async function loadQuery() {
Expand Down

0 comments on commit 9aed9ac

Please sign in to comment.