Skip to content

Commit

Permalink
[8.12] [Lens] Fix context formula functions (#172710) (#173760)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.12`:
- [[Lens] Fix context formula functions
(#172710)](#172710)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Drew
Tate","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-12-19T15:32:31Z","message":"[Lens]
Fix context formula functions (#172710)\n\n## Summary\r\nFix
https://github.com/elastic/kibana/issues/170762\r\n\r\n\r\n\r\nhttps://github.com/elastic/kibana/assets/315764/f5b50ffa-4a03-45ee-bc7a-2f2aca7fa3bd\r\n\r\n\r\n\r\n###
Checklist\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<[email protected]>","sha":"99763dc61647c817384019f6603de7ad258eea01","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Feature:ExpressionLanguage","Team:Visualizations","Feature:Lens","backport:prev-minor","v8.13.0"],"number":172710,"url":"https://github.com/elastic/kibana/pull/172710","mergeCommit":{"message":"[Lens]
Fix context formula functions (#172710)\n\n## Summary\r\nFix
https://github.com/elastic/kibana/issues/170762\r\n\r\n\r\n\r\nhttps://github.com/elastic/kibana/assets/315764/f5b50ffa-4a03-45ee-bc7a-2f2aca7fa3bd\r\n\r\n\r\n\r\n###
Checklist\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<[email protected]>","sha":"99763dc61647c817384019f6603de7ad258eea01"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.13.0","labelRegex":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/172710","number":172710,"mergeCommit":{"message":"[Lens]
Fix context formula functions (#172710)\n\n## Summary\r\nFix
https://github.com/elastic/kibana/issues/170762\r\n\r\n\r\n\r\nhttps://github.com/elastic/kibana/assets/315764/f5b50ffa-4a03-45ee-bc7a-2f2aca7fa3bd\r\n\r\n\r\n\r\n###
Checklist\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<[email protected]>","sha":"99763dc61647c817384019f6603de7ad258eea01"}}]}]
BACKPORT-->
  • Loading branch information
drewdaemon authored Dec 20, 2023
1 parent cf47748 commit 7542adb
Show file tree
Hide file tree
Showing 23 changed files with 264 additions and 171 deletions.
1 change: 1 addition & 0 deletions packages/kbn-es-query/src/expressions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { Filter, Query, TimeRange } from '../filters';

export interface ExecutionContextSearch {
now?: number;
filters?: Filter[];
query?: Query | Query[];
timeRange?: TimeRange;
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pageLoadAssetSize:
kibanaUsageCollection: 16463
kibanaUtils: 79713
kubernetesSecurity: 77234
lens: 39000
lens: 41000
licenseManagement: 41817
licensing: 29004
links: 44490
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/plugins/data/common/search/expressions/kibana.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('interpreter/functions#kibana', () => {
beforeEach(() => {
input = { timeRange: { from: '0', to: '1' } };
search = {
now: 0,
type: 'kibana_context',
query: { language: 'lucene', query: 'geo.src:US' },
filters: [
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/common/search/expressions/kibana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const kibana: ExpressionFunctionKibana = {
// TODO: But it shouldn't be need.
...input,
type: 'kibana_context',
now: getSearchContext().now ?? Date.now(),
query: [...toArray(getSearchContext().query), ...toArray((input || {}).query)],
filters: [...(getSearchContext().filters || []), ...((input || {}).filters || [])],
timeRange: getSearchContext().timeRange || (input ? input.timeRange : undefined),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export * from './overall_metric';
export * from './derivative';
export * from './moving_average';
export * from './ui_setting';
export * from './math_column';
export type { MapColumnArguments } from './map_column';
export { mapColumn } from './map_column';
export type { MathArguments, MathInput } from './math';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ export type MathColumnArguments = MathArguments & {
copyMetaFrom?: string | null;
};

export const mathColumn: ExpressionFunctionDefinition<
export type ExpressionFunctionMathColumn = ExpressionFunctionDefinition<
'mathColumn',
Datatable,
MathColumnArguments,
Promise<Datatable>
> = {
>;

export const mathColumn: ExpressionFunctionMathColumn = {
name: 'mathColumn',
type: 'datatable',
inputTypes: ['datatable'],
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/expressions/common/expression_functions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ExpressionFunctionDerivative,
ExpressionFunctionMovingAverage,
ExpressionFunctionOverallMetric,
ExpressionFunctionMathColumn,
} from './specs';
import { ExpressionAstFunction } from '../ast';

Expand Down Expand Up @@ -132,4 +133,5 @@ export interface ExpressionFunctionDefinitions {
overall_metric: ExpressionFunctionOverallMetric;
derivative: ExpressionFunctionDerivative;
moving_average: ExpressionFunctionMovingAverage;
math_column: ExpressionFunctionMathColumn;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ExecutionContext } from '@kbn/expressions-plugin/common';
import { Adapters } from '@kbn/inspector-plugin/common';
import { formulaIntervalFn, formulaNowFn, formulaTimeRangeFn } from './context_fns';

describe('interval', () => {
it('should return 0 if no time range available', () => {
// (not sure if this case is actually possible)
const result = formulaIntervalFn.fn(undefined, { targetBars: 100 }, {
getSearchContext: () => ({
/* no time range */
}),
} as ExecutionContext<Adapters>);
expect(result).toEqual(0);
});

it('should return 0 if no targetBars is passed', () => {
const result = formulaIntervalFn.fn(
undefined,
{
/* no targetBars */
},
{
getSearchContext: () => ({
timeRange: {
from: 'now-15m',
to: 'now',
},
}),
} as ExecutionContext<Adapters>
);
expect(result).toEqual(0);
});

it('should return a valid value > 0 if both timeRange and targetBars is passed', () => {
const result = formulaIntervalFn.fn(undefined, { targetBars: 100 }, {
getSearchContext: () => ({
timeRange: {
from: 'now-15m',
to: 'now',
},
}),
} as ExecutionContext<Adapters>);
expect(result).toEqual(10000);
});
});

describe('time range', () => {
it('should return 0 if no time range is available', () => {
// (not sure if this case is actually possible)
const result = formulaTimeRangeFn.fn(undefined, {}, {
getSearchContext: () => ({
/* no time range */
}),
} as ExecutionContext<Adapters>);
expect(result).toEqual(0);
});

it('should return a valid value > 0 if time range is available', () => {
const result = formulaTimeRangeFn.fn(undefined, {}, {
getSearchContext: () => ({
timeRange: {
from: 'now-15m',
to: 'now',
},
now: 1000000, // important to provide this to make the result consistent
}),
} as ExecutionContext<Adapters>);

expect(result).toBe(900000);
});
});

describe('now', () => {
it('should return the now value when passed', () => {
const now = 123456789;
expect(
formulaNowFn.fn(undefined, {}, {
getSearchContext: () => ({
now,
}),
} as ExecutionContext<Adapters>)
).toEqual(now);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { getAbsoluteTimeRange, calcAutoIntervalNear } from '@kbn/data-plugin/common';
import type { TimeRange } from '@kbn/es-query';
import type { ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common';
import moment from 'moment';
import { i18n } from '@kbn/i18n';

export type ExpressionFunctionFormulaTimeRange = ExpressionFunctionDefinition<
'formula_time_range',
undefined,
object,
number
>;

const getTimeRangeAsNumber = (timeRange: TimeRange | undefined, now: number | undefined) => {
if (!timeRange) return 0;
const absoluteTimeRange = getAbsoluteTimeRange(
timeRange,
now != null ? { forceNow: new Date(now) } : {}
);
return timeRange ? moment(absoluteTimeRange.to).diff(moment(absoluteTimeRange.from)) : 0;
};

export const formulaTimeRangeFn: ExpressionFunctionFormulaTimeRange = {
name: 'formula_time_range',

help: i18n.translate('xpack.lens.formula.timeRange.help', {
defaultMessage: 'The specified time range, in milliseconds (ms).',
}),

args: {},

fn(_input, _args, { getSearchContext }) {
const { timeRange, now } = getSearchContext();
return getTimeRangeAsNumber(timeRange, now);
},
};

export type ExpressionFunctionFormulaInterval = ExpressionFunctionDefinition<
'formula_interval',
undefined,
{
targetBars?: number;
},
number
>;

export const formulaIntervalFn: ExpressionFunctionFormulaInterval = {
name: 'formula_interval',

help: i18n.translate('xpack.lens.formula.interval.help', {
defaultMessage: 'The specified minimum interval for the date histogram, in milliseconds (ms).',
}),

args: {
targetBars: {
types: ['number'],
help: i18n.translate('xpack.lens.formula.interval.targetBars.help', {
defaultMessage: 'The target number of bars for the date histogram.',
}),
},
},

fn(_input, args, { getSearchContext }) {
const { timeRange, now } = getSearchContext();
return timeRange && args.targetBars
? calcAutoIntervalNear(args.targetBars, getTimeRangeAsNumber(timeRange, now)).asMilliseconds()
: 0;
},
};

export type ExpressionFunctionFormulaNow = ExpressionFunctionDefinition<
'formula_now',
undefined,
object,
number
>;

export const formulaNowFn: ExpressionFunctionFormulaNow = {
name: 'formula_now',

help: i18n.translate('xpack.lens.formula.now.help', {
defaultMessage: 'The current now moment used in Kibana expressed in milliseconds (ms).',
}),

args: {},

fn(_input, _args, { getSearchContext }) {
return getSearchContext().now ?? Date.now();
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export * from './context_fns';
1 change: 1 addition & 0 deletions x-pack/plugins/lens/common/expressions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './format_column';
export * from './map_to_columns';
export * from './time_scale';
export * from './datatable';
export * from './formula_context';
Loading

0 comments on commit 7542adb

Please sign in to comment.