@cubejs-client/react 1.7.13 → 1.7.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CubeContext.d.ts +35 -0
- package/dist/CubeContext.d.ts.map +1 -0
- package/dist/CubeProvider.d.ts +31 -0
- package/dist/CubeProvider.d.ts.map +1 -0
- package/dist/QueryBuilder.d.ts +135 -0
- package/dist/QueryBuilder.d.ts.map +1 -0
- package/dist/QueryRenderer.d.ts +34 -0
- package/dist/QueryRenderer.d.ts.map +1 -0
- package/dist/QueryRendererWithTotals.d.ts +4 -0
- package/dist/QueryRendererWithTotals.d.ts.map +1 -0
- package/dist/cubejs-client-react.cjs.js +248 -23
- package/dist/cubejs-client-react.cjs.js.map +1 -1
- package/dist/cubejs-client-react.esm.js +253 -31
- package/dist/cubejs-client-react.esm.js.map +1 -1
- package/dist/cubejs-client-react.umd.js +248 -23
- package/dist/cubejs-client-react.umd.js.map +1 -1
- package/dist/hooks/cube-fetch.d.ts +6 -0
- package/dist/hooks/cube-fetch.d.ts.map +1 -0
- package/dist/hooks/cube-meta.d.ts +4 -0
- package/dist/hooks/cube-meta.d.ts.map +1 -0
- package/dist/hooks/cube-query.d.ts +39 -0
- package/dist/hooks/cube-query.d.ts.map +1 -0
- package/dist/hooks/cube-sql.d.ts +12 -0
- package/dist/hooks/cube-sql.d.ts.map +1 -0
- package/dist/hooks/deep-compare-memoize.d.ts +2 -0
- package/dist/hooks/deep-compare-memoize.d.ts.map +1 -0
- package/dist/hooks/dry-run.d.ts +7 -0
- package/dist/hooks/dry-run.d.ts.map +1 -0
- package/dist/hooks/lazy-dry-run.d.ts +7 -0
- package/dist/hooks/lazy-dry-run.d.ts.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/types.d.ts +765 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +14 -10
- package/src/CubeContext.ts +37 -0
- package/src/CubeProvider.tsx +42 -0
- package/src/{QueryBuilder.jsx → QueryBuilder.tsx} +238 -89
- package/src/{QueryRenderer.jsx → QueryRenderer.tsx} +39 -14
- package/src/QueryRendererWithTotals.tsx +24 -0
- package/src/hooks/cube-fetch.ts +98 -0
- package/src/hooks/cube-meta.ts +8 -0
- package/src/hooks/{cube-query.js → cube-query.ts} +90 -14
- package/src/hooks/cube-sql.ts +22 -0
- package/src/hooks/{deep-compare-memoize.js → deep-compare-memoize.ts} +2 -2
- package/src/hooks/dry-run.ts +17 -0
- package/src/hooks/lazy-dry-run.ts +24 -0
- package/src/index.ts +77 -0
- package/src/types.ts +837 -0
- package/src/{utils.js → utils.ts} +3 -3
- package/index.d.ts +0 -697
- package/src/CubeContext.js +0 -3
- package/src/CubeProvider.jsx +0 -14
- package/src/QueryRendererWithTotals.jsx +0 -20
- package/src/hooks/cube-fetch.js +0 -66
- package/src/hooks/cube-meta.js +0 -5
- package/src/hooks/cube-sql.js +0 -8
- package/src/hooks/dry-run.js +0 -8
- package/src/hooks/lazy-dry-run.js +0 -11
- package/src/index.js +0 -18
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { equals, toPairs, fromPairs } from 'ramda';
|
|
3
3
|
import { isQueryPresent } from '@cubejs-client/core';
|
|
4
|
+
import type { CubeApi, LoadMethodOptions, Query, ResultSet } from '@cubejs-client/core';
|
|
4
5
|
|
|
5
6
|
import CubeContext from './CubeContext';
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
import type {
|
|
8
|
+
MutexObj,
|
|
9
|
+
QueryRendererLoadState,
|
|
10
|
+
QueryRendererProps,
|
|
11
|
+
QueryRendererRenderProps,
|
|
12
|
+
QueryRendererState,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `<QueryRenderer />` a react component that accepts a query, fetches the given query, and uses the render prop to render the resulting data
|
|
17
|
+
* @stickyTypes QueryRendererProps, QueryRendererRenderProps
|
|
18
|
+
* @noInheritDoc
|
|
19
|
+
*/
|
|
20
|
+
export default class QueryRenderer extends React.Component<QueryRendererProps, QueryRendererState> {
|
|
8
21
|
static contextType = CubeContext;
|
|
9
22
|
|
|
10
23
|
static defaultProps = {
|
|
@@ -19,11 +32,11 @@ export default class QueryRenderer extends React.Component {
|
|
|
19
32
|
};
|
|
20
33
|
|
|
21
34
|
// @deprecated use `isQueryPresent` from `@cubejs-client/core`
|
|
22
|
-
static isQueryPresent(query) {
|
|
35
|
+
static isQueryPresent(query: Query | Query[]) {
|
|
23
36
|
return isQueryPresent(query);
|
|
24
37
|
}
|
|
25
38
|
|
|
26
|
-
constructor(props) {
|
|
39
|
+
constructor(props: QueryRendererProps) {
|
|
27
40
|
super(props);
|
|
28
41
|
this.state = {};
|
|
29
42
|
this.mutexObj = {};
|
|
@@ -39,7 +52,7 @@ export default class QueryRenderer extends React.Component {
|
|
|
39
52
|
}
|
|
40
53
|
}
|
|
41
54
|
|
|
42
|
-
shouldComponentUpdate(nextProps, nextState) {
|
|
55
|
+
shouldComponentUpdate(nextProps: QueryRendererProps, nextState: QueryRendererState) {
|
|
43
56
|
const {
|
|
44
57
|
query, queries, render, cubeApi, loadSql, updateOnlyOnStateChange
|
|
45
58
|
} = this.props;
|
|
@@ -55,7 +68,7 @@ export default class QueryRenderer extends React.Component {
|
|
|
55
68
|
|| nextProps.updateOnlyOnStateChange !== updateOnlyOnStateChange;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
componentDidUpdate(prevProps) {
|
|
71
|
+
componentDidUpdate(prevProps: QueryRendererProps) {
|
|
59
72
|
const { query, queries } = this.props;
|
|
60
73
|
if (!equals(prevProps.query, query)) {
|
|
61
74
|
this.load(query);
|
|
@@ -66,12 +79,22 @@ export default class QueryRenderer extends React.Component {
|
|
|
66
79
|
}
|
|
67
80
|
}
|
|
68
81
|
|
|
69
|
-
|
|
82
|
+
// These sit after the lifecycle methods because `react/sort-comp` sorts
|
|
83
|
+
// TypeScript field declarations into `everything-else`, which the configured
|
|
84
|
+
// order puts after `lifecycle`. Runtime is unaffected: field initializers run
|
|
85
|
+
// right after `super()`, so the constructor's assignments still win.
|
|
86
|
+
//
|
|
87
|
+
// `this.context` is not re-declared: React types it as `any`, and a field
|
|
88
|
+
// declaration would be emitted at runtime and shadow the context React
|
|
89
|
+
// assigns.
|
|
90
|
+
private mutexObj: MutexObj;
|
|
91
|
+
|
|
92
|
+
cubeApi(): CubeApi {
|
|
70
93
|
// eslint-disable-next-line react/destructuring-assignment
|
|
71
94
|
return this.props.cubeApi || this.context && this.context.cubeApi;
|
|
72
95
|
}
|
|
73
96
|
|
|
74
|
-
load(query) {
|
|
97
|
+
load(query: Query | Query[]) {
|
|
75
98
|
const { resetResultSetOnChange, cache } = this.props;
|
|
76
99
|
this.setState({
|
|
77
100
|
isLoading: true,
|
|
@@ -82,7 +105,7 @@ export default class QueryRenderer extends React.Component {
|
|
|
82
105
|
const { loadSql } = this.props;
|
|
83
106
|
const cubeApi = this.cubeApi();
|
|
84
107
|
|
|
85
|
-
const loadOptions = {
|
|
108
|
+
const loadOptions: LoadMethodOptions = {
|
|
86
109
|
mutexObj: this.mutexObj,
|
|
87
110
|
mutexKey: 'query',
|
|
88
111
|
...(cache ? { cache } : {}),
|
|
@@ -121,7 +144,7 @@ export default class QueryRenderer extends React.Component {
|
|
|
121
144
|
}
|
|
122
145
|
}
|
|
123
146
|
|
|
124
|
-
loadQueries(queries) {
|
|
147
|
+
loadQueries(queries?: { [key: string]: Query }) {
|
|
125
148
|
const cubeApi = this.cubeApi();
|
|
126
149
|
const { resetResultSetOnChange, cache } = this.props;
|
|
127
150
|
this.setState({
|
|
@@ -130,12 +153,12 @@ export default class QueryRenderer extends React.Component {
|
|
|
130
153
|
error: null
|
|
131
154
|
});
|
|
132
155
|
|
|
133
|
-
const resultPromises = Promise.all(toPairs(queries).map(
|
|
156
|
+
const resultPromises = Promise.all(toPairs(queries as { [key: string]: Query }).map(
|
|
134
157
|
([name, query]) => cubeApi.load(query, {
|
|
135
158
|
mutexObj: this.mutexObj,
|
|
136
159
|
mutexKey: name,
|
|
137
160
|
...(cache ? { cache } : {}),
|
|
138
|
-
}).then(r => [name, r])
|
|
161
|
+
}).then((r): [string, ResultSet] => [name, r])
|
|
139
162
|
));
|
|
140
163
|
|
|
141
164
|
resultPromises
|
|
@@ -157,7 +180,7 @@ export default class QueryRenderer extends React.Component {
|
|
|
157
180
|
} = this.state;
|
|
158
181
|
const { render } = this.props;
|
|
159
182
|
|
|
160
|
-
const loadState = {
|
|
183
|
+
const loadState: QueryRendererLoadState = {
|
|
161
184
|
error: error ? new Error(error.response?.plainError || error.message || error.toString()) : null,
|
|
162
185
|
resultSet: queries ? (resultSet || {}) : resultSet,
|
|
163
186
|
loadingState: { isLoading },
|
|
@@ -165,7 +188,9 @@ export default class QueryRenderer extends React.Component {
|
|
|
165
188
|
};
|
|
166
189
|
|
|
167
190
|
if (render) {
|
|
168
|
-
|
|
191
|
+
// The prop is declared as returning `void` for backwards compatibility,
|
|
192
|
+
// while what it returns is what gets rendered
|
|
193
|
+
return render(loadState as QueryRendererRenderProps) as React.ReactNode;
|
|
169
194
|
}
|
|
170
195
|
|
|
171
196
|
return null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TimeDimension } from '@cubejs-client/core';
|
|
3
|
+
|
|
4
|
+
import QueryRenderer from './QueryRenderer';
|
|
5
|
+
import type { QueryRendererWithTotalsProps } from './types';
|
|
6
|
+
|
|
7
|
+
const QueryRendererWithTotals = ({ query, ...restProps }: QueryRendererWithTotalsProps) => (
|
|
8
|
+
<QueryRenderer
|
|
9
|
+
queries={{
|
|
10
|
+
// `granularity: null` is sent to the API on purpose to get totals
|
|
11
|
+
totals: {
|
|
12
|
+
...query,
|
|
13
|
+
dimensions: [],
|
|
14
|
+
timeDimensions: query.timeDimensions
|
|
15
|
+
? query.timeDimensions.map(td => ({ ...td, granularity: null }) as unknown as TimeDimension)
|
|
16
|
+
: undefined
|
|
17
|
+
},
|
|
18
|
+
main: query
|
|
19
|
+
}}
|
|
20
|
+
{...restProps}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export default QueryRendererWithTotals;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useContext, useEffect, useState, useRef } from 'react';
|
|
2
|
+
import { isQueryPresent } from '@cubejs-client/core';
|
|
3
|
+
import type { MetaMethodOptions, Query } from '@cubejs-client/core';
|
|
4
|
+
|
|
5
|
+
import CubeContext from '../CubeContext';
|
|
6
|
+
import useDeepCompareMemoize from './deep-compare-memoize';
|
|
7
|
+
import type {
|
|
8
|
+
CubeFetchArgs,
|
|
9
|
+
CubeFetchDispatch,
|
|
10
|
+
CubeFetchMethod,
|
|
11
|
+
CubeFetchState,
|
|
12
|
+
MutexObj,
|
|
13
|
+
UseCubeFetchInternalResult,
|
|
14
|
+
UseCubeFetchLoadOptions,
|
|
15
|
+
UseCubeFetchOptions,
|
|
16
|
+
UseCubeFetchResult,
|
|
17
|
+
} from '../types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @hidden
|
|
21
|
+
*/
|
|
22
|
+
export function useCubeFetch<T>(
|
|
23
|
+
method: CubeFetchMethod,
|
|
24
|
+
options?: UseCubeFetchOptions
|
|
25
|
+
): UseCubeFetchResult<T>;
|
|
26
|
+
|
|
27
|
+
export function useCubeFetch<T>(
|
|
28
|
+
method: CubeFetchMethod,
|
|
29
|
+
options: UseCubeFetchOptions = {}
|
|
30
|
+
): UseCubeFetchInternalResult<T> {
|
|
31
|
+
const context = useContext(CubeContext);
|
|
32
|
+
const mutexRef = useRef<MutexObj>({});
|
|
33
|
+
|
|
34
|
+
const [response, setResponse] = useState<CubeFetchState<T>>({
|
|
35
|
+
isLoading: false,
|
|
36
|
+
response: null,
|
|
37
|
+
});
|
|
38
|
+
const [error, setError] = useState<Error | null>(null);
|
|
39
|
+
|
|
40
|
+
const { skip = false } = options;
|
|
41
|
+
|
|
42
|
+
async function load(loadOptions: UseCubeFetchLoadOptions = {}, ignoreSkip = false) {
|
|
43
|
+
const cubeApi = options.cubeApi || context?.cubeApi;
|
|
44
|
+
const query = loadOptions.query || options.query;
|
|
45
|
+
const onlyViews = 'onlyViews' in loadOptions ? loadOptions.onlyViews : options.onlyViews;
|
|
46
|
+
|
|
47
|
+
const queryCondition = method === 'meta' ? true : query && isQueryPresent(query);
|
|
48
|
+
|
|
49
|
+
if (cubeApi && (ignoreSkip || !skip) && queryCondition) {
|
|
50
|
+
setError(null);
|
|
51
|
+
setResponse({
|
|
52
|
+
isLoading: true,
|
|
53
|
+
response: null,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const coreOptions: MetaMethodOptions = {
|
|
57
|
+
mutexObj: mutexRef.current,
|
|
58
|
+
mutexKey: method,
|
|
59
|
+
...(options.baseRequestId ? { baseRequestId: options.baseRequestId } : {}),
|
|
60
|
+
...(method === 'meta' && onlyViews ? { onlyViews: true } : {})
|
|
61
|
+
};
|
|
62
|
+
const args: CubeFetchArgs = method === 'meta' ? [coreOptions] : [query!, coreOptions];
|
|
63
|
+
// `method` picks between overloaded `CubeApi` methods, so the call is
|
|
64
|
+
// dispatched dynamically while keeping `cubeApi` as the receiver
|
|
65
|
+
const fetchMethod = cubeApi[method] as CubeFetchDispatch;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const fetchResponse = await fetchMethod.apply(cubeApi, args) as T;
|
|
69
|
+
|
|
70
|
+
setResponse({
|
|
71
|
+
response: fetchResponse,
|
|
72
|
+
isLoading: false,
|
|
73
|
+
});
|
|
74
|
+
} catch (fetchError) {
|
|
75
|
+
setError(fetchError as Error);
|
|
76
|
+
setResponse({
|
|
77
|
+
isLoading: false,
|
|
78
|
+
response: null,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
load();
|
|
86
|
+
// `order` is read off a single query; an array of queries does not carry it
|
|
87
|
+
}, useDeepCompareMemoize([
|
|
88
|
+
Object.keys((options.query as Query | undefined)?.order || {}),
|
|
89
|
+
options,
|
|
90
|
+
context,
|
|
91
|
+
]));
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
...response,
|
|
95
|
+
error,
|
|
96
|
+
refetch: (refetchOptions?: UseCubeFetchLoadOptions) => load(refetchOptions, true),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Meta } from '@cubejs-client/core';
|
|
2
|
+
|
|
3
|
+
import { useCubeFetch } from './cube-fetch';
|
|
4
|
+
import type { CubeMetaFetchOptions, UseCubeFetchResult } from '../types';
|
|
5
|
+
|
|
6
|
+
export function useCubeMeta(options: CubeMetaFetchOptions = {}): UseCubeFetchResult<Meta> {
|
|
7
|
+
return useCubeFetch<Meta>('meta', options);
|
|
8
|
+
}
|
|
@@ -1,21 +1,87 @@
|
|
|
1
1
|
import { useContext, useEffect, useState, useRef } from 'react';
|
|
2
2
|
import { isQueryPresent, areQueriesEqual } from '@cubejs-client/core';
|
|
3
|
+
import type {
|
|
4
|
+
DeeplyReadonly,
|
|
5
|
+
ProgressResponse,
|
|
6
|
+
Query,
|
|
7
|
+
QueryRecordType,
|
|
8
|
+
ResultSet,
|
|
9
|
+
UnsubscribeObj,
|
|
10
|
+
} from '@cubejs-client/core';
|
|
3
11
|
|
|
4
12
|
import CubeContext from '../CubeContext';
|
|
5
13
|
import useDeepCompareMemoize from './deep-compare-memoize';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
import type {
|
|
15
|
+
MutexObj,
|
|
16
|
+
ProgressCallback,
|
|
17
|
+
ProgressResultWithResponse,
|
|
18
|
+
ReadonlyQueryInput,
|
|
19
|
+
UseCubeQueryInternalResult,
|
|
20
|
+
UseCubeQueryOptions,
|
|
21
|
+
UseCubeQueryResult,
|
|
22
|
+
} from '../types';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A React hook for executing Cube.js queries
|
|
26
|
+
* ```js
|
|
27
|
+
* import React from 'react';
|
|
28
|
+
* import { Table } from 'antd';
|
|
29
|
+
* import { useCubeQuery } from '@cubejs-client/react';
|
|
30
|
+
*
|
|
31
|
+
* export default function App() {
|
|
32
|
+
* const { resultSet, isLoading, error, progress } = useCubeQuery({
|
|
33
|
+
* measures: ['Orders.count'],
|
|
34
|
+
* dimensions: ['Orders.createdAt.month'],
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* if (isLoading) {
|
|
38
|
+
* return <div>{progress?.stage || 'Loading...'}</div>;
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* if (error) {
|
|
42
|
+
* return <div>{error.toString()}</div>;
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* if (!resultSet) {
|
|
46
|
+
* return null;
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* const dataSource = resultSet.tablePivot();
|
|
50
|
+
* const columns = resultSet.tableColumns();
|
|
51
|
+
*
|
|
52
|
+
* return <Table columns={columns} dataSource={dataSource} />;
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* ```
|
|
56
|
+
* @order 1
|
|
57
|
+
* @stickyTypes
|
|
58
|
+
*/
|
|
59
|
+
export function useCubeQuery<
|
|
60
|
+
Data,
|
|
61
|
+
QueryInput extends ReadonlyQueryInput = ReadonlyQueryInput
|
|
62
|
+
>(
|
|
63
|
+
query: QueryInput,
|
|
64
|
+
options?: UseCubeQueryOptions
|
|
65
|
+
): UseCubeQueryResult<QueryInput, unknown extends Data ? QueryRecordType<QueryInput> : Data>;
|
|
66
|
+
|
|
67
|
+
export function useCubeQuery(
|
|
68
|
+
query: ReadonlyQueryInput,
|
|
69
|
+
options: UseCubeQueryOptions = {}
|
|
70
|
+
): UseCubeQueryInternalResult {
|
|
71
|
+
const mutexRef = useRef<MutexObj>({});
|
|
72
|
+
const [currentQuery, setCurrentQuery] = useState<ReadonlyQueryInput | null>(null);
|
|
10
73
|
const [isLoading, setLoading] = useState(!options.skip);
|
|
11
|
-
const [resultSet, setResultSet] = useState(null);
|
|
12
|
-
const [progress, setProgress] = useState(null);
|
|
13
|
-
const [error, setError] = useState(null);
|
|
74
|
+
const [resultSet, setResultSet] = useState<ResultSet | null>(null);
|
|
75
|
+
const [progress, setProgress] = useState<ProgressResponse | null>(null);
|
|
76
|
+
const [error, setError] = useState<Error | null>(null);
|
|
14
77
|
const context = useContext(CubeContext);
|
|
15
78
|
|
|
16
|
-
let subscribeRequest = null;
|
|
79
|
+
let subscribeRequest: UnsubscribeObj | null = null;
|
|
17
80
|
|
|
18
|
-
|
|
81
|
+
// `progressResponse` is not part of the public `ProgressResult` API
|
|
82
|
+
const progressCallback: ProgressCallback = (progressResult) => setProgress(
|
|
83
|
+
(progressResult as unknown as ProgressResultWithResponse).progressResponse
|
|
84
|
+
);
|
|
19
85
|
|
|
20
86
|
async function fetch() {
|
|
21
87
|
const { resetResultSetOnChange } = options;
|
|
@@ -43,8 +109,8 @@ export function useCubeQuery(query, options = {}) {
|
|
|
43
109
|
|
|
44
110
|
setResultSet(response);
|
|
45
111
|
setProgress(null);
|
|
46
|
-
} catch (
|
|
47
|
-
setError(
|
|
112
|
+
} catch (loadError) {
|
|
113
|
+
setError(loadError as Error);
|
|
48
114
|
setResultSet(null);
|
|
49
115
|
setProgress(null);
|
|
50
116
|
}
|
|
@@ -63,7 +129,11 @@ export function useCubeQuery(query, options = {}) {
|
|
|
63
129
|
|
|
64
130
|
async function loadQuery() {
|
|
65
131
|
if (!skip && isQueryPresent(query)) {
|
|
66
|
-
|
|
132
|
+
// `areQueriesEqual` is declared for a single query, and reads no more
|
|
133
|
+
// than `order` off one when given an array of queries
|
|
134
|
+
const previousQuery = currentQuery as DeeplyReadonly<Query> | null;
|
|
135
|
+
|
|
136
|
+
if (!areQueriesEqual(previousQuery, query as DeeplyReadonly<Query>)) {
|
|
67
137
|
if (resetResultSetOnChange == null || resetResultSetOnChange) {
|
|
68
138
|
setResultSet(null);
|
|
69
139
|
}
|
|
@@ -102,7 +172,7 @@ export function useCubeQuery(query, options = {}) {
|
|
|
102
172
|
await fetch();
|
|
103
173
|
}
|
|
104
174
|
} catch (e) {
|
|
105
|
-
setError(e);
|
|
175
|
+
setError(e as Error);
|
|
106
176
|
setResultSet(null);
|
|
107
177
|
setLoading(false);
|
|
108
178
|
setProgress(null);
|
|
@@ -118,7 +188,13 @@ export function useCubeQuery(query, options = {}) {
|
|
|
118
188
|
subscribeRequest = null;
|
|
119
189
|
}
|
|
120
190
|
};
|
|
121
|
-
|
|
191
|
+
// `order` is read off a single query; an array of queries does not carry it
|
|
192
|
+
}, useDeepCompareMemoize([
|
|
193
|
+
query,
|
|
194
|
+
Object.keys((query as DeeplyReadonly<Query> | undefined)?.order || {}),
|
|
195
|
+
options,
|
|
196
|
+
context,
|
|
197
|
+
]));
|
|
122
198
|
|
|
123
199
|
return {
|
|
124
200
|
isLoading,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DryRunResponse, Query, SqlQuery } from '@cubejs-client/core';
|
|
2
|
+
|
|
3
|
+
import { useCubeFetch } from './cube-fetch';
|
|
4
|
+
import type { UseCubeFetchOptions, UseCubeFetchResult } from '../types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The hook resolves with a `SqlQuery`, while its `response` stays declared as a
|
|
8
|
+
* dry-run response for backwards compatibility — `UseCubeSqlResult` spells the
|
|
9
|
+
* real shape. `refetch` is declared, as it is on `useDryRun` and `useCubeMeta`,
|
|
10
|
+
* because all three return the same object.
|
|
11
|
+
*
|
|
12
|
+
* @hidden
|
|
13
|
+
*/
|
|
14
|
+
export function useCubeSql(
|
|
15
|
+
query: Query | Query[],
|
|
16
|
+
options: UseCubeFetchOptions = {}
|
|
17
|
+
): UseCubeFetchResult<DryRunResponse> {
|
|
18
|
+
return useCubeFetch<SqlQuery>('sql', {
|
|
19
|
+
...options,
|
|
20
|
+
query
|
|
21
|
+
}) as unknown as UseCubeFetchResult<DryRunResponse>;
|
|
22
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useRef } from 'react';
|
|
2
2
|
import { equals } from 'ramda';
|
|
3
3
|
|
|
4
|
-
export default function useDeepCompareMemoize(value) {
|
|
5
|
-
const ref = useRef([]);
|
|
4
|
+
export default function useDeepCompareMemoize(value: unknown[]): unknown[] {
|
|
5
|
+
const ref = useRef<unknown[]>([]);
|
|
6
6
|
|
|
7
7
|
if (!equals(value, ref.current)) {
|
|
8
8
|
ref.current = value;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DryRunResponse, Query } from '@cubejs-client/core';
|
|
2
|
+
|
|
3
|
+
import { useCubeFetch } from './cube-fetch';
|
|
4
|
+
import type { UseCubeFetchOptions, UseCubeFetchResult } from '../types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @hidden
|
|
8
|
+
*/
|
|
9
|
+
export function useDryRun(
|
|
10
|
+
query: Query | Query[],
|
|
11
|
+
options: UseCubeFetchOptions = {}
|
|
12
|
+
): UseCubeFetchResult<DryRunResponse> {
|
|
13
|
+
return useCubeFetch<DryRunResponse>('dryRun', {
|
|
14
|
+
...options,
|
|
15
|
+
query,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DryRunResponse, Query } from '@cubejs-client/core';
|
|
2
|
+
|
|
3
|
+
import { useCubeFetch } from './cube-fetch';
|
|
4
|
+
import type {
|
|
5
|
+
CubeFetchResult,
|
|
6
|
+
UseCubeFetchLoadOptions,
|
|
7
|
+
UseCubeFetchOptions,
|
|
8
|
+
} from '../types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @hidden
|
|
12
|
+
*/
|
|
13
|
+
export function useLazyDryRun(
|
|
14
|
+
query?: Query | Query[],
|
|
15
|
+
options: UseCubeFetchOptions = {}
|
|
16
|
+
): [(loadOptions?: UseCubeFetchLoadOptions) => Promise<void>, CubeFetchResult<DryRunResponse>] {
|
|
17
|
+
const { refetch, ...result } = useCubeFetch<DryRunResponse>('dryRun', {
|
|
18
|
+
...options,
|
|
19
|
+
query,
|
|
20
|
+
skip: true
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return [refetch, result];
|
|
24
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title @cubejs-client/react
|
|
3
|
+
* @permalink /@cubejs-client-react
|
|
4
|
+
* @menuCategory Reference
|
|
5
|
+
* @subcategory Frontend
|
|
6
|
+
* @menuOrder 3
|
|
7
|
+
* @description `@cubejs-client/react` provides React Components for easy Cube.js integration in a React app.
|
|
8
|
+
*/
|
|
9
|
+
import QueryRenderer from './QueryRenderer';
|
|
10
|
+
import QueryRendererWithTotals from './QueryRendererWithTotals';
|
|
11
|
+
import QueryBuilder from './QueryBuilder';
|
|
12
|
+
import CubeProvider from './CubeProvider';
|
|
13
|
+
import CubeContext from './CubeContext';
|
|
14
|
+
|
|
15
|
+
export * from './hooks/cube-sql';
|
|
16
|
+
export * from './hooks/dry-run';
|
|
17
|
+
export * from './hooks/lazy-dry-run';
|
|
18
|
+
export * from './hooks/cube-query';
|
|
19
|
+
export * from './hooks/cube-meta';
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
AvailableCube,
|
|
23
|
+
AvailableMembers,
|
|
24
|
+
ChartType,
|
|
25
|
+
CubeContextProps,
|
|
26
|
+
CubeFetchOptions,
|
|
27
|
+
CubeFetchResult,
|
|
28
|
+
CubeMetaFetchOptions,
|
|
29
|
+
CubeProviderOptions,
|
|
30
|
+
CubeProviderProps,
|
|
31
|
+
DimensionUpdater,
|
|
32
|
+
FilterExtraFields,
|
|
33
|
+
FilterUpdateFields,
|
|
34
|
+
FilterUpdater,
|
|
35
|
+
FilterWithExtraFields,
|
|
36
|
+
GranularityOption,
|
|
37
|
+
GranularityOptions,
|
|
38
|
+
LoadLazyDryRunOptions,
|
|
39
|
+
MeasureUpdater,
|
|
40
|
+
MemberUpdater,
|
|
41
|
+
OrderUpdater,
|
|
42
|
+
PivotConfigExtraUpdateFields,
|
|
43
|
+
PivotConfigUpdater,
|
|
44
|
+
PivotConfigUpdaterArgs,
|
|
45
|
+
QueryBuilderProps,
|
|
46
|
+
QueryBuilderRenderProps,
|
|
47
|
+
QueryBuilderState,
|
|
48
|
+
QueryRendererProps,
|
|
49
|
+
QueryRendererRenderProps,
|
|
50
|
+
QueryRendererWithTotalsProps,
|
|
51
|
+
ReadonlyQueryInput,
|
|
52
|
+
SchemaChangeProps,
|
|
53
|
+
SegmentUpdater,
|
|
54
|
+
TimeDimensionComparisonUpdateFields,
|
|
55
|
+
TimeDimensionExtraFields,
|
|
56
|
+
TimeDimensionRangedUpdateFields,
|
|
57
|
+
TimeDimensionUpdater,
|
|
58
|
+
TimeDimensionWithExtraFields,
|
|
59
|
+
TLoadingState,
|
|
60
|
+
UseCubeFetchLoadOptions,
|
|
61
|
+
UseCubeFetchOptions,
|
|
62
|
+
UseCubeFetchResult,
|
|
63
|
+
UseCubeQueryOptions,
|
|
64
|
+
UseCubeQueryResult,
|
|
65
|
+
UseCubeSqlResponse,
|
|
66
|
+
UseCubeSqlResult,
|
|
67
|
+
UseDryRunResult,
|
|
68
|
+
VizState,
|
|
69
|
+
} from './types';
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
QueryRenderer,
|
|
73
|
+
QueryRendererWithTotals,
|
|
74
|
+
QueryBuilder,
|
|
75
|
+
CubeContext,
|
|
76
|
+
CubeProvider,
|
|
77
|
+
};
|