Skip to content

Instantly share code, notes, and snippets.

@philippefutureboy
Created January 14, 2020 01:07
Show Gist options
  • Save philippefutureboy/1ccbd14ec4d877b744bd1eacfe397c91 to your computer and use it in GitHub Desktop.
Save philippefutureboy/1ccbd14ec4d877b744bd1eacfe397c91 to your computer and use it in GitHub Desktop.
Cube.js Client Wrapper Gist
import cube from '../../../../../../utils/cube';
export default cube.ql`
{
"measures": [
"Patient.count"
],
"timeDimensions": [],
"dimensions": [
"Patient.ageGroup"
],
"filters": [
{
"member": "Patient.referrerName",
"operator": "equals",
"values": {{{rowRollupKeys}}}
},
{
"member": "FileOpeningCalendar.fiscalYear",
"operator": "equals",
"values": ["{{currentFiscalYear}}"]
},
{
"member": "FileOpeningCalendar.monthsInFiscalYear",
"operator": "lte",
"values": ["{{currentMonthInFiscalYear}}"]
}
],
"order": {
"Patient.ageGroup": "asc"
}
}
`;
import Mustache from 'mustache';
function ql(strings, ...args) {
const template = strings.raw
.map((s, i) => (i === strings.length - 1 ? s : s + args[i]))
.join('')
// adding double quotes for keys that are not quotes-enclosed
.replace(
/(\s+)(\w+):\s*(.*)/g,
(match, space, key, rest) => `${space}"${key}": ${rest}`
);
function queryql(client, context = {}) {
const renderedString = Mustache.render(
template.replace(/\r?\n/g, ''),
context
);
let query;
try {
query = JSON.parse(renderedString);
} catch (err) {
const match = err.message.match(/position\s+(\d+)/);
let position;
if (match !== null) {
position = parseInt(match[1], 10);
}
err.position = position;
err.before = renderedString.substr(position - 14, position + 1);
err.after = renderedString.substr(position, position + 15);
err.template = template;
throw err;
}
return client.load(query);
}
return queryql;
}
const createExecuteQueryAction = (payload) => ({
type: 'CUBE::EXECUTE_QUERY',
payload,
});
function query({ name, query }) {
return async (dispatch, state, client) => {
const { context } = state;
const data = await query(client, context);
dispatch(createExecuteQueryAction({ name, data }));
};
}
const createSetContextAction = (payload) => ({
type: 'CUBE::SET_CONTEXT',
payload,
});
function setContext(fn) {
return async (dispatch, state, client) => {
const context = await fn(state);
dispatch(createSetContextAction(context));
};
}
function all(...fns) {
return (dispatch, state, client) =>
Promise.all(fns.map((fn) => fn(dispatch, state, client)));
}
const createReduceAction = (payload) => ({
type: 'CUBE::REDUCE',
payload,
});
function reduce(fn) {
return async (dispatch, state, client) => {
const newState = await fn(state);
dispatch(createReduceAction(newState));
};
}
function cubePipeReducer(state, action) {
if (action.type === 'CUBE::EXECUTE_QUERY') {
const { name, data } = action.payload;
return {
...state,
data: {
...state.data,
[name]: data,
},
};
} else if (action.type === 'CUBE::SET_CONTEXT') {
const context = action.payload;
return {
...state,
context,
};
} else if (action.type === 'CUBE::REDUCE') {
return action.payload;
}
return state;
}
function pipe(...fns) {
return async (client, context) => {
let state = { data: {}, context };
function dispatch(action) {
state = cubePipeReducer(state, action);
}
for (const fn of fns) {
await fn(dispatch, state, client);
}
return state;
};
}
export default {
ql,
query,
setContext,
pipe,
all,
reduce,
};
import React from 'react';
import * as R from 'ramda';
import cube from '../../utils/cube';
import TableContainer from './Table';
import { getAllResultSetDataFromResultSetDict } from '../../utils/cube.utils';
import {
sortByRowRollupValue,
sumColumnRollupRecordsToGrandTotalRecord,
} from '../helpers/rollupOrderedPatientAgeGroupDrilldownTableHelpers';
const createRollupOrderedDrilldownTableCubePipeline = ({
queries,
rowKeyProp,
}) => {
const { columnRollupQuery, rowRollupQuery, drillDownQuery } = queries;
return cube.pipe(
cube.query({
name: 'rowRollup',
query: rowRollupQuery,
}),
cube.setContext(({ data, context }) => {
const { rowRollup } = data;
const rowRollupKeys = rowRollup.loadResponse.data.map(R.prop(rowKeyProp));
return {
...context,
rowRollupKeys: JSON.stringify(rowRollupKeys),
};
}),
cube.all(
cube.query({
name: 'columnRollup',
query: columnRollupQuery,
}),
cube.query({
name: 'drillDown',
query: drillDownQuery,
})
)
);
};
// omitted createRollupOrderedDrilldownTableStateReducer
export default function RollupOrderedDrilldownTable({
columns,
queries: { rowRollupQuery, columnRollupQuery, drillDownQuery },
factProp,
rowKeyProp,
columnKeyProp,
grandTotalRecordReducer,
sortBy,
context,
}) {
return (
<TableContainer
columns={columns}
shouldAlternateRowBgColor={false}
query={createRollupOrderedDrilldownTableCubePipeline({
queries: {
rowRollupQuery,
columnRollupQuery,
drillDownQuery,
},
rowKeyProp,
})}
stateReducer={createRollupOrderedDrilldownTableStateReducer({
factProp,
rowKeyProp,
columnKeyProp,
sortBy,
grandTotalRecordReducer,
})}
context={context}
/>
);
}
import cube from '../../../../../../utils/cube';
export default cube.ql`
{
"measures": [
"Patient.count"
],
"timeDimensions": [],
"dimensions": [
"Patient.referrerName"
],
"filters": [
{
"member": "FileOpeningCalendar.fiscalYear",
"operator": "equals",
"values": ["{{currentFiscalYear}}"]
},
{
"member": "FileOpeningCalendar.monthsInFiscalYear",
"operator": "lte",
"values": ["{{currentMonthInFiscalYear}}"]
}
],
"order": {
"Patient.count": "desc"
},
"limit": 5
}
`;
import React from 'react';
import { getCubejsClient } from './cubejs.utils';
export default function useCubeJSAnalytics({ query, context }) {
const [result, setResult] = React.useState({
data: null,
isLoading: true,
error: null,
query,
context,
});
// call the api
React.useEffect(() => {
async function asyncEffect() {
try {
const cubejsClient = await getCubejsClient();
const resultSet = await query(cubejsClient, context);
setResult({
data: resultSet,
isLoading: false,
error: null,
query,
context,
});
} catch (error) {
console.error('useCubeJSAnalyticsError', error);
if (typeof error.position === 'number') {
console.error({
position: error.position,
before: error.before.replace(/\s+/g, ' '),
after: error.after.replace(/\s+/g, ' '),
});
console.error(error.template);
}
console.error(context);
setResult({
data: null,
isLoading: false,
error,
query,
context,
});
}
}
asyncEffect();
}, [query, context]);
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment