Skip to content

Commit

Permalink
query method for raw data modal
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianmroz-allegro committed Feb 3, 2023
1 parent 3e539a3 commit 5511f71
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 13 deletions.
20 changes: 11 additions & 9 deletions src/client/modals/raw-data-modal/raw-data-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@

import { isDate } from "chronoshift";
import { List } from "immutable";
import { $, AttributeInfo, Dataset, Datum, Expression } from "plywood";
import { AttributeInfo, Dataset, Datum, Expression } from "plywood";
import React from "react";
import { ClientDataCube } from "../../../common/models/data-cube/data-cube";
import { findDimensionByName } from "../../../common/models/dimension/dimensions";
import { Essence } from "../../../common/models/essence/essence";
import { Locale } from "../../../common/models/locale/locale";
import { LIMIT } from "../../../common/models/raw-data-modal/raw-data-modal";
import { Stage } from "../../../common/models/stage/stage";
import { Timekeeper } from "../../../common/models/timekeeper/timekeeper";
import { formatFilterClause } from "../../../common/utils/formatter/formatter";
Expand All @@ -36,11 +37,11 @@ import { exportOptions, STRINGS } from "../../config/constants";
import { classNames } from "../../utils/dom/dom";
import { download, FileFormat, fileNameBase } from "../../utils/download/download";
import { getVisibleSegments } from "../../utils/sizing/sizing";
import { ApiContext, ApiContextValue } from "../../views/cube-view/api-context";
import "./raw-data-modal.scss";

const HEADER_HEIGHT = 30;
const ROW_HEIGHT = 30;
const LIMIT = 100;
const TIME_COL_WIDTH = 180;
const BOOLEAN_COL_WIDTH = 100;
const NUMBER_COL_WIDTH = 100;
Expand Down Expand Up @@ -83,7 +84,10 @@ function classFromAttribute(attribute: AttributeInfo): string {
}

export class RawDataModal extends React.Component<RawDataModalProps, RawDataModalState> {
static contextType = ApiContext;

public mounted: boolean;
context: ApiContextValue;

constructor(props: RawDataModalProps) {
super(props);
Expand All @@ -100,20 +104,18 @@ export class RawDataModal extends React.Component<RawDataModalProps, RawDataModa

componentDidMount() {
this.mounted = true;
const { essence, timekeeper } = this.props;
this.fetchData(essence, timekeeper);
const { essence } = this.props;
this.fetchData(essence);
}

componentWillUnmount() {
this.mounted = false;
}

fetchData(essence: Essence, timekeeper: Timekeeper): void {
const { dataCube } = essence;
const $main = $("main");
const query = $main.filter(essence.getEffectiveFilter(timekeeper).toExpression(dataCube)).limit(LIMIT);
fetchData(essence: Essence): void {
const { rawDataQuery } = this.context;
this.setState({ loading: true });
dataCube.executor(query, { timezone: essence.timezone })
rawDataQuery(essence)
.then(
(dataset: Dataset) => {
if (!this.mounted) return;
Expand Down
21 changes: 17 additions & 4 deletions src/client/views/cube-view/api-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ import React, { useContext } from "react";
import { ClientAppSettings } from "../../../common/models/app-settings/app-settings";
import { Dimension } from "../../../common/models/dimension/dimension";
import { Essence } from "../../../common/models/essence/essence";
import { Binary, Unary } from "../../../common/utils/functional/functional";
import { Binary, Nullary, Unary } from "../../../common/utils/functional/functional";
import { DEFAULT_VIEW_DEFINITION_VERSION, definitionConverters } from "../../../common/view-definitions";
import { Ajax } from "../../utils/ajax/ajax";

export type VisualizationQuery = Unary<Essence, Promise<Dataset>>;

export type RawDataQuery = Unary<Essence, Promise<Dataset>>;

export type BooleanFilterQuery = Binary<Essence, Dimension, Promise<Dataset>>;

export interface ApiContextValue {
visualizationQuery: VisualizationQuery;
booleanFilterQuery: BooleanFilterQuery;
rawDataQuery: RawDataQuery;
}

export const ApiContext = React.createContext<ApiContextValue>({
Expand All @@ -38,6 +41,9 @@ export const ApiContext = React.createContext<ApiContextValue>({
},
get visualizationQuery(): VisualizationQuery {
throw new Error("Attempted to consume ApiContext when there was no Provider");
},
get rawDataQuery(): RawDataQuery {
throw new Error("Attempted to consume ApiContext when there was no Provider");
}
});

Expand All @@ -49,13 +55,15 @@ interface QueryResponse {
result: DatasetJS;
}

type QueryEndpoints = "visualization" | "boolean-filter";
type QueryEndpoints = "visualization" | "boolean-filter" | "raw-data";

type ExtraParams = Record<string, unknown>;

type SerializeExtraBase = (...args: any[]) => ExtraParams;
type QueryFunction<T extends SerializeExtraBase> = (essence: Essence, ...args: Parameters<T>) => Promise<Dataset>;

const emptyParams: Nullary<ExtraParams> = () => ({});

function createApiCall<T extends SerializeExtraBase>(settings: ClientAppSettings, query: QueryEndpoints, serializeExtraParams: T): QueryFunction<T> {
const { oauth, clientTimeout: timeout } = settings;
const viewDefinitionVersion = DEFAULT_VIEW_DEFINITION_VERSION;
Expand All @@ -81,17 +89,22 @@ function createApiCall<T extends SerializeExtraBase>(settings: ClientAppSettings
const constructDataset = (res: QueryResponse) => Dataset.fromJS(res.result);

function createVizQueryApi(settings: ClientAppSettings): VisualizationQuery {
return createApiCall(settings, "visualization", () => ({}));
return createApiCall(settings, "visualization", emptyParams);
}

function createBooleanFilterQuery(settings: ClientAppSettings): BooleanFilterQuery {
return createApiCall(settings, "boolean-filter", (dimension: Dimension) => ({ dimension: dimension.name }));
}

function createRawDataQueryApi(settings: ClientAppSettings): RawDataQuery {
return createApiCall(settings, "raw-data", emptyParams);
}

function createApi(settings: ClientAppSettings): ApiContextValue {
return {
booleanFilterQuery: createBooleanFilterQuery(settings),
visualizationQuery: createVizQueryApi(settings)
visualizationQuery: createVizQueryApi(settings),
rawDataQuery: createRawDataQueryApi(settings)
};
}

Expand Down
16 changes: 16 additions & 0 deletions src/common/models/raw-data-modal/raw-data-modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2017-2022 Allegro.pl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const LIMIT = 100;
27 changes: 27 additions & 0 deletions src/server/routes/query/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { $, Expression } from "plywood";
import makeGridQuery from "../../../client/visualizations/grid/make-query";
import { Dimension } from "../../../common/models/dimension/dimension";
import { Essence } from "../../../common/models/essence/essence";
import { LIMIT } from "../../../common/models/raw-data-modal/raw-data-modal";
import { Timekeeper } from "../../../common/models/timekeeper/timekeeper";
import makeQuery from "../../../common/utils/query/visualization-query";
import { createEssence } from "../../utils/essence/create-essence";
Expand Down Expand Up @@ -58,6 +59,32 @@ export function queryRouter(settings: Pick<SettingsManager, "logger" | "getSourc
}
});

router.post("/raw-data", async (req: Request, res: Response) => {
function getQuery(essence: Essence, timekeeper: Timekeeper): Expression {
const { dataCube } = essence;
const $main = $("main");
const filterExpression = essence
.getEffectiveFilter(timekeeper)
.toExpression(dataCube);
return $main.filter(filterExpression).limit(LIMIT);
}

try {
const dataCube = await parseDataCube(req, settings);
const viewDefinition = parseViewDefinition(req);
const converter = parseViewDefinitionConverter(req);

const essence = createEssence(viewDefinition, converter, dataCube, settings.appSettings);

const query = getQuery(essence, settings.getTimekeeper());
const queryDecorator = getQueryDecorator(req, dataCube, settings);
const result = await executeQuery(dataCube, query, essence.timezone, queryDecorator);
res.json({ result });
} catch (error) {
handleRequestErrors(error, res, settings.logger);
}
});

router.post("/boolean-filter", async (req: Request, res: Response) => {
function getQuery(essence: Essence, dimension: Dimension, timekeeper: Timekeeper): Expression {
const { dataCube } = essence;
Expand Down

0 comments on commit 5511f71

Please sign in to comment.