diff --git a/src/client/components/filter-menu/number-filter-menu/number-filter-menu.mocha.tsx b/src/client/components/filter-menu/number-filter-menu/number-filter-menu.mocha.tsx deleted file mode 100644 index 28499ac38..000000000 --- a/src/client/components/filter-menu/number-filter-menu/number-filter-menu.mocha.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015-2016 Imply Data, Inc. - * Copyright 2017-2019 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. - */ - -import { expect } from "chai"; -import React from "react"; -import * as TestUtils from "react-dom/test-utils"; -import { DimensionFixtures } from "../../../../common/models/dimension/dimension.fixtures"; -import { EssenceFixtures } from "../../../../common/models/essence/essence.fixtures"; -import { StageFixtures } from "../../../../common/models/stage/stage.fixtures"; -import { TimekeeperFixtures } from "../../../../common/models/timekeeper/timekeeper.fixtures"; -import { findDOMNode, renderIntoDocument } from "../../../utils/test-utils"; -import { NumberFilterMenu } from "./number-filter-menu"; - -describe("NumberFilterMenu", () => { - const div = document.createElement("div"); - div.setAttribute("id", "Div1"); - - it("adds the correct class", () => { - const renderedComponent = renderIntoDocument( - - ); - - expect(TestUtils.isCompositeComponent(renderedComponent), "should be composite").to.equal(true); - expect(findDOMNode(renderedComponent).className, "should contain class").to.contain("number-filter-menu"); - }); - -}); diff --git a/src/client/components/number-range-picker/number-range-picker.mocha.tsx b/src/client/components/number-range-picker/number-range-picker.mocha.tsx deleted file mode 100644 index cd5498a24..000000000 --- a/src/client/components/number-range-picker/number-range-picker.mocha.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015-2016 Imply Data, Inc. - * Copyright 2017-2019 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. - */ - -import { expect } from "chai"; -import React from "react"; -import * as TestUtils from "react-dom/test-utils"; -import { DimensionFixtures } from "../../../common/models/dimension/dimension.fixtures"; -import { EssenceFixtures } from "../../../common/models/essence/essence.fixtures"; -import { TimekeeperFixtures } from "../../../common/models/timekeeper/timekeeper.fixtures"; -import { findDOMNode, renderIntoDocument } from "../../utils/test-utils"; -import { NumberRangePicker } from "./number-range-picker"; - -describe("NumberRangePicker", () => { - it("adds the correct class", () => { - const renderedComponent = renderIntoDocument( - - ); - - expect(TestUtils.isCompositeComponent(renderedComponent), "should be composite").to.equal(true); - expect(findDOMNode(renderedComponent).className, "should contain class").to.contain("number-range-picker"); - }); - -}); diff --git a/src/client/components/number-range-picker/number-range-picker.tsx b/src/client/components/number-range-picker/number-range-picker.tsx index 0e2898807..d864eab41 100644 --- a/src/client/components/number-range-picker/number-range-picker.tsx +++ b/src/client/components/number-range-picker/number-range-picker.tsx @@ -15,13 +15,14 @@ * limitations under the License. */ -import { $, Dataset, ply } from "plywood"; +import { Dataset } from "plywood"; import React from "react"; import { Dimension } from "../../../common/models/dimension/dimension"; import { Essence } from "../../../common/models/essence/essence"; import { Timekeeper } from "../../../common/models/timekeeper/timekeeper"; import { getNumberOfWholeDigits, isTruthy, toSignificantDigits } from "../../../common/utils/general/general"; import { clamp, classNames, getXFromEvent } from "../../utils/dom/dom"; +import { ApiContext, ApiContextValue } from "../../views/cube-view/api-context"; import { Loader } from "../loader/loader"; import { QueryError } from "../query-error/query-error"; import { RangeHandle } from "../range-handle/range-handle"; @@ -72,6 +73,9 @@ export interface NumberRangePickerState { } export class NumberRangePicker extends React.Component { + static contextType = ApiContext; + + context: ApiContextValue; public mounted: boolean; private picker = React.createRef(); @@ -87,19 +91,12 @@ export class NumberRangePicker extends React.Component { if (!this.mounted) return; diff --git a/src/client/views/cube-view/api-context.tsx b/src/client/views/cube-view/api-context.tsx index 39eec84dd..e4a2b36ee 100644 --- a/src/client/views/cube-view/api-context.tsx +++ b/src/client/views/cube-view/api-context.tsx @@ -32,14 +32,21 @@ export type RawDataQuery = Unary>; export type BooleanFilterQuery = Binary>; export type StringFilterQuery = Binary>; + +export type NumberFilterQuery = Binary>; + export interface ApiContextValue { visualizationQuery: VisualizationQuery; booleanFilterQuery: BooleanFilterQuery; rawDataQuery: RawDataQuery; stringFilterQuery: StringFilterQuery; + numberFilterQuery: NumberFilterQuery; } export const ApiContext = React.createContext({ + get numberFilterQuery(): NumberFilterQuery { + throw new Error("Attempted to consume ApiContext when there was no Provider"); + }, get booleanFilterQuery(): BooleanFilterQuery { throw new Error("Attempted to consume ApiContext when there was no Provider"); }, @@ -62,7 +69,7 @@ interface QueryResponse { result: DatasetJS; } -type QueryEndpoints = "visualization" | "boolean-filter" | "string-filter" | "number-filter" | "raw-data"; +type QueryEndpoints = "visualization" | "pinboard" | "boolean-filter" | "string-filter" | "number-filter" | "raw-data"; type ExtraParams = Record; @@ -97,6 +104,10 @@ function createVizQueryApi(settings: ClientAppSettings): VisualizationQuery { return createApiCall(settings, "visualization", emptyParams); } +function createNumberFilterQuery(settings: ClientAppSettings): NumberFilterQuery { + return createApiCall(settings, "number-filter", (dimension: Dimension) => ({ dimension: dimension.name })); +} + function createBooleanFilterQuery(settings: ClientAppSettings): BooleanFilterQuery { return createApiCall(settings, "boolean-filter", (dimension: Dimension) => ({ dimension: dimension.name })); } @@ -114,6 +125,7 @@ function createRawDataQueryApi(settings: ClientAppSettings): RawDataQuery { function createApi(settings: ClientAppSettings): ApiContextValue { return { + numberFilterQuery: createNumberFilterQuery(settings), booleanFilterQuery: createBooleanFilterQuery(settings), visualizationQuery: createVizQueryApi(settings), rawDataQuery: createRawDataQueryApi(settings), diff --git a/src/common/utils/functional/functional.ts b/src/common/utils/functional/functional.ts index c44d9922f..ff730673a 100644 --- a/src/common/utils/functional/functional.ts +++ b/src/common/utils/functional/functional.ts @@ -119,10 +119,10 @@ export function range(from: number, to: number): number[] { } // TODO: fix to use infer on arguments tuple https://stackoverflow.com/a/50014868/1089761 -export function debounceWithPromise any>(fn: T, ms: number): ((...args: any[]) => Promise) & { cancel: Fn } { +export function debounceWithPromise Promise>(fn: T, ms: number): ((...args: Parameters) => Promise) & { cancel: Fn } { let timeoutId: any; - const debouncedFn = (...args: any[]) => { + const debouncedFn = (...args: Parameters) => { let resolve: Function; const promise = new Promise(pResolve => { resolve = pResolve; diff --git a/src/server/routes/query/query.ts b/src/server/routes/query/query.ts index 3ac460456..8cf3a96d7 100644 --- a/src/server/routes/query/query.ts +++ b/src/server/routes/query/query.ts @@ -154,7 +154,36 @@ export function queryRouter(settings: Pick { + + function getQuery(essence: Essence, dimension: Dimension, timekeeper: Timekeeper): Expression { + const { dataCube } = essence; + const filterExpression = essence + .getEffectiveFilter(timekeeper, { unfilterDimension: dimension }) + .toExpression(dataCube); + const $main = $("main"); + return ply() + .apply("main", $main.filter(filterExpression)) + .apply("Min", $main.min($(dimension.name))) + .apply("Max", $main.max($(dimension.name))); + } + + try { + const dataCube = await parseDataCube(req, settings); + const viewDefinition = parseViewDefinition(req); + const dimension = parseDimension(req, dataCube); + const essence = createEssence(viewDefinition, converter, dataCube, settings.appSettings); + + const query = getQuery(essence, dimension, 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); }