From f713739dea2ae075183b057cad6b1914090c3f38 Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Mon, 13 Feb 2023 14:01:35 +0100 Subject: [PATCH 1/8] add logger to query router context --- src/common/logger/logger.ts | 10 +++++----- src/server/routes/query/query.ts | 8 ++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/common/logger/logger.ts b/src/common/logger/logger.ts index 08639c966..b1e6ef43b 100644 --- a/src/common/logger/logger.ts +++ b/src/common/logger/logger.ts @@ -19,7 +19,7 @@ import { noop, Unary } from "../utils/functional/functional"; import { isNil } from "../utils/general/general"; import { isoNow } from "../utils/time/time"; -type LogFn = (msg: string, extra?: Record) => void; +type LogFn = (msg: string, extra?: Record) => void; type LogLevel = "INFO" | "WARN" | "ERROR"; export function errorToMessage(error: Error): string { @@ -41,7 +41,7 @@ class JSONLogger implements Logger { constructor(private logger = "turnilo") { } - private logMessage(level: LogLevel, message: string, extra: Record = {}) { + private logMessage(level: LogLevel, message: string, extra: Record = {}) { console.log(JSON.stringify({ message, level, @@ -51,15 +51,15 @@ class JSONLogger implements Logger { })); } - log(message: string, extra: Record = {}) { + log(message: string, extra: Record = {}) { this.logMessage("INFO", message, extra); } - error(message: string, extra: Record = {}) { + error(message: string, extra: Record = {}) { this.logMessage("ERROR", message, extra); } - warn(message: string, extra: Record = {}) { + warn(message: string, extra: Record = {}) { this.logMessage("WARN", message, extra); } diff --git a/src/server/routes/query/query.ts b/src/server/routes/query/query.ts index e88f06453..9ef62a774 100644 --- a/src/server/routes/query/query.ts +++ b/src/server/routes/query/query.ts @@ -15,6 +15,7 @@ */ import { NextFunction, Request, Response, Router } from "express"; +import { Logger } from "../../../common/logger/logger"; import { QueryableDataCube } from "../../../common/models/data-cube/queryable-data-cube"; import { Essence } from "../../../common/models/essence/essence"; import { Timekeeper } from "../../../common/models/timekeeper/timekeeper"; @@ -40,6 +41,7 @@ interface QueryRouterContext { essence: Essence; decorator: AppliedQueryDecorator; timekeeper: Timekeeper; + logger: Logger; } export type QueryRouterRequest = Request & { @@ -47,6 +49,7 @@ export type QueryRouterRequest = Request & { }; export function queryRouter(settings: Pick) { + const logger = settings.logger; const router = Router(); @@ -57,6 +60,7 @@ export function queryRouter(settings: Pick { - handleRequestErrors(error, res, settings.logger); + router.use((error: Error, { context }: QueryRouterRequest, res: Response, next: NextFunction) => { + handleRequestErrors(error, res, context.logger); }); return router; From 4bbd75df95042a828ebf69358c04dabea282a94a Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Mon, 13 Feb 2023 14:01:43 +0100 Subject: [PATCH 2/8] log information for viz query --- .../routes/query/routes/visualization.ts | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/server/routes/query/routes/visualization.ts b/src/server/routes/query/routes/visualization.ts index 1887ae935..1f0aa78eb 100644 --- a/src/server/routes/query/routes/visualization.ts +++ b/src/server/routes/query/routes/visualization.ts @@ -14,10 +14,13 @@ * limitations under the License. */ +import { Duration } from "chronoshift"; import { Response } from "express"; import { Expression } from "plywood"; import makeGridQuery from "../../../../client/visualizations/grid/make-query"; +import { Logger } from "../../../../common/logger/logger"; import { Essence } from "../../../../common/models/essence/essence"; +import { FixedTimeFilterClause } from "../../../../common/models/filter-clause/filter-clause"; import { Timekeeper } from "../../../../common/models/timekeeper/timekeeper"; import makeQuery from "../../../../common/utils/query/visualization-query"; import { executeQuery } from "../../../utils/query/execute-query"; @@ -27,8 +30,52 @@ function getQuery(essence: Essence, timekeeper: Timekeeper): Expression { return essence.visualization.name === "grid" ? makeGridQuery(essence, timekeeper) : makeQuery(essence, timekeeper); } +function start(clause: FixedTimeFilterClause): string { + return clause.values.first().start.toUTCString(); +} + +function intervalLength(clause: FixedTimeFilterClause): number { + const timeRange = clause.values.first(); + return timeRange.end.getTime() - timeRange.start.getTime(); +} + +function timeVariables(essence: Essence, timekeeper: Timekeeper): Record { + const timeFilter = essence.currentTimeFilter(timekeeper); + const timeDimension = essence.getTimeDimension(); + const timeSplit = essence.splits.findSplitForDimension(timeDimension); + + const startTime = start(timeFilter); + const interval = intervalLength(timeFilter); + + const variables: Record = { startTime, interval }; + + if (timeSplit && timeSplit.bucket instanceof Duration) { + variables.granularity = timeSplit.bucket.getDescription(); + } + + if (essence.hasComparison()) { + const previousTimeFilter = essence.previousTimeFilter(timekeeper); + variables.shiftedTimeStart = start(previousTimeFilter); + } + + return variables; +} + +function logQueryInfo(essence: Essence, timekeeper: Timekeeper, logger: Logger) { + const nonTimeFilters = essence.filter.removeClause(essence.getTimeDimension().name); + + logger.log("visualization query", { + ...timeVariables(essence, timekeeper), + visualization: essence.visualization.name, + filters: nonTimeFilters.clauses.map(clause => clause.reference).toArray(), + splits: essence.splits.splits.map(split => split.reference).toArray(), + series: essence.series.series.map(series => series.reference).toArray() + }); +} + export default async function visualizationRoute({ context }: QueryRouterRequest, res: Response) { - const { dataCube, essence, decorator, timekeeper } = context; + const { dataCube, essence, decorator, timekeeper, logger } = context; + logQueryInfo(essence, timekeeper, logger); const query = getQuery(essence, timekeeper); const result = await executeQuery(dataCube, query, essence.timezone, decorator); res.json({ result }); From 611d9ab9e85779afa4b6a02129960cb72354d16b Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Mon, 13 Feb 2023 17:18:07 +0100 Subject: [PATCH 3/8] middleware request is not available in error handler --- src/server/routes/query/query.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/routes/query/query.ts b/src/server/routes/query/query.ts index 9ef62a774..c86054513 100644 --- a/src/server/routes/query/query.ts +++ b/src/server/routes/query/query.ts @@ -82,8 +82,8 @@ export function queryRouter(settings: Pick { - handleRequestErrors(error, res, context.logger); + router.use((error: Error, req: Request, res: Response, next: NextFunction) => { + handleRequestErrors(error, res, logger); }); return router; From c0e7cda677ee609223288d501569eb1d294da79d Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Tue, 14 Feb 2023 09:48:16 +0100 Subject: [PATCH 4/8] add data cube name to logged message --- src/server/routes/query/routes/visualization.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/routes/query/routes/visualization.ts b/src/server/routes/query/routes/visualization.ts index 1f0aa78eb..46a323880 100644 --- a/src/server/routes/query/routes/visualization.ts +++ b/src/server/routes/query/routes/visualization.ts @@ -66,6 +66,7 @@ function logQueryInfo(essence: Essence, timekeeper: Timekeeper, logger: Logger) logger.log("visualization query", { ...timeVariables(essence, timekeeper), + dataCube: essence.dataCube.name, visualization: essence.visualization.name, filters: nonTimeFilters.clauses.map(clause => clause.reference).toArray(), splits: essence.splits.splits.map(split => split.reference).toArray(), From 5a6c5f86ddb659062ef2a952c91b85d0c1cbb59a Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Tue, 14 Feb 2023 15:18:31 +0100 Subject: [PATCH 5/8] description method for essence --- src/client/utils/download/download.ts | 7 +------ src/common/models/essence/essence.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/client/utils/download/download.ts b/src/client/utils/download/download.ts index 34617fed8..ce71b0df8 100644 --- a/src/client/utils/download/download.ts +++ b/src/client/utils/download/download.ts @@ -19,7 +19,6 @@ import * as fileSaver from "file-saver"; import { Dataset, TabulatorOptions } from "plywood"; import { Essence } from "../../../common/models/essence/essence"; import { Timekeeper } from "../../../common/models/timekeeper/timekeeper"; -import { formatUrlSafeDateTime } from "../../../common/utils/time/time"; import tabularOptions from "../tabular-options/tabular-options"; export type FileFormat = "csv" | "tsv"; @@ -61,9 +60,5 @@ export function datasetToFileString(dataset: Dataset, fileFormat: FileFormat, op } export function fileNameBase(essence: Essence, timekeeper: Timekeeper): string { - const timeFilter = essence.currentTimeFilter(timekeeper); - const { start, end } = timeFilter.values.first(); - const timezone = essence.timezone; - - return `${essence.dataCube.name}_${formatUrlSafeDateTime(start, timezone)}_${formatUrlSafeDateTime(end, timezone)}`; + return essence.description(timekeeper); } diff --git a/src/common/models/essence/essence.ts b/src/common/models/essence/essence.ts index c07ddb0ba..f39a805ea 100644 --- a/src/common/models/essence/essence.ts +++ b/src/common/models/essence/essence.ts @@ -22,6 +22,7 @@ import { serialize as serializeDataCube } from "../../../client/deserializers/da import { thread } from "../../utils/functional/functional"; import nullableEquals from "../../utils/immutable-utils/nullable-equals"; import { visualizationIndependentEvaluator } from "../../utils/rules/visualization-independent-evaluator"; +import { formatUrlSafeDateTime } from "../../utils/time/time"; import { MANIFESTS } from "../../visualization-manifests"; import { ClientAppSettings } from "../app-settings/app-settings"; import { @@ -29,7 +30,8 @@ import { getDefaultFilter, getDefaultSeries, getDefaultSplits, - getMaxTime, getTimeDimension + getMaxTime, + getTimeDimension } from "../data-cube/data-cube"; import { DateRange } from "../date-range/date-range"; import { Dimension } from "../dimension/dimension"; @@ -656,4 +658,12 @@ export class Essence extends ImmutableRecord(defaultEssence) { public getPinnedSortSeries(): ConcreteSeries { return this.findConcreteSeries(this.pinnedSort); } + + public description(timekeeper: Timekeeper): string { + const timeFilter = this.currentTimeFilter(timekeeper); + const { start, end } = timeFilter.values.first(); + const timezone = this.timezone; + + return `${this.dataCube.name}_${formatUrlSafeDateTime(start, timezone)}_${formatUrlSafeDateTime(end, timezone)}`; + } } From 529dd69691d155fefa649cded93708138365ac38 Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Tue, 14 Feb 2023 15:18:45 +0100 Subject: [PATCH 6/8] method for series that returns used measures --- src/common/models/series/expression-series.ts | 15 ++++++++++++++- src/common/models/series/measure-series.ts | 4 ++++ src/common/models/series/quantile-series.ts | 4 ++++ src/common/models/series/series.ts | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/common/models/series/expression-series.ts b/src/common/models/series/expression-series.ts index dc8b3945d..f61de3a09 100644 --- a/src/common/models/series/expression-series.ts +++ b/src/common/models/series/expression-series.ts @@ -16,7 +16,7 @@ import { Record } from "immutable"; import { RequireOnly } from "../../utils/functional/functional"; -import { Expression, fromJS } from "../expression/expression"; +import { Expression, ExpressionSeriesOperation, fromJS } from "../expression/expression"; import { getNameWithDerivation, SeriesDerivation } from "./concrete-series"; import { BasicSeriesValue, SeriesBehaviours } from "./series"; import { DEFAULT_FORMAT, SeriesFormat } from "./series-format"; @@ -58,4 +58,17 @@ export class ExpressionSeries extends Record(defaultSerie plywoodKey(period = SeriesDerivation.CURRENT): string { return getNameWithDerivation(this.key(), period); } + + measures(): string[] { + switch (this.expression.operation) { + case ExpressionSeriesOperation.PERCENT_OF_PARENT: + case ExpressionSeriesOperation.PERCENT_OF_TOTAL: + return [this.reference]; + case ExpressionSeriesOperation.ADD: + case ExpressionSeriesOperation.SUBTRACT: + case ExpressionSeriesOperation.MULTIPLY: + case ExpressionSeriesOperation.DIVIDE: + return [this.reference, this.expression.reference]; + } + } } diff --git a/src/common/models/series/measure-series.ts b/src/common/models/series/measure-series.ts index 9bbfde27a..ce23d7215 100644 --- a/src/common/models/series/measure-series.ts +++ b/src/common/models/series/measure-series.ts @@ -54,4 +54,8 @@ export class MeasureSeries extends Record(defaultMeasureSeri plywoodKey(derivation = SeriesDerivation.CURRENT): string { return getNameWithDerivation(this.reference, derivation); } + + measures(): string[] { + return [this.reference]; + } } diff --git a/src/common/models/series/quantile-series.ts b/src/common/models/series/quantile-series.ts index 935c2b972..48626956d 100644 --- a/src/common/models/series/quantile-series.ts +++ b/src/common/models/series/quantile-series.ts @@ -71,4 +71,8 @@ export class QuantileSeries extends Record(defaultQuantileS plywoodKey(derivation = SeriesDerivation.CURRENT): string { return getNameWithDerivation(this.key(), derivation); } + + measures(): string[] { + return [this.reference]; + } } diff --git a/src/common/models/series/series.ts b/src/common/models/series/series.ts index b30d7c376..95e8b7eb7 100644 --- a/src/common/models/series/series.ts +++ b/src/common/models/series/series.ts @@ -30,6 +30,7 @@ export interface BasicSeriesValue { export interface SeriesBehaviours { key: () => string; plywoodKey: (period?: SeriesDerivation) => string; + measures: () => string[]; } export type Series = MeasureSeries | ExpressionSeries | QuantileSeries; From cac3579415b913c6ca271263693f9a9b5500f7f4 Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Tue, 14 Feb 2023 15:19:16 +0100 Subject: [PATCH 7/8] naming, switch from series to measures and description in log message --- src/server/routes/query/routes/visualization.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/routes/query/routes/visualization.ts b/src/server/routes/query/routes/visualization.ts index 46a323880..f33108f9c 100644 --- a/src/server/routes/query/routes/visualization.ts +++ b/src/server/routes/query/routes/visualization.ts @@ -55,7 +55,7 @@ function timeVariables(essence: Essence, timekeeper: Timekeeper): Record clause.reference).toArray(), splits: essence.splits.splits.map(split => split.reference).toArray(), - series: essence.series.series.map(series => series.reference).toArray() + measures: essence.series.series.flatMap(series => series.measures()).toSet().toArray() }); } From 038cc2730d9908a40ab064ba85d47badccabce28 Mon Sep 17 00:00:00 2001 From: Adrian Mroz Date: Wed, 15 Feb 2023 10:12:47 +0100 Subject: [PATCH 8/8] usedMeasures function --- src/common/models/measure/measure.fixtures.ts | 4 + src/common/models/series/expression-series.ts | 15 +-- src/common/models/series/measure-series.ts | 4 - src/common/models/series/quantile-series.ts | 4 - src/common/models/series/series.ts | 1 - .../models/series/used-measures.mocha.ts | 123 ++++++++++++++++++ src/common/models/series/used-measures.ts | 44 +++++++ .../routes/query/routes/visualization.ts | 3 +- 8 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 src/common/models/series/used-measures.mocha.ts create mode 100644 src/common/models/series/used-measures.ts diff --git a/src/common/models/measure/measure.fixtures.ts b/src/common/models/measure/measure.fixtures.ts index 811664dd8..40402ccfd 100644 --- a/src/common/models/measure/measure.fixtures.ts +++ b/src/common/models/measure/measure.fixtures.ts @@ -39,6 +39,10 @@ export class MeasureFixtures { return createMeasure("avg_delta", $("main").average($("delta"))); } + static histogram(): Measure { + return createMeasure("histogram", $("main").quantile($("create_to_collect_duration_histogram"), 0.95, "k=128")); + } + static wikiCountJS(): MeasureJS { return { name: "count", diff --git a/src/common/models/series/expression-series.ts b/src/common/models/series/expression-series.ts index f61de3a09..dc8b3945d 100644 --- a/src/common/models/series/expression-series.ts +++ b/src/common/models/series/expression-series.ts @@ -16,7 +16,7 @@ import { Record } from "immutable"; import { RequireOnly } from "../../utils/functional/functional"; -import { Expression, ExpressionSeriesOperation, fromJS } from "../expression/expression"; +import { Expression, fromJS } from "../expression/expression"; import { getNameWithDerivation, SeriesDerivation } from "./concrete-series"; import { BasicSeriesValue, SeriesBehaviours } from "./series"; import { DEFAULT_FORMAT, SeriesFormat } from "./series-format"; @@ -58,17 +58,4 @@ export class ExpressionSeries extends Record(defaultSerie plywoodKey(period = SeriesDerivation.CURRENT): string { return getNameWithDerivation(this.key(), period); } - - measures(): string[] { - switch (this.expression.operation) { - case ExpressionSeriesOperation.PERCENT_OF_PARENT: - case ExpressionSeriesOperation.PERCENT_OF_TOTAL: - return [this.reference]; - case ExpressionSeriesOperation.ADD: - case ExpressionSeriesOperation.SUBTRACT: - case ExpressionSeriesOperation.MULTIPLY: - case ExpressionSeriesOperation.DIVIDE: - return [this.reference, this.expression.reference]; - } - } } diff --git a/src/common/models/series/measure-series.ts b/src/common/models/series/measure-series.ts index ce23d7215..9bbfde27a 100644 --- a/src/common/models/series/measure-series.ts +++ b/src/common/models/series/measure-series.ts @@ -54,8 +54,4 @@ export class MeasureSeries extends Record(defaultMeasureSeri plywoodKey(derivation = SeriesDerivation.CURRENT): string { return getNameWithDerivation(this.reference, derivation); } - - measures(): string[] { - return [this.reference]; - } } diff --git a/src/common/models/series/quantile-series.ts b/src/common/models/series/quantile-series.ts index 48626956d..935c2b972 100644 --- a/src/common/models/series/quantile-series.ts +++ b/src/common/models/series/quantile-series.ts @@ -71,8 +71,4 @@ export class QuantileSeries extends Record(defaultQuantileS plywoodKey(derivation = SeriesDerivation.CURRENT): string { return getNameWithDerivation(this.key(), derivation); } - - measures(): string[] { - return [this.reference]; - } } diff --git a/src/common/models/series/series.ts b/src/common/models/series/series.ts index 95e8b7eb7..b30d7c376 100644 --- a/src/common/models/series/series.ts +++ b/src/common/models/series/series.ts @@ -30,7 +30,6 @@ export interface BasicSeriesValue { export interface SeriesBehaviours { key: () => string; plywoodKey: (period?: SeriesDerivation) => string; - measures: () => string[]; } export type Series = MeasureSeries | ExpressionSeries | QuantileSeries; diff --git a/src/common/models/series/used-measures.mocha.ts b/src/common/models/series/used-measures.mocha.ts new file mode 100644 index 000000000..764ba35e4 --- /dev/null +++ b/src/common/models/series/used-measures.mocha.ts @@ -0,0 +1,123 @@ +/* + * 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. + */ + +import { expect } from "chai"; +import { ArithmeticExpression } from "../expression/concreteArithmeticOperation"; +import { ExpressionSeriesOperation } from "../expression/expression"; +import { PercentExpression } from "../expression/percent"; +import { MeasureFixtures } from "../measure/measure.fixtures"; +import { ExpressionSeries } from "./expression-series"; +import { MeasureSeries } from "./measure-series"; +import { QuantileSeries } from "./quantile-series"; +import { usedMeasures } from "./used-measures"; + +const avgDelta = MeasureFixtures.avgDelta(); +const avgAdded = MeasureFixtures.avgAdded(); +const histogram = MeasureFixtures.histogram(); + +describe("usedMeasures", () => { + describe("MeasureSeries", () => { + it("should return array with measure reference", () => { + const series = MeasureSeries.fromMeasure(avgDelta); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta"]); + }); + }); + + describe("QuantileSeries", () => { + it("should return array with measure reference", () => { + const series = QuantileSeries.fromQuantileMeasure(histogram); + expect(usedMeasures(series)).to.be.deep.equal(["histogram"]); + }); + }); + + describe("ExpressionSeries", () => { + describe("Percent of total", () => { + it("should return array with measure reference", () => { + const series = ExpressionSeries.fromJS({ + reference: avgDelta.name, + expression: new PercentExpression({ + operation: ExpressionSeriesOperation.PERCENT_OF_TOTAL + }) + }); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta"]); + }); + }); + + describe("Percent of parent", () => { + it("should return array with measure reference", () => { + const series = ExpressionSeries.fromJS({ + reference: avgDelta.name, + expression: new PercentExpression({ + operation: ExpressionSeriesOperation.PERCENT_OF_PARENT + }) + }); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta"]); + }); + }); + + describe("Arithmetic ADD", () => { + it("should return array with measure reference and reference of operand", () => { + const series = ExpressionSeries.fromJS({ + reference: avgDelta.name, + expression: new ArithmeticExpression({ + operation: ExpressionSeriesOperation.ADD, + reference: avgAdded.name + }) + }); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta", "avg_added"]); + }); + }); + + describe("Arithmetic SUBTRACT", () => { + it("should return array with measure reference and reference of operand", () => { + const series = ExpressionSeries.fromJS({ + reference: avgDelta.name, + expression: new ArithmeticExpression({ + operation: ExpressionSeriesOperation.SUBTRACT, + reference: avgAdded.name + }) + }); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta", "avg_added"]); + }); + }); + + describe("Arithmetic MULTIPLY", () => { + it("should return array with measure reference and reference of operand", () => { + const series = ExpressionSeries.fromJS({ + reference: avgDelta.name, + expression: new ArithmeticExpression({ + operation: ExpressionSeriesOperation.MULTIPLY, + reference: avgAdded.name + }) + }); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta", "avg_added"]); + }); + }); + + describe("Arithmetic DIVIDE", () => { + it("should return array with measure reference and reference of operand", () => { + const series = ExpressionSeries.fromJS({ + reference: avgDelta.name, + expression: new ArithmeticExpression({ + operation: ExpressionSeriesOperation.DIVIDE, + reference: avgAdded.name + }) + }); + expect(usedMeasures(series)).to.be.deep.equal(["avg_delta", "avg_added"]); + }); + }); + }); +}); diff --git a/src/common/models/series/used-measures.ts b/src/common/models/series/used-measures.ts new file mode 100644 index 000000000..5f2884ab9 --- /dev/null +++ b/src/common/models/series/used-measures.ts @@ -0,0 +1,44 @@ +/* + * 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. + */ + +import { ExpressionSeriesOperation } from "../expression/expression"; +import { ExpressionSeries } from "./expression-series"; +import { Series } from "./series"; +import { SeriesType } from "./series-type"; + +function usedMeasuresInExpressionSeries(series: ExpressionSeries): string[] { + switch (series.expression.operation) { + case ExpressionSeriesOperation.PERCENT_OF_PARENT: + case ExpressionSeriesOperation.PERCENT_OF_TOTAL: + return [series.reference]; + case ExpressionSeriesOperation.ADD: + case ExpressionSeriesOperation.SUBTRACT: + case ExpressionSeriesOperation.MULTIPLY: + case ExpressionSeriesOperation.DIVIDE: + return [series.reference, series.expression.reference]; + } +} + +export function usedMeasures(series: Series): string[] { + switch (series.type) { + case SeriesType.MEASURE: + return [series.reference]; + case SeriesType.EXPRESSION: + return usedMeasuresInExpressionSeries(series); + case SeriesType.QUANTILE: + return [series.reference]; + } +} diff --git a/src/server/routes/query/routes/visualization.ts b/src/server/routes/query/routes/visualization.ts index f33108f9c..a13827e79 100644 --- a/src/server/routes/query/routes/visualization.ts +++ b/src/server/routes/query/routes/visualization.ts @@ -21,6 +21,7 @@ import makeGridQuery from "../../../../client/visualizations/grid/make-query"; import { Logger } from "../../../../common/logger/logger"; import { Essence } from "../../../../common/models/essence/essence"; import { FixedTimeFilterClause } from "../../../../common/models/filter-clause/filter-clause"; +import { usedMeasures } from "../../../../common/models/series/used-measures"; import { Timekeeper } from "../../../../common/models/timekeeper/timekeeper"; import makeQuery from "../../../../common/utils/query/visualization-query"; import { executeQuery } from "../../../utils/query/execute-query"; @@ -70,7 +71,7 @@ function logQueryInfo(essence: Essence, timekeeper: Timekeeper, logger: Logger) visualization: essence.visualization.name, filters: nonTimeFilters.clauses.map(clause => clause.reference).toArray(), splits: essence.splits.splits.map(split => split.reference).toArray(), - measures: essence.series.series.flatMap(series => series.measures()).toSet().toArray() + measures: essence.series.series.flatMap(usedMeasures).toSet().toArray() }); }