[expressions] select_filter and remove_filter functions (#113533)

This commit is contained in:
Peter Pisljar 2021-10-21 11:03:53 +02:00 committed by GitHub
parent 933ece47ad
commit 800cfb504c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 579 additions and 0 deletions

View file

@ -56,6 +56,8 @@ export type FilterMeta = {
negate?: boolean;
// controlledBy is there to identify who owns the filter
controlledBy?: string;
// allows grouping of filters
group?: string;
// index and type are optional only because when you create a new filter, there are no defaults
index?: string;
isMultiIndex?: boolean;

View file

@ -36,6 +36,8 @@ export * from './field';
export * from './phrase_filter';
export * from './exists_filter';
export * from './range_filter';
export * from './remove_filter';
export * from './select_filter';
export * from './kibana_filter';
export * from './filters_to_ast';
export * from './timerange';

View file

@ -0,0 +1,206 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { createMockContext } from '../../../../expressions/common';
import { functionWrapper } from './utils';
import { removeFilterFunction } from './remove_filter';
import { KibanaContext } from './kibana_context_type';
describe('interpreter/functions#removeFilter', () => {
const fn = functionWrapper(removeFilterFunction);
const kibanaContext: KibanaContext = {
type: 'kibana_context',
filters: [
{
meta: {
group: 'g1',
},
query: {},
},
{
meta: {
group: 'g2',
},
query: {},
},
{
meta: {
group: 'g1',
controlledBy: 'i1',
},
query: {},
},
{
meta: {
group: 'g1',
controlledBy: 'i2',
},
query: {},
},
{
meta: {
controlledBy: 'i1',
},
query: {},
},
],
};
it('removes all filters when called without arguments', () => {
const actual = fn(kibanaContext, {}, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [],
"type": "kibana_context",
}
`);
});
it('removes filters belonging to certain group', () => {
const actual = fn(kibanaContext, { group: 'g1' }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g2",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('removes ungrouped filters', () => {
const actual = fn(kibanaContext, { ungrouped: true }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"group": "g2",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i2",
"group": "g1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('removes ungrouped filters and filters matching a group', () => {
const actual = fn(kibanaContext, { group: 'g1', ungrouped: true }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g2",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('removes filters controlled by specified id', () => {
const actual = fn(kibanaContext, { from: 'i1' }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"group": "g2",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i2",
"group": "g1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('removes filters controlled by specified id and matching a group', () => {
const actual = fn(kibanaContext, { group: 'g1', from: 'i1' }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"group": "g2",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i2",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
});

View file

@ -0,0 +1,69 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { i18n } from '@kbn/i18n';
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
import { KibanaContext } from './kibana_context_type';
interface Arguments {
group?: string;
from?: string;
ungrouped?: boolean;
}
export type ExpressionFunctionRemoveFilter = ExpressionFunctionDefinition<
'removeFilter',
KibanaContext,
Arguments,
KibanaContext
>;
export const removeFilterFunction: ExpressionFunctionRemoveFilter = {
name: 'removeFilter',
type: 'kibana_context',
inputTypes: ['kibana_context'],
help: i18n.translate('data.search.functions.removeFilter.help', {
defaultMessage: 'Removes filters from context',
}),
args: {
group: {
types: ['string'],
aliases: ['_'],
help: i18n.translate('data.search.functions.removeFilter.group.help', {
defaultMessage: 'Removes only filters belonging to the provided group',
}),
},
from: {
types: ['string'],
help: i18n.translate('data.search.functions.removeFilter.from.help', {
defaultMessage: 'Removes only filters owned by the provided id',
}),
},
ungrouped: {
types: ['boolean'],
aliases: ['nogroup', 'nogroups'],
default: false,
help: i18n.translate('data.search.functions.removeFilter.ungrouped.help', {
defaultMessage: 'Should filters without group be removed',
}),
},
},
fn(input, { group, from, ungrouped }) {
return {
...input,
filters:
input.filters?.filter(({ meta }) => {
const isGroupMatching =
(!group && !ungrouped) || group === meta.group || (ungrouped && !meta.group);
const isOriginMatching = !from || from === meta.controlledBy;
return !isGroupMatching || !isOriginMatching;
}) || [],
};
},
};

View file

@ -0,0 +1,223 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { createMockContext } from '../../../../expressions/common';
import { functionWrapper } from './utils';
import { selectFilterFunction } from './select_filter';
import { KibanaContext } from './kibana_context_type';
describe('interpreter/functions#selectFilter', () => {
const fn = functionWrapper(selectFilterFunction);
const kibanaContext: KibanaContext = {
type: 'kibana_context',
filters: [
{
meta: {
group: 'g1',
},
query: {},
},
{
meta: {
group: 'g2',
},
query: {},
},
{
meta: {
group: 'g1',
controlledBy: 'i1',
},
query: {},
},
{
meta: {
group: 'g1',
controlledBy: 'i2',
},
query: {},
},
{
meta: {
controlledBy: 'i1',
},
query: {},
},
],
};
it('selects all filters when called without arguments', () => {
const actual = fn(kibanaContext, {}, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"group": "g2",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i2",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('selects filters belonging to certain group', () => {
const actual = fn(kibanaContext, { group: 'g1' }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i2",
"group": "g1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('selects ungrouped filters', () => {
const actual = fn(kibanaContext, { ungrouped: true }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"controlledBy": "i1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('selects ungrouped filters and filters matching a group', () => {
const actual = fn(kibanaContext, { group: 'g1', ungrouped: true }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i2",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('selects filters controlled by specified id', () => {
const actual = fn(kibanaContext, { from: 'i1' }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"controlledBy": "i1",
"group": "g1",
},
"query": Object {},
},
Object {
"meta": Object {
"controlledBy": "i1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
it('selects filters controlled by specified id and matching a group', () => {
const actual = fn(kibanaContext, { group: 'g1', from: 'i1' }, createMockContext());
expect(actual).toMatchInlineSnapshot(`
Object {
"filters": Array [
Object {
"meta": Object {
"controlledBy": "i1",
"group": "g1",
},
"query": Object {},
},
],
"type": "kibana_context",
}
`);
});
});

View file

@ -0,0 +1,69 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { i18n } from '@kbn/i18n';
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
import { KibanaContext } from './kibana_context_type';
interface Arguments {
group?: string;
from?: string;
ungrouped?: boolean;
}
export type ExpressionFunctionSelectFilter = ExpressionFunctionDefinition<
'selectFilter',
KibanaContext,
Arguments,
KibanaContext
>;
export const selectFilterFunction: ExpressionFunctionSelectFilter = {
name: 'selectFilter',
type: 'kibana_context',
inputTypes: ['kibana_context'],
help: i18n.translate('data.search.functions.selectFilter.help', {
defaultMessage: 'Selects filters from context',
}),
args: {
group: {
types: ['string'],
aliases: ['_'],
help: i18n.translate('data.search.functions.selectFilter.group.help', {
defaultMessage: 'Select only filters belonging to the provided group',
}),
},
from: {
types: ['string'],
help: i18n.translate('data.search.functions.selectFilter.from.help', {
defaultMessage: 'Select only filters owned by the provided id',
}),
},
ungrouped: {
types: ['boolean'],
aliases: ['nogroup', 'nogroups'],
default: false,
help: i18n.translate('data.search.functions.selectFilter.ungrouped.help', {
defaultMessage: 'Should filters without group be included',
}),
},
},
fn(input, { group, ungrouped, from }) {
return {
...input,
filters:
input.filters?.filter(({ meta }) => {
const isGroupMatching =
(!group && !ungrouped) || group === meta.group || (ungrouped && !meta.group);
const isOriginMatching = !from || from === meta.controlledBy;
return isGroupMatching && isOriginMatching;
}) || [],
};
},
};

View file

@ -39,6 +39,8 @@ import {
geoPointFunction,
queryFilterFunction,
rangeFilterFunction,
removeFilterFunction,
selectFilterFunction,
kibanaFilterFunction,
phraseFilterFunction,
esRawResponse,
@ -139,6 +141,8 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
expressions.registerFunction(existsFilterFunction);
expressions.registerFunction(queryFilterFunction);
expressions.registerFunction(rangeFilterFunction);
expressions.registerFunction(removeFilterFunction);
expressions.registerFunction(selectFilterFunction);
expressions.registerFunction(phraseFilterFunction);
expressions.registerType(kibanaContext);

View file

@ -66,6 +66,8 @@ import {
numericalRangeFunction,
queryFilterFunction,
rangeFilterFunction,
removeFilterFunction,
selectFilterFunction,
rangeFunction,
SearchSourceDependencies,
searchSourceRequiredUiSettings,
@ -205,6 +207,8 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
expressions.registerFunction(existsFilterFunction);
expressions.registerFunction(queryFilterFunction);
expressions.registerFunction(rangeFilterFunction);
expressions.registerFunction(removeFilterFunction);
expressions.registerFunction(selectFilterFunction);
expressions.registerFunction(phraseFilterFunction);
expressions.registerType(kibanaContext);
expressions.registerType(esRawResponse);