mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[kbn-es-query] Add support for OR filters (#142417)
Co-authored-by: Peter Pisljar <peter.pisljar@elastic.co>
This commit is contained in:
parent
32b029ebbb
commit
98f365eadf
12 changed files with 727 additions and 35 deletions
|
@ -67,6 +67,7 @@ export {
|
|||
buildEmptyFilter,
|
||||
buildExistsFilter,
|
||||
buildFilter,
|
||||
buildOrFilter,
|
||||
buildPhraseFilter,
|
||||
buildPhrasesFilter,
|
||||
buildQueryFilter,
|
||||
|
@ -89,6 +90,7 @@ export {
|
|||
isFilterPinned,
|
||||
isFilters,
|
||||
isMatchAllFilter,
|
||||
isOrFilter,
|
||||
isPhraseFilter,
|
||||
isPhrasesFilter,
|
||||
isQueryStringFilter,
|
||||
|
|
|
@ -13,6 +13,7 @@ import { filterMatchesIndex } from './filter_matches_index';
|
|||
import { Filter, cleanFilter, isFilterDisabled } from '../filters';
|
||||
import { BoolQuery, DataViewBase } from './types';
|
||||
import { handleNestedFilter } from './handle_nested_filter';
|
||||
import { handleOrFilter } from './handle_or_filter';
|
||||
|
||||
/**
|
||||
* Create a filter that can be reversed for filters with negate set
|
||||
|
@ -66,10 +67,11 @@ export interface EsQueryFiltersConfig {
|
|||
export const buildQueryFromFilters = (
|
||||
inputFilters: Filter[] = [],
|
||||
inputDataViews: DataViewBase | DataViewBase[] | undefined,
|
||||
{ ignoreFilterIfFieldNotInIndex = false, nestedIgnoreUnmapped }: EsQueryFiltersConfig = {
|
||||
options: EsQueryFiltersConfig = {
|
||||
ignoreFilterIfFieldNotInIndex: false,
|
||||
}
|
||||
): BoolQuery => {
|
||||
const { ignoreFilterIfFieldNotInIndex = false, nestedIgnoreUnmapped } = options;
|
||||
const filters = inputFilters.filter((filter) => filter && !isFilterDisabled(filter));
|
||||
const indexPatterns = Array.isArray(inputDataViews) ? inputDataViews : [inputDataViews];
|
||||
|
||||
|
@ -92,6 +94,7 @@ export const buildQueryFromFilters = (
|
|||
ignoreUnmapped: nestedIgnoreUnmapped,
|
||||
});
|
||||
})
|
||||
.map((filter) => handleOrFilter(filter, inputDataViews, options))
|
||||
.map(cleanFilter)
|
||||
.map(translateToQuery);
|
||||
};
|
||||
|
|
610
packages/kbn-es-query/src/es_query/handle_or_filter.test.ts
Normal file
610
packages/kbn-es-query/src/es_query/handle_or_filter.test.ts
Normal file
|
@ -0,0 +1,610 @@
|
|||
/*
|
||||
* 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 { fields } from '../filters/stubs';
|
||||
import { DataViewBase } from './types';
|
||||
import { handleOrFilter } from './handle_or_filter';
|
||||
import {
|
||||
buildExistsFilter,
|
||||
buildOrFilter,
|
||||
buildPhraseFilter,
|
||||
buildPhrasesFilter,
|
||||
buildRangeFilter,
|
||||
} from '../filters';
|
||||
|
||||
describe('#handleOrFilter', function () {
|
||||
const indexPattern: DataViewBase = {
|
||||
id: 'logstash-*',
|
||||
fields,
|
||||
title: 'dataView',
|
||||
};
|
||||
|
||||
const getField = (fieldName: string) => {
|
||||
const field = fields.find(({ name }) => fieldName === name);
|
||||
if (!field) throw new Error(`field ${name} does not exist`);
|
||||
return field;
|
||||
};
|
||||
|
||||
it('Handles an empty list of filters', () => {
|
||||
const filter = buildOrFilter([]);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Handles a simple list of filters', () => {
|
||||
const filters = [
|
||||
buildPhraseFilter(getField('extension'), 'value', indexPattern),
|
||||
buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern),
|
||||
buildExistsFilter(getField('machine.os'), indexPattern),
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Handles a combination of filters and filter arrays', () => {
|
||||
const filters = [
|
||||
buildPhraseFilter(getField('extension'), 'value', indexPattern),
|
||||
[
|
||||
buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern),
|
||||
buildExistsFilter(getField('machine.os'), indexPattern),
|
||||
],
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Handles nested OR filters', () => {
|
||||
const nestedOrFilter = buildOrFilter([
|
||||
buildPhraseFilter(getField('machine.os'), 'value', indexPattern),
|
||||
buildPhraseFilter(getField('extension'), 'value', indexPattern),
|
||||
]);
|
||||
const filters = [
|
||||
buildPhraseFilter(getField('extension'), 'value2', indexPattern),
|
||||
nestedOrFilter,
|
||||
buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern),
|
||||
buildExistsFilter(getField('machine.os.raw'), indexPattern),
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value2",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"machine.os": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os.raw",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Handles negated sub-filters', () => {
|
||||
const negatedFilter = buildPhrasesFilter(getField('extension'), ['tar', 'gz'], indexPattern);
|
||||
negatedFilter.meta.negate = true;
|
||||
|
||||
const filters = [
|
||||
[negatedFilter, buildPhraseFilter(getField('extension'), 'value', indexPattern)],
|
||||
buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern),
|
||||
buildExistsFilter(getField('machine.os'), indexPattern),
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "tar",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "gz",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Handles disabled filters within a filter array', () => {
|
||||
const disabledFilter = buildPhraseFilter(getField('ssl'), false, indexPattern);
|
||||
disabledFilter.meta.disabled = true;
|
||||
const filters = [
|
||||
buildPhraseFilter(getField('extension'), 'value', indexPattern),
|
||||
[disabledFilter, buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern)],
|
||||
buildExistsFilter(getField('machine.os'), indexPattern),
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Handles complex-nested filters with ANDs and ORs', () => {
|
||||
const filters = [
|
||||
[
|
||||
buildPhrasesFilter(getField('extension'), ['tar', 'gz'], indexPattern),
|
||||
buildPhraseFilter(getField('ssl'), false, indexPattern),
|
||||
buildOrFilter([
|
||||
buildPhraseFilter(getField('extension'), 'value', indexPattern),
|
||||
buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern),
|
||||
]),
|
||||
buildExistsFilter(getField('machine.os'), indexPattern),
|
||||
],
|
||||
buildPhrasesFilter(getField('machine.os.keyword'), ['foo', 'bar'], indexPattern),
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const result = handleOrFilter(filter);
|
||||
expect(result.query).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "tar",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "gz",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"ssl": false,
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os",
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"bool": Object {
|
||||
"minimum_should_match": 1,
|
||||
"should": Array [
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"machine.os.keyword": "foo",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match_phrase": Object {
|
||||
"machine.os.keyword": "bar",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
"must": Array [],
|
||||
"must_not": Array [],
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Preserves filter properties', () => {
|
||||
const filters = [
|
||||
buildPhraseFilter(getField('extension'), 'value', indexPattern),
|
||||
buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern),
|
||||
buildExistsFilter(getField('machine.os'), indexPattern),
|
||||
];
|
||||
const filter = buildOrFilter(filters);
|
||||
const { query, ...rest } = handleOrFilter(filter);
|
||||
expect(rest).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"$state": Object {
|
||||
"store": "appState",
|
||||
},
|
||||
"meta": Object {
|
||||
"alias": null,
|
||||
"disabled": false,
|
||||
"index": undefined,
|
||||
"negate": false,
|
||||
"params": Array [
|
||||
Object {
|
||||
"meta": Object {
|
||||
"index": "logstash-*",
|
||||
},
|
||||
"query": Object {
|
||||
"match_phrase": Object {
|
||||
"extension": "value",
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"meta": Object {
|
||||
"field": "bytes",
|
||||
"index": "logstash-*",
|
||||
"params": Object {},
|
||||
},
|
||||
"query": Object {
|
||||
"range": Object {
|
||||
"bytes": Object {
|
||||
"gte": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"meta": Object {
|
||||
"index": "logstash-*",
|
||||
},
|
||||
"query": Object {
|
||||
"exists": Object {
|
||||
"field": "machine.os",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"type": "OR",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
41
packages/kbn-es-query/src/es_query/handle_or_filter.ts
Normal file
41
packages/kbn-es-query/src/es_query/handle_or_filter.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 { Filter, FilterItem, isOrFilter } from '../filters';
|
||||
import { DataViewBase } from './types';
|
||||
import { buildQueryFromFilters, EsQueryFiltersConfig } from './from_filters';
|
||||
|
||||
/** @internal */
|
||||
export const handleOrFilter = (
|
||||
filter: Filter,
|
||||
inputDataViews?: DataViewBase | DataViewBase[],
|
||||
options: EsQueryFiltersConfig = {}
|
||||
): Filter => {
|
||||
if (!isOrFilter(filter)) return filter;
|
||||
const { params } = filter.meta;
|
||||
const should = params.map((subFilter) => {
|
||||
const subFilters = Array.isArray(subFilter) ? subFilter : [subFilter];
|
||||
return { bool: buildQueryFromFilters(flattenFilters(subFilters), inputDataViews, options) };
|
||||
});
|
||||
return {
|
||||
...filter,
|
||||
query: {
|
||||
bool: {
|
||||
should,
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
function flattenFilters(filters: FilterItem[]): Filter[] {
|
||||
return filters.reduce<Filter[]>((result, filter) => {
|
||||
if (Array.isArray(filter)) return [...result, ...flattenFilters(filter)];
|
||||
return [...result, filter];
|
||||
}, []);
|
||||
}
|
|
@ -14,6 +14,7 @@ export * from './exists_filter';
|
|||
export * from './get_filter_field';
|
||||
export * from './get_filter_params';
|
||||
export * from './match_all_filter';
|
||||
export * from './or_filter';
|
||||
export * from './phrase_filter';
|
||||
export * from './phrases_filter';
|
||||
export * from './query_string_filter';
|
||||
|
|
57
packages/kbn-es-query/src/filters/build_filters/or_filter.ts
Normal file
57
packages/kbn-es-query/src/filters/build_filters/or_filter.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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 { Filter, FilterMeta, FILTERS } from './types';
|
||||
import { buildEmptyFilter } from './build_empty_filter';
|
||||
|
||||
/**
|
||||
* Each item in an OR filter may represent either one filter (to be ORed) or an array of filters (ANDed together before
|
||||
* becoming part of the OR clause).
|
||||
* @public
|
||||
*/
|
||||
export type FilterItem = Filter | FilterItem[];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface OrFilterMeta extends FilterMeta {
|
||||
type: typeof FILTERS.OR;
|
||||
params: FilterItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface OrFilter extends Filter {
|
||||
meta: OrFilterMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function isOrFilter(filter: Filter): filter is OrFilter {
|
||||
return filter?.meta?.type === FILTERS.OR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an OR filter. An OR filter is a filter with multiple sub-filters. Each sub-filter (FilterItem) represents a
|
||||
* condition.
|
||||
* @param filters An array of OrFilterItem
|
||||
* @public
|
||||
*/
|
||||
export function buildOrFilter(filters: FilterItem[]): OrFilter {
|
||||
const filter = buildEmptyFilter(false);
|
||||
return {
|
||||
...filter,
|
||||
meta: {
|
||||
...filter.meta,
|
||||
type: FILTERS.OR,
|
||||
params: filters,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -37,6 +37,7 @@ export enum FILTERS {
|
|||
RANGE = 'range',
|
||||
RANGE_FROM_VALUE = 'range_from_value',
|
||||
SPATIAL_FILTER = 'spatial_filter',
|
||||
OR = 'OR',
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,8 @@ export {
|
|||
export {
|
||||
isExistsFilter,
|
||||
isMatchAllFilter,
|
||||
buildOrFilter,
|
||||
isOrFilter,
|
||||
isPhraseFilter,
|
||||
isPhrasesFilter,
|
||||
isRangeFilter,
|
||||
|
@ -75,6 +77,9 @@ export type {
|
|||
CustomFilter,
|
||||
RangeFilterParams,
|
||||
QueryStringFilter,
|
||||
OrFilter,
|
||||
OrFilterMeta,
|
||||
FilterItem,
|
||||
} from './build_filters';
|
||||
|
||||
export { FilterStateStore, FILTERS } from './build_filters/types';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { buildEmptyFilter, Filter } from '@kbn/es-query';
|
||||
import { buildEmptyFilter, Filter, FilterItem } from '@kbn/es-query';
|
||||
import { ConditionTypes } from '../utils';
|
||||
import {
|
||||
getFilterByPath,
|
||||
|
@ -16,7 +16,6 @@ import {
|
|||
moveFilter,
|
||||
normalizeFilters,
|
||||
} from './filters_builder_utils';
|
||||
import type { FilterItem } from '../utils';
|
||||
import { getConditionalOperationType } from '../utils';
|
||||
|
||||
import {
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
*/
|
||||
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
import type { Filter, FilterItem } from '@kbn/es-query';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { ConditionTypes, getConditionalOperationType, isOrFilter, buildOrFilter } from '../utils';
|
||||
import type { FilterItem } from '../utils';
|
||||
import { buildOrFilter, isOrFilter } from '@kbn/es-query';
|
||||
import { ConditionTypes, getConditionalOperationType } from '../utils';
|
||||
import type { Operator } from '../filter_bar/filter_editor';
|
||||
|
||||
const PATH_SEPARATOR = '.';
|
||||
|
|
|
@ -9,10 +9,4 @@
|
|||
export { onRaf } from './on_raf';
|
||||
export { shallowEqual } from './shallow_equal';
|
||||
|
||||
export type { FilterItem } from './or_filter';
|
||||
export {
|
||||
ConditionTypes,
|
||||
isOrFilter,
|
||||
getConditionalOperationType,
|
||||
buildOrFilter,
|
||||
} from './or_filter';
|
||||
export { ConditionTypes, getConditionalOperationType } from './or_filter';
|
||||
|
|
|
@ -6,20 +6,13 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
// Methods from this file will be removed after they are moved to the package
|
||||
import { buildEmptyFilter, Filter } from '@kbn/es-query';
|
||||
import { isOrFilter, FilterItem } from '@kbn/es-query';
|
||||
|
||||
export enum ConditionTypes {
|
||||
OR = 'OR',
|
||||
AND = 'AND',
|
||||
}
|
||||
|
||||
/** @internal **/
|
||||
export type FilterItem = Filter | FilterItem[];
|
||||
|
||||
/** to: @kbn/es-query **/
|
||||
export const isOrFilter = (filter: Filter) => Boolean(filter?.meta?.type === 'OR');
|
||||
|
||||
/**
|
||||
* Defines a conditional operation type (AND/OR) from the filter otherwise returns undefined.
|
||||
* @param {FilterItem} filter
|
||||
|
@ -31,17 +24,3 @@ export const getConditionalOperationType = (filter: FilterItem) => {
|
|||
return ConditionTypes.OR;
|
||||
}
|
||||
};
|
||||
|
||||
/** to: @kbn/es-query **/
|
||||
export const buildOrFilter = (filters: FilterItem) => {
|
||||
const filter = buildEmptyFilter(false);
|
||||
|
||||
return {
|
||||
...filter,
|
||||
meta: {
|
||||
...filter.meta,
|
||||
type: 'OR',
|
||||
params: filters,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue