mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Convert filter_manager/lib to TypeScript / Jest (#45785)
* Convert filter_manager/lib to TypeScript / Jest Fix: #44952 * Update map_query_string.ts * remove extra ts-ignore * formatting * fix PR comments * Fix PR comments * fix PR comments * fix PR comments * fix merge conflicts * revert logic * Fix PR commnets * add tests for compare_filters * fix PR comments
This commit is contained in:
parent
a99a5d62bf
commit
905d021c5a
65 changed files with 1663 additions and 1335 deletions
|
@ -21,6 +21,13 @@ import { Filter, FilterMeta } from './meta_filter';
|
|||
|
||||
export type ExistsFilterMeta = FilterMeta;
|
||||
|
||||
export interface FilterExistsProperty {
|
||||
field: any;
|
||||
}
|
||||
|
||||
export type ExistsFilter = Filter & {
|
||||
meta: ExistsFilterMeta;
|
||||
exists?: FilterExistsProperty;
|
||||
};
|
||||
|
||||
export const isExistsFilter = (filter: any): filter is ExistsFilter => filter && filter.exists;
|
||||
|
|
|
@ -28,4 +28,8 @@ export type GeoBoundingBoxFilterMeta = FilterMeta & {
|
|||
|
||||
export type GeoBoundingBoxFilter = Filter & {
|
||||
meta: GeoBoundingBoxFilterMeta;
|
||||
geo_bounding_box: any;
|
||||
};
|
||||
|
||||
export const isGeoBoundingBoxFilter = (filter: any): filter is GeoBoundingBoxFilter =>
|
||||
filter && filter.geo_bounding_box;
|
||||
|
|
|
@ -27,4 +27,8 @@ export type GeoPolygonFilterMeta = FilterMeta & {
|
|||
|
||||
export type GeoPolygonFilter = Filter & {
|
||||
meta: GeoPolygonFilterMeta;
|
||||
geo_polygon: any;
|
||||
};
|
||||
|
||||
export const isGeoPolygonFilter = (filter: any): filter is GeoPolygonFilter =>
|
||||
filter && filter.geo_polygon;
|
||||
|
|
|
@ -22,22 +22,38 @@ export * from './meta_filter';
|
|||
|
||||
// The actual filter types
|
||||
import { CustomFilter } from './custom_filter';
|
||||
import { ExistsFilter } from './exists_filter';
|
||||
import { GeoBoundingBoxFilter } from './geo_bounding_box_filter';
|
||||
import { GeoPolygonFilter } from './geo_polygon_filter';
|
||||
import { PhraseFilter } from './phrase_filter';
|
||||
import { PhrasesFilter } from './phrases_filter';
|
||||
import { QueryStringFilter } from './query_string_filter';
|
||||
import { RangeFilter } from './range_filter';
|
||||
import { ExistsFilter, isExistsFilter } from './exists_filter';
|
||||
import { GeoBoundingBoxFilter, isGeoBoundingBoxFilter } from './geo_bounding_box_filter';
|
||||
import { GeoPolygonFilter, isGeoPolygonFilter } from './geo_polygon_filter';
|
||||
import { PhraseFilter, isPhraseFilter, isScriptedPhraseFilter } from './phrase_filter';
|
||||
import { PhrasesFilter, isPhrasesFilter } from './phrases_filter';
|
||||
import { QueryStringFilter, isQueryStringFilter } from './query_string_filter';
|
||||
import { RangeFilter, isRangeFilter, isScriptedRangeFilter } from './range_filter';
|
||||
import { MatchAllFilter, isMatchAllFilter } from './match_all_filter';
|
||||
import { MissingFilter, isMissingFilter } from './missing_filter';
|
||||
|
||||
export {
|
||||
CustomFilter,
|
||||
ExistsFilter,
|
||||
isExistsFilter,
|
||||
GeoBoundingBoxFilter,
|
||||
isGeoBoundingBoxFilter,
|
||||
GeoPolygonFilter,
|
||||
isGeoPolygonFilter,
|
||||
PhraseFilter,
|
||||
isPhraseFilter,
|
||||
isScriptedPhraseFilter,
|
||||
PhrasesFilter,
|
||||
isPhrasesFilter,
|
||||
QueryStringFilter,
|
||||
isQueryStringFilter,
|
||||
RangeFilter,
|
||||
isRangeFilter,
|
||||
isScriptedRangeFilter,
|
||||
MatchAllFilter,
|
||||
isMatchAllFilter,
|
||||
MissingFilter,
|
||||
isMissingFilter,
|
||||
};
|
||||
|
||||
// Any filter associated with a field (used in the filter bar/editor)
|
||||
|
@ -47,4 +63,19 @@ export type FieldFilter =
|
|||
| GeoPolygonFilter
|
||||
| PhraseFilter
|
||||
| PhrasesFilter
|
||||
| RangeFilter;
|
||||
| RangeFilter
|
||||
| MatchAllFilter
|
||||
| MissingFilter;
|
||||
|
||||
export enum FILTERS {
|
||||
CUSTOM = 'custom',
|
||||
PHRASES = 'phrases',
|
||||
PHRASE = 'phrase',
|
||||
EXISTS = 'exists',
|
||||
MATCH_ALL = 'match_all',
|
||||
MISSING = 'missing',
|
||||
QUERY_STRING = 'query_string',
|
||||
RANGE = 'range',
|
||||
GEO_BOUNDING_BOX = 'geo_bounding_box',
|
||||
GEO_POLYGON = 'geo_polygon',
|
||||
}
|
||||
|
|
33
packages/kbn-es-query/src/filters/lib/match_all_filter.ts
Normal file
33
packages/kbn-es-query/src/filters/lib/match_all_filter.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { Filter, FilterMeta } from './meta_filter';
|
||||
|
||||
export interface MatchAllFilterMeta extends FilterMeta {
|
||||
field: any;
|
||||
formattedValue: string;
|
||||
}
|
||||
|
||||
export type MatchAllFilter = Filter & {
|
||||
meta: MatchAllFilterMeta;
|
||||
match_all: any;
|
||||
};
|
||||
|
||||
export const isMatchAllFilter = (filter: any): filter is MatchAllFilter =>
|
||||
filter && filter.match_all;
|
|
@ -35,12 +35,13 @@ export interface FilterMeta {
|
|||
alias: string | null;
|
||||
key?: string;
|
||||
value?: string;
|
||||
params?: any;
|
||||
}
|
||||
|
||||
export interface Filter {
|
||||
$state?: FilterState;
|
||||
meta: FilterMeta;
|
||||
query?: object;
|
||||
query?: any;
|
||||
}
|
||||
|
||||
export interface LatLon {
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { mapFilter } from './map_filter';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
|
||||
export function mapAndFlattenFilters(indexPatterns, filters) {
|
||||
const flattened = _(filters)
|
||||
.flatten()
|
||||
.compact()
|
||||
.map(item => mapFilter(indexPatterns, item)).value();
|
||||
return Promise.all(flattened);
|
||||
}
|
||||
export type MissingFilterMeta = FilterMeta;
|
||||
|
||||
export type MissingFilter = Filter & {
|
||||
meta: MissingFilterMeta;
|
||||
missing: any;
|
||||
};
|
||||
|
||||
export const isMissingFilter = (filter: any): filter is MissingFilter => filter && filter.missing;
|
|
@ -17,14 +17,27 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
|
||||
export type PhraseFilterMeta = FilterMeta & {
|
||||
params: {
|
||||
query: string; // The unformatted value
|
||||
};
|
||||
script?: {
|
||||
script: {
|
||||
params: any;
|
||||
};
|
||||
};
|
||||
field?: any;
|
||||
};
|
||||
|
||||
export type PhraseFilter = Filter & {
|
||||
meta: PhraseFilterMeta;
|
||||
};
|
||||
|
||||
export const isPhraseFilter = (filter: any): filter is PhraseFilter =>
|
||||
filter && (filter.query && filter.query.match);
|
||||
|
||||
export const isScriptedPhraseFilter = (filter: any): filter is PhraseFilter =>
|
||||
Boolean(get(filter, 'script.script.params.value'));
|
||||
|
|
|
@ -21,8 +21,12 @@ import { Filter, FilterMeta } from './meta_filter';
|
|||
|
||||
export type PhrasesFilterMeta = FilterMeta & {
|
||||
params: string[]; // The unformatted values
|
||||
field?: string;
|
||||
};
|
||||
|
||||
export type PhrasesFilter = Filter & {
|
||||
meta: PhrasesFilterMeta;
|
||||
};
|
||||
|
||||
export const isPhrasesFilter = (filter: any): filter is PhrasesFilter =>
|
||||
filter && filter.meta.type === 'phrases';
|
||||
|
|
|
@ -23,4 +23,12 @@ export type QueryStringFilterMeta = FilterMeta;
|
|||
|
||||
export type QueryStringFilter = Filter & {
|
||||
meta: QueryStringFilterMeta;
|
||||
query?: {
|
||||
query_string: {
|
||||
query: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export const isQueryStringFilter = (filter: any): filter is QueryStringFilter =>
|
||||
filter && filter.query && filter.query.query_string;
|
||||
|
|
|
@ -16,20 +16,50 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { get, keys } from 'lodash';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
|
||||
export interface RangeFilterParams {
|
||||
interface FilterRange {
|
||||
from?: number | string;
|
||||
to?: number | string;
|
||||
}
|
||||
|
||||
interface FilterRangeGt {
|
||||
gt?: number | string;
|
||||
gte?: number | string;
|
||||
lte?: number | string;
|
||||
lt?: number | string;
|
||||
}
|
||||
|
||||
interface FilterRangeGte {
|
||||
gte?: number | string;
|
||||
lte?: number | string;
|
||||
}
|
||||
|
||||
export type RangeFilterParams = FilterRange & FilterRangeGt & FilterRangeGte;
|
||||
|
||||
export type RangeFilterMeta = FilterMeta & {
|
||||
params: RangeFilterParams;
|
||||
field?: any;
|
||||
};
|
||||
|
||||
export type RangeFilter = Filter & {
|
||||
meta: RangeFilterMeta;
|
||||
script?: {
|
||||
script: {
|
||||
params: any;
|
||||
};
|
||||
};
|
||||
range: { [key: string]: RangeFilterParams };
|
||||
};
|
||||
|
||||
const hasRangeKeys = (params: RangeFilterParams) =>
|
||||
Boolean(
|
||||
keys(params).find((key: string) => ['gte', 'gt', 'lte', 'lt', 'from', 'to'].includes(key))
|
||||
);
|
||||
|
||||
export const isRangeFilter = (filter: any): filter is RangeFilter => filter && filter.range;
|
||||
|
||||
export const isScriptedRangeFilter = (filter: any): filter is RangeFilter => {
|
||||
const params: RangeFilterParams = get(filter, 'script.script.params', {});
|
||||
|
||||
return hasRangeKeys(params);
|
||||
};
|
||||
|
|
|
@ -36,4 +36,5 @@ export const rangeFilter: RangeFilter = {
|
|||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
},
|
||||
range: {},
|
||||
};
|
||||
|
|
|
@ -17,19 +17,16 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter, isFilterPinned, FilterStateStore } from '@kbn/es-query';
|
||||
import { Filter, isFilterPinned, isRangeFilter, FilterStateStore } from '@kbn/es-query';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import { UiSettingsClientContract } from 'src/core/public';
|
||||
// @ts-ignore
|
||||
import { compareFilters } from './lib/compare_filters';
|
||||
// @ts-ignore
|
||||
import { mapAndFlattenFilters } from './lib/map_and_flatten_filters';
|
||||
// @ts-ignore
|
||||
import { uniqFilters } from './lib/uniq_filters';
|
||||
|
||||
import { compareFilters } from './lib/compare_filters';
|
||||
import { mapAndFlattenFilters } from './lib/map_and_flatten_filters';
|
||||
import { uniqFilters } from './lib/uniq_filters';
|
||||
import { extractTimeFilter } from './lib/extract_time_filter';
|
||||
import { changeTimeFilter } from './lib/change_time_filter';
|
||||
import { onlyDisabledFiltersChanged } from './lib/only_disabled';
|
||||
|
@ -194,7 +191,10 @@ export class FilterManager {
|
|||
|
||||
public async addFiltersAndChangeTimeFilter(filters: Filter[]) {
|
||||
const timeFilter = await extractTimeFilter(this.indexPatterns, filters);
|
||||
if (timeFilter) changeTimeFilter(this.timefilter, timeFilter);
|
||||
|
||||
if (isRangeFilter(timeFilter)) {
|
||||
changeTimeFilter(this.timefilter, timeFilter);
|
||||
}
|
||||
return this.addFilters(filters.filter(filter => filter !== timeFilter));
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,5 @@
|
|||
export { FilterManager } from './filter_manager';
|
||||
export { FilterStateManager } from './filter_state_manager';
|
||||
|
||||
// @ts-ignore
|
||||
export { uniqFilters } from './lib/uniq_filters';
|
||||
export { onlyDisabledFiltersChanged } from './lib/only_disabled';
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { dedupFilters } from '../dedup_filters';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('dedupFilters(existing, filters)', function () {
|
||||
|
||||
it('should return only filters which are not in the existing', function () {
|
||||
const existing = [
|
||||
{ range: { bytes: { from: 0, to: 1024 } } },
|
||||
{ query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const filters = [
|
||||
{ range: { bytes: { from: 1024, to: 2048 } } },
|
||||
{ query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const results = dedupFilters(existing, filters);
|
||||
expect(results).to.contain(filters[0]);
|
||||
expect(results).to.not.contain(filters[1]);
|
||||
});
|
||||
|
||||
it('should ignore the disabled attribute when comparing ', function () {
|
||||
const existing = [
|
||||
{ range: { bytes: { from: 0, to: 1024 } } },
|
||||
{ meta: { disabled: true }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const filters = [
|
||||
{ range: { bytes: { from: 1024, to: 2048 } } },
|
||||
{ query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const results = dedupFilters(existing, filters);
|
||||
expect(results).to.contain(filters[0]);
|
||||
expect(results).to.not.contain(filters[1]);
|
||||
});
|
||||
|
||||
it('should ignore $state attribute', function () {
|
||||
const existing = [
|
||||
{ range: { bytes: { from: 0, to: 1024 } } },
|
||||
{ $state: { store: 'appState' }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const filters = [
|
||||
{ range: { bytes: { from: 1024, to: 2048 } } },
|
||||
{ $state: { store: 'globalState' }, query: { match: { _term: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const results = dedupFilters(existing, filters);
|
||||
expect(results).to.contain(filters[0]);
|
||||
expect(results).to.not.contain(filters[1]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { extractTimeFilter } from '../extract_time_filter';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('extractTimeFilter()', function () {
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
}));
|
||||
|
||||
it('should return the matching filter for the default time field', function (done) {
|
||||
const filters = [
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { _type: { query: 'apache', type: 'phrase' } } } },
|
||||
{ meta: { index: 'logstash-*' }, range: { 'time': { gt: 1388559600000, lt: 1388646000000 } } }
|
||||
];
|
||||
extractTimeFilter(mockIndexPatterns, filters).then(function (filter) {
|
||||
expect(filter).to.eql(filters[1]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not return the non-matching filter for the default time field', function (done) {
|
||||
const filters = [
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { _type: { query: 'apache', type: 'phrase' } } } },
|
||||
{ meta: { index: 'logstash-*' }, range: { '@timestamp': { gt: 1388559600000, lt: 1388646000000 } } }
|
||||
];
|
||||
extractTimeFilter(mockIndexPatterns, filters).then(function (filter) {
|
||||
expect(filter).to.be(undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 sinon from 'sinon';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { generateMappingChain } from '../generate_mapping_chain';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('generateMappingChain()', function () {
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
|
||||
it('should create a chaining function which calls the next function if the promise is rejected', function (done) {
|
||||
const filter = {};
|
||||
const mapping = sinon.stub();
|
||||
mapping.rejects(filter);
|
||||
const next = sinon.stub();
|
||||
next.resolves('good');
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
chain(filter).then(function (result) {
|
||||
expect(result).to.be('good');
|
||||
sinon.assert.calledOnce(next);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a chaining function which DOES NOT call the next function if the result is resolved', function (done) {
|
||||
const mapping = sinon.stub();
|
||||
mapping.resolves('good');
|
||||
const next = sinon.stub();
|
||||
next.resolves('bad');
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
chain({}).then(function (result) {
|
||||
expect(result).to.be('good');
|
||||
sinon.assert.notCalled(next);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should resolve result for the mapping function', function (done) {
|
||||
const mapping = sinon.stub();
|
||||
mapping.resolves({ key: 'test', value: 'example' });
|
||||
const next = sinon.stub();
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
chain({}).then(function (result) {
|
||||
sinon.assert.notCalled(next);
|
||||
expect(result).to.eql({ key: 'test', value: 'example' });
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the mapping function with the argument to the chain', function (done) {
|
||||
const mapping = sinon.stub();
|
||||
mapping.resolves({ key: 'test', value: 'example' });
|
||||
const next = sinon.stub();
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
chain({ test: 'example' }).then(function (result) {
|
||||
sinon.assert.calledOnce(mapping);
|
||||
expect(mapping.args[0][0]).to.eql({ test: 'example' });
|
||||
sinon.assert.notCalled(next);
|
||||
expect(result).to.eql({ key: 'test', value: 'example' });
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should resolve result for the next function', function (done) {
|
||||
const filter = {};
|
||||
const mapping = sinon.stub();
|
||||
mapping.rejects(filter);
|
||||
const next = sinon.stub();
|
||||
next.resolves({ key: 'test', value: 'example' });
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
chain(filter).then(function (result) {
|
||||
sinon.assert.calledOnce(mapping);
|
||||
sinon.assert.calledOnce(next);
|
||||
expect(result).to.eql({ key: 'test', value: 'example' });
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject with an error if no functions match', function (done) {
|
||||
const filter = {};
|
||||
const mapping = sinon.stub();
|
||||
mapping.rejects(filter);
|
||||
const chain = generateMappingChain(mapping);
|
||||
chain(filter).catch(function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.message).to.be('No mappings have been found for filter.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapAndFlattenFilters } from '../map_and_flatten_filters';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapAndFlattenFilters()', function () {
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
}));
|
||||
|
||||
const filters = [
|
||||
null,
|
||||
[
|
||||
{ meta: { index: 'logstash-*' }, exists: { field: '_type' } },
|
||||
{ meta: { index: 'logstash-*' }, missing: { field: '_type' } }
|
||||
],
|
||||
{ meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } },
|
||||
{ meta: { index: 'logstash-*' }, range: { bytes: { lt: 2048, gt: 1024 } } },
|
||||
{ meta: { index: 'logstash-*' }, query: { match: { _type: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
|
||||
it('should map and flatten the filters', function (done) {
|
||||
mapAndFlattenFilters(mockIndexPatterns, filters).then(function (results) {
|
||||
expect(results).to.have.length(5);
|
||||
expect(results[0]).to.have.property('meta');
|
||||
expect(results[1]).to.have.property('meta');
|
||||
expect(results[2]).to.have.property('meta');
|
||||
expect(results[3]).to.have.property('meta');
|
||||
expect(results[4]).to.have.property('meta');
|
||||
expect(results[0].meta).to.have.property('key', '_type');
|
||||
expect(results[0].meta).to.have.property('value', 'exists');
|
||||
expect(results[1].meta).to.have.property('key', '_type');
|
||||
expect(results[1].meta).to.have.property('value', 'missing');
|
||||
expect(results[2].meta).to.have.property('key', 'query');
|
||||
expect(results[2].meta).to.have.property('value', 'foo:bar');
|
||||
expect(results[3].meta).to.have.property('key', 'bytes');
|
||||
expect(results[3].meta).to.have.property('value', '1,024 to 2,048');
|
||||
expect(results[4].meta).to.have.property('key', '_type');
|
||||
expect(results[4].meta).to.have.property('value', 'apache');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import { mapDefault } from '../map_default';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapDefault()', function () {
|
||||
|
||||
it('should return the key and value for matching filters', function (done) {
|
||||
const filter = { query: { match_all: {} } };
|
||||
mapDefault(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'query');
|
||||
expect(result).to.have.property('value', '{"match_all":{}}');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with undefined filter types', function (done) {
|
||||
const filter = {
|
||||
'bool': {
|
||||
'must': {
|
||||
'term': {
|
||||
'geo.src': 'US'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
mapDefault(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'bool');
|
||||
expect(result).to.have.property('value', JSON.stringify(filter.bool));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined if there is no valid key', function (done) {
|
||||
const filter = { meta: {} };
|
||||
mapDefault(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapFilter } from '../map_filter';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
}));
|
||||
|
||||
describe('mapFilter()', function () {
|
||||
it('should map query filters', function (done) {
|
||||
const before = { meta: { index: 'logstash-*' }, query: { match: { '_type': { query: 'apache' } } } };
|
||||
mapFilter(mockIndexPatterns, before).then(function (after) {
|
||||
expect(after).to.have.property('meta');
|
||||
expect(after.meta).to.have.property('key', '_type');
|
||||
expect(after.meta).to.have.property('value', 'apache');
|
||||
expect(after.meta).to.have.property('disabled', false);
|
||||
expect(after.meta).to.have.property('negate', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should map exists filters', function (done) {
|
||||
const before = { meta: { index: 'logstash-*' }, exists: { field: '@timestamp' } };
|
||||
mapFilter(mockIndexPatterns, before).then(function (after) {
|
||||
expect(after).to.have.property('meta');
|
||||
expect(after.meta).to.have.property('key', '@timestamp');
|
||||
expect(after.meta).to.have.property('value', 'exists');
|
||||
expect(after.meta).to.have.property('disabled', false);
|
||||
expect(after.meta).to.have.property('negate', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should map missing filters', function (done) {
|
||||
const before = { meta: { index: 'logstash-*' }, missing: { field: '@timestamp' } };
|
||||
mapFilter(mockIndexPatterns, before).then(function (after) {
|
||||
expect(after).to.have.property('meta');
|
||||
expect(after.meta).to.have.property('key', '@timestamp');
|
||||
expect(after.meta).to.have.property('value', 'missing');
|
||||
expect(after.meta).to.have.property('disabled', false);
|
||||
expect(after.meta).to.have.property('negate', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should map json filter', function (done) {
|
||||
const before = { meta: { index: 'logstash-*' }, query: { match_all: {} } };
|
||||
mapFilter(mockIndexPatterns, before).then(function (after) {
|
||||
expect(after).to.have.property('meta');
|
||||
expect(after.meta).to.have.property('key', 'query');
|
||||
expect(after.meta).to.have.property('value', '{"match_all":{}}');
|
||||
expect(after.meta).to.have.property('disabled', false);
|
||||
expect(after.meta).to.have.property('negate', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should finish with a catch', function (done) {
|
||||
const before = { meta: { index: 'logstash-*' } };
|
||||
mapFilter(mockIndexPatterns, before).catch(function (error) {
|
||||
expect(error).to.be.an(Error);
|
||||
expect(error.message).to.be('No mappings have been found for filter.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapGeoBoundingBox } from '../map_geo_bounding_box';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapGeoBoundingBox()', function () {
|
||||
let mapGeoBoundingBoxFn;
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
mapGeoBoundingBoxFn = mapGeoBoundingBox(mockIndexPatterns);
|
||||
}));
|
||||
|
||||
it('should return the key and value for matching filters with bounds', function (done) {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*'
|
||||
},
|
||||
geo_bounding_box: {
|
||||
point: { // field name
|
||||
top_left: { lat: 5, lon: 10 },
|
||||
bottom_right: { lat: 15, lon: 20 }
|
||||
}
|
||||
}
|
||||
};
|
||||
mapGeoBoundingBoxFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'point');
|
||||
expect(result).to.have.property('value');
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).to.be('lat5lon10tolat15lon20');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } };
|
||||
mapGeoBoundingBoxFn(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the key and value even when using ignore_unmapped', function (done) {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*'
|
||||
},
|
||||
geo_bounding_box: {
|
||||
ignore_unmapped: true,
|
||||
point: { // field name
|
||||
top_left: { lat: 5, lon: 10 },
|
||||
bottom_right: { lat: 15, lon: 20 }
|
||||
}
|
||||
}
|
||||
};
|
||||
mapGeoBoundingBoxFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'point');
|
||||
expect(result).to.have.property('value');
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).to.be('lat5lon10tolat15lon20');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapGeoPolygon } from '../map_geo_polygon';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapGeoPolygon()', function () {
|
||||
let mapGeoPolygonFn;
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
mapGeoPolygonFn = mapGeoPolygon(mockIndexPatterns);
|
||||
}));
|
||||
|
||||
it('should return the key and value for matching filters with bounds', function (done) {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*'
|
||||
},
|
||||
geo_polygon: {
|
||||
point: { // field name
|
||||
points: [
|
||||
{ lat: 5, lon: 10 },
|
||||
{ lat: 15, lon: 20 }
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
mapGeoPolygonFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'point');
|
||||
expect(result).to.have.property('value');
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).to.be('lat5lon10lat15lon20');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } };
|
||||
mapGeoPolygonFn(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the key and value even when using ignore_unmapped', function (done) {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*'
|
||||
},
|
||||
geo_polygon: {
|
||||
ignore_unmapped: true,
|
||||
point: { // field name
|
||||
points: [
|
||||
{ lat: 5, lon: 10 },
|
||||
{ lat: 15, lon: 20 }
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
mapGeoPolygonFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'point');
|
||||
expect(result).to.have.property('value');
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).to.be('lat5lon10lat15lon20');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapMatchAll } from '../map_match_all';
|
||||
|
||||
describe('filter_manager/lib', function () {
|
||||
describe('mapMatchAll()', function () {
|
||||
let filter;
|
||||
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function () {
|
||||
filter = {
|
||||
match_all: {},
|
||||
meta: {
|
||||
field: 'foo',
|
||||
formattedValue: 'bar'
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
describe('when given a filter that is not match_all', function () {
|
||||
it('filter is rejected', function (done) {
|
||||
delete filter.match_all;
|
||||
mapMatchAll(filter).catch(result => {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a match_all filter', function () {
|
||||
let result;
|
||||
beforeEach(function (done) {
|
||||
mapMatchAll(filter).then(r => {
|
||||
result = r;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('key is set to meta field', function () {
|
||||
expect(result).to.have.property('key', filter.meta.field);
|
||||
});
|
||||
|
||||
it('value is set to meta formattedValue', function () {
|
||||
expect(result).to.have.property('value', filter.meta.formattedValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapPhrase } from '../map_phrase';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapPhrase()', function () {
|
||||
let mapPhraseFn;
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
mapPhraseFn = mapPhrase(mockIndexPatterns);
|
||||
}));
|
||||
|
||||
it('should return the key and value for matching filters', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, query: { match: { _type: { query: 'apache', type: 'phrase' } } } };
|
||||
mapPhraseFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', '_type');
|
||||
expect(result).to.have.property('value', 'apache');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } };
|
||||
mapPhraseFn(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapRange } from '../map_range';
|
||||
import IndexPatternMock from 'fixtures/mock_index_patterns';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapRange()', function () {
|
||||
let mapRangeFn;
|
||||
let mockIndexPatterns;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/courier'
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
mockIndexPatterns = Private(IndexPatternMock);
|
||||
mapRangeFn = mapRange(mockIndexPatterns);
|
||||
}));
|
||||
|
||||
it('should return the key and value for matching filters with gt/lt', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, range: { bytes: { lt: 2048, gt: 1024 } } };
|
||||
mapRangeFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'bytes');
|
||||
expect(result).to.have.property('value', '1,024 to 2,048');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the key and value for matching filters with gte/lte', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, range: { bytes: { lte: 2048, gte: 1024 } } };
|
||||
mapRangeFn(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'bytes');
|
||||
expect(result).to.have.property('value', '1,024 to 2,048');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } };
|
||||
mapRangeFn(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { uniqFilters } from '../uniq_filters';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('uniqFilter', function () {
|
||||
|
||||
it('should filter out dups', function () {
|
||||
const before = [
|
||||
{ query: { _type: { match: { query: 'apache', type: 'phrase' } } } },
|
||||
{ query: { _type: { match: { query: 'apache', type: 'phrase' } } } }
|
||||
];
|
||||
const results = uniqFilters(before);
|
||||
expect(results).to.have.length(1);
|
||||
});
|
||||
|
||||
it('should filter out duplicates, ignoring meta attributes', function () {
|
||||
const before = [
|
||||
{
|
||||
meta: { negate: true },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
},
|
||||
{
|
||||
meta: { negate: false },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
}
|
||||
];
|
||||
const results = uniqFilters(before);
|
||||
expect(results).to.have.length(1);
|
||||
});
|
||||
|
||||
it('should filter out duplicates, ignoring $state attributes', function () {
|
||||
const before = [
|
||||
{
|
||||
$state: { store: 'appState' },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
},
|
||||
{
|
||||
$state: { store: 'globalState' },
|
||||
query: { _type: { match: { query: 'apache', type: 'phrase' } } }
|
||||
}
|
||||
];
|
||||
const results = uniqFilters(before);
|
||||
expect(results).to.have.length(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,15 +16,16 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import expect from '@kbn/expect';
|
||||
import { changeTimeFilter } from '../change_time_filter';
|
||||
import { RangeFilter } from '@kbn/es-query';
|
||||
import { changeTimeFilter } from './change_time_filter';
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { timefilterServiceMock } from '../../../timefilter/timefilter_service.mock';
|
||||
|
||||
import { timefilterServiceMock } from '../../../../timefilter/timefilter_service.mock';
|
||||
const timefilterMock = timefilterServiceMock.createSetupContract();
|
||||
const timefilter = timefilterMock.timefilter;
|
||||
|
||||
let _time: TimeRange | undefined;
|
||||
|
||||
timefilter.setTime.mockImplementation((time: any) => {
|
||||
_time = {
|
||||
from: time.from.toISOString(),
|
||||
|
@ -35,23 +36,27 @@ timefilter.getTime.mockImplementation(() => {
|
|||
return _time!;
|
||||
});
|
||||
|
||||
describe('changeTimeFilter()', function() {
|
||||
describe('changeTimeFilter()', () => {
|
||||
const gt = 1388559600000;
|
||||
const lt = 1388646000000;
|
||||
|
||||
test('should change the timefilter to match the range gt/lt', function() {
|
||||
const filter = { range: { '@timestamp': { gt, lt } } };
|
||||
changeTimeFilter(timefilter, filter);
|
||||
test('should change the timefilter to match the range gt/lt', () => {
|
||||
const filter: any = { range: { '@timestamp': { gt, lt } } };
|
||||
changeTimeFilter(timefilter, filter as RangeFilter);
|
||||
|
||||
const { to, from } = timefilter.getTime();
|
||||
expect(to).to.be(new Date(lt).toISOString());
|
||||
expect(from).to.be(new Date(gt).toISOString());
|
||||
|
||||
expect(to).toBe(new Date(lt).toISOString());
|
||||
expect(from).toBe(new Date(gt).toISOString());
|
||||
});
|
||||
|
||||
test('should change the timefilter to match the range gte/lte', function() {
|
||||
const filter = { range: { '@timestamp': { gte: gt, lte: lt } } };
|
||||
changeTimeFilter(timefilter, filter);
|
||||
test('should change the timefilter to match the range gte/lte', () => {
|
||||
const filter: any = { range: { '@timestamp': { gte: gt, lte: lt } } };
|
||||
changeTimeFilter(timefilter, filter as RangeFilter);
|
||||
|
||||
const { to, from } = timefilter.getTime();
|
||||
expect(to).to.be(new Date(lt).toISOString());
|
||||
expect(from).to.be(new Date(gt).toISOString());
|
||||
|
||||
expect(to).toBe(new Date(lt).toISOString());
|
||||
expect(from).toBe(new Date(gt).toISOString());
|
||||
});
|
||||
});
|
|
@ -18,14 +18,18 @@
|
|||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
import { keys } from 'lodash';
|
||||
import { RangeFilter, isRangeFilter } from '@kbn/es-query';
|
||||
import { TimefilterContract } from '../../../timefilter';
|
||||
|
||||
export function changeTimeFilter(timefilter: TimefilterContract, filter: any) {
|
||||
const key = _.keys(filter.range)[0];
|
||||
const values = filter.range[key];
|
||||
timefilter.setTime({
|
||||
from: moment(values.gt || values.gte),
|
||||
to: moment(values.lt || values.lte),
|
||||
});
|
||||
export function changeTimeFilter(timeFilter: TimefilterContract, filter: RangeFilter) {
|
||||
if (isRangeFilter(filter)) {
|
||||
const key = keys(filter.range)[0];
|
||||
const values = filter.range[key];
|
||||
|
||||
timeFilter.setTime({
|
||||
from: moment(values.gt || values.gte),
|
||||
to: moment(values.lt || values.lte),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { buildQueryFilter, buildEmptyFilter, FilterStateStore } from '@kbn/es-query';
|
||||
import { compareFilters } from './compare_filters';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('compare filters', () => {
|
||||
test('should compare filters', () => {
|
||||
const f1 = buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'index'
|
||||
);
|
||||
const f2 = buildEmptyFilter(true);
|
||||
|
||||
expect(compareFilters(f1, f2)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should compare duplicates', () => {
|
||||
const f1 = buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'index'
|
||||
);
|
||||
const f2 = buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'index'
|
||||
);
|
||||
|
||||
expect(compareFilters(f1, f2)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should compare duplicates, ignoring meta attributes', () => {
|
||||
const f1 = buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'index1'
|
||||
);
|
||||
const f2 = buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'index2'
|
||||
);
|
||||
|
||||
expect(compareFilters(f1, f2)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should compare duplicates, ignoring $state attributes', () => {
|
||||
const f1 = {
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
};
|
||||
const f2 = {
|
||||
$state: { store: FilterStateStore.GLOBAL_STATE },
|
||||
...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
};
|
||||
|
||||
expect(compareFilters(f1, f2)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,20 +17,31 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
let excludedAttributes;
|
||||
let comparators;
|
||||
import { Filter, FilterMeta } from '@kbn/es-query';
|
||||
import { defaults, isEqual, omit } from 'lodash';
|
||||
|
||||
/**
|
||||
* Compare two filters to see if they match
|
||||
*
|
||||
* @param {object} first The first filter to compare
|
||||
* @param {object} second The second filter to compare
|
||||
* @param {object} comparatorOptions Parameters to use for comparison
|
||||
*
|
||||
* @returns {bool} Filters are the same
|
||||
*/
|
||||
export function compareFilters(first, second, comparatorOptions) {
|
||||
excludedAttributes = ['$$hashKey', 'meta'];
|
||||
comparators = _.defaults(comparatorOptions || {}, {
|
||||
export const compareFilters = (first: Filter, second: Filter, comparatorOptions: any = {}) => {
|
||||
let comparators: any = {};
|
||||
const mapFilter = (filter: Filter) => {
|
||||
const cleaned: FilterMeta = omit(filter, excludedAttributes);
|
||||
|
||||
if (comparators.negate) cleaned.negate = filter.meta && Boolean(filter.meta.negate);
|
||||
if (comparators.disabled) cleaned.disabled = filter.meta && Boolean(filter.meta.disabled);
|
||||
|
||||
return cleaned;
|
||||
};
|
||||
const excludedAttributes: string[] = ['$$hashKey', 'meta'];
|
||||
|
||||
comparators = defaults(comparatorOptions || {}, {
|
||||
state: false,
|
||||
negate: false,
|
||||
disabled: false,
|
||||
|
@ -38,12 +49,5 @@ export function compareFilters(first, second, comparatorOptions) {
|
|||
|
||||
if (!comparators.state) excludedAttributes.push('$state');
|
||||
|
||||
return _.isEqual(mapFilter(first), mapFilter(second));
|
||||
}
|
||||
|
||||
function mapFilter(filter) {
|
||||
const cleaned = _.omit(filter, excludedAttributes);
|
||||
if (comparators.negate) cleaned.negate = filter.meta && !!filter.meta.negate;
|
||||
if (comparators.disabled) cleaned.disabled = filter.meta && !!filter.meta.disabled;
|
||||
return cleaned;
|
||||
}
|
||||
return isEqual(mapFilter(first), mapFilter(second));
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { Filter, buildRangeFilter, FilterStateStore, buildQueryFilter } from '@kbn/es-query';
|
||||
import { dedupFilters } from './dedup_filters';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('dedupFilters(existing, filters)', () => {
|
||||
test('should return only filters which are not in the existing', () => {
|
||||
const existing: Filter[] = [
|
||||
buildRangeFilter({ name: 'bytes' }, { from: 0, to: 1024 }, 'index'),
|
||||
buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
];
|
||||
const filters: Filter[] = [
|
||||
buildRangeFilter({ name: 'bytes' }, { from: 1024, to: 2048 }, 'index'),
|
||||
buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
];
|
||||
const results = dedupFilters(existing, filters);
|
||||
|
||||
expect(results).toContain(filters[0]);
|
||||
expect(results).not.toContain(filters[1]);
|
||||
});
|
||||
|
||||
test('should ignore the disabled attribute when comparing ', () => {
|
||||
const existing: Filter[] = [
|
||||
buildRangeFilter({ name: 'bytes' }, { from: 0, to: 1024 }, 'index'),
|
||||
{
|
||||
...buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
meta: { disabled: true, negate: false, alias: null },
|
||||
},
|
||||
];
|
||||
const filters: Filter[] = [
|
||||
buildRangeFilter({ name: 'bytes' }, { from: 1024, to: 2048 }, 'index'),
|
||||
buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
];
|
||||
const results = dedupFilters(existing, filters);
|
||||
|
||||
expect(results).toContain(filters[0]);
|
||||
expect(results).not.toContain(filters[1]);
|
||||
});
|
||||
|
||||
test('should ignore $state attribute', () => {
|
||||
const existing: Filter[] = [
|
||||
buildRangeFilter({ name: 'bytes' }, { from: 0, to: 1024 }, 'index'),
|
||||
{
|
||||
...buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
},
|
||||
];
|
||||
const filters: Filter[] = [
|
||||
buildRangeFilter({ name: 'bytes' }, { from: 1024, to: 2048 }, 'index'),
|
||||
{
|
||||
...buildQueryFilter({ match: { _term: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
$state: { store: FilterStateStore.GLOBAL_STATE },
|
||||
},
|
||||
];
|
||||
const results = dedupFilters(existing, filters);
|
||||
|
||||
expect(results).toContain(filters[0]);
|
||||
expect(results).not.toContain(filters[1]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,22 +17,33 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { filter, find } from 'lodash';
|
||||
import { compareFilters } from './compare_filters';
|
||||
|
||||
/**
|
||||
* Combine 2 filter collections, removing duplicates
|
||||
* @param {object} existing The filters to compare to
|
||||
* @param {object} filters The filters being added
|
||||
* @param {object} comparatorOptions Parameters to use for comparison
|
||||
*
|
||||
* @param {object} existingFilters - The filters to compare to
|
||||
* @param {object} filters - The filters being added
|
||||
* @param {object} comparatorOptions - Parameters to use for comparison
|
||||
*
|
||||
* @returns {object} An array of filters that were not in existing
|
||||
*/
|
||||
export function dedupFilters(existingFilters, filters, comparatorOptions) {
|
||||
if (!Array.isArray(filters)) filters = [filters];
|
||||
export const dedupFilters = (
|
||||
existingFilters: Filter[],
|
||||
filters: Filter[],
|
||||
comparatorOptions: any = {}
|
||||
) => {
|
||||
if (!Array.isArray(filters)) {
|
||||
filters = [filters];
|
||||
}
|
||||
|
||||
return _.filter(filters, function (filter) {
|
||||
return !_.find(existingFilters, function (existingFilter) {
|
||||
return compareFilters(existingFilter, filter, comparatorOptions);
|
||||
});
|
||||
});
|
||||
}
|
||||
return filter(
|
||||
filters,
|
||||
(f: Filter) =>
|
||||
!find(existingFilters, (existingFilter: Filter) =>
|
||||
compareFilters(existingFilter, f, comparatorOptions)
|
||||
)
|
||||
);
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { Filter, buildRangeFilter, buildQueryFilter } from '@kbn/es-query';
|
||||
import { extractTimeFilter } from './extract_time_filter';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
const mockIndexPatterns = jest.fn(
|
||||
() =>
|
||||
({
|
||||
get: () => ({
|
||||
timeFieldName: 'time',
|
||||
}),
|
||||
} as any)
|
||||
);
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('extractTimeFilter()', () => {
|
||||
const indexPatterns = mockIndexPatterns() as IndexPatterns;
|
||||
|
||||
test('should return the matching filter for the default time field', async () => {
|
||||
const filters: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'),
|
||||
buildRangeFilter({ name: 'time' }, { gt: 1388559600000, lt: 1388646000000 }, 'logstash-*'),
|
||||
];
|
||||
const result = await extractTimeFilter(indexPatterns, filters);
|
||||
|
||||
expect(result).toEqual(filters[1]);
|
||||
});
|
||||
|
||||
test('should not return the non-matching filter for the default time field', async () => {
|
||||
const filters: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'),
|
||||
buildRangeFilter({ name: '@timestamp' }, { from: 1, to: 2 }, 'logstash-*'),
|
||||
];
|
||||
const result = await extractTimeFilter(indexPatterns, filters);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,22 +17,25 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { keys, find, get } from 'lodash';
|
||||
import { Filter, isRangeFilter } from '@kbn/es-query';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
export async function extractTimeFilter(indexPatterns: IndexPatterns, filters: any) {
|
||||
export async function extractTimeFilter(indexPatterns: IndexPatterns, filters: Filter[]) {
|
||||
// Assume all the index patterns are the same since they will be added
|
||||
// from the same visualization.
|
||||
const id: string = _.get(filters, '[0].meta.index');
|
||||
const id: string = get(filters, '[0].meta.index');
|
||||
if (id == null) return;
|
||||
|
||||
const indexPattern = await indexPatterns.get(id);
|
||||
|
||||
const filter = _.find(filters, function(obj: any) {
|
||||
const key = _.keys(obj.range)[0];
|
||||
return key === indexPattern.timeFieldName;
|
||||
return find(filters, (obj: Filter) => {
|
||||
let key;
|
||||
|
||||
if (isRangeFilter(obj)) {
|
||||
key = keys(obj.range)[0];
|
||||
}
|
||||
|
||||
return Boolean(key && key === indexPattern.timeFieldName);
|
||||
});
|
||||
if (filter && filter.range) {
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 sinon from 'sinon';
|
||||
import { Filter, buildEmptyFilter } from '@kbn/es-query';
|
||||
import { generateMappingChain } from './generate_mapping_chain';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
let mapping: any;
|
||||
let next: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mapping = sinon.stub();
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
describe('generateMappingChain()', () => {
|
||||
test('should create a chaining function which calls the next function if the promise is rejected', async () => {
|
||||
const filter: Filter = buildEmptyFilter(true);
|
||||
|
||||
mapping.rejects(filter);
|
||||
next.resolves('good');
|
||||
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
const result = await chain(filter);
|
||||
|
||||
expect(result).toBe('good');
|
||||
sinon.assert.calledOnce(next);
|
||||
});
|
||||
|
||||
test('should create a chaining function which DOES NOT call the next function if the result is resolved', async () => {
|
||||
const filter: Filter = buildEmptyFilter(true);
|
||||
|
||||
mapping.resolves('good');
|
||||
next.resolves('bad');
|
||||
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
const result = await chain(filter);
|
||||
|
||||
expect(result).toBe('good');
|
||||
});
|
||||
|
||||
test('should resolve result for the mapping function', async () => {
|
||||
const filter: Filter = buildEmptyFilter(true);
|
||||
|
||||
mapping.resolves({ key: 'test', value: 'example' });
|
||||
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
const result = await chain(filter);
|
||||
|
||||
sinon.assert.notCalled(next);
|
||||
expect(result).toEqual({ key: 'test', value: 'example' });
|
||||
});
|
||||
|
||||
test('should call the mapping function with the argument to the chain', async () => {
|
||||
// @ts-ignore
|
||||
const filter: Filter = { test: 'example' };
|
||||
|
||||
mapping.resolves({ key: 'test', value: 'example' });
|
||||
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
const result = await chain(filter);
|
||||
|
||||
sinon.assert.calledOnce(mapping);
|
||||
expect(mapping.args[0][0]).toEqual({ test: 'example' });
|
||||
sinon.assert.notCalled(next);
|
||||
expect(result).toEqual({ key: 'test', value: 'example' });
|
||||
});
|
||||
|
||||
test('should resolve result for the next function', async () => {
|
||||
const filter: Filter = buildEmptyFilter(true);
|
||||
|
||||
mapping.rejects(filter);
|
||||
next.resolves({ key: 'test', value: 'example' });
|
||||
|
||||
const chain = generateMappingChain(mapping, next);
|
||||
const result = await chain(filter);
|
||||
|
||||
sinon.assert.calledOnce(mapping);
|
||||
sinon.assert.calledOnce(next);
|
||||
expect(result).toEqual({ key: 'test', value: 'example' });
|
||||
});
|
||||
|
||||
test('should reject with an error if no functions match', async done => {
|
||||
const filter: Filter = buildEmptyFilter(true);
|
||||
|
||||
mapping.rejects(filter);
|
||||
|
||||
const chain = generateMappingChain(mapping);
|
||||
|
||||
chain(filter).catch(err => {
|
||||
expect(err).toBeInstanceOf(Error);
|
||||
expect(err.message).toBe('No mappings have been found for filter.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,19 +16,19 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Filter } from '@kbn/es-query';
|
||||
|
||||
export function generateMappingChain(fn, next) {
|
||||
const noop = function () {
|
||||
throw new Error('No mappings have been found for filter.');
|
||||
};
|
||||
const noop = () => {
|
||||
throw new Error('No mappings have been found for filter.');
|
||||
};
|
||||
|
||||
next = next || noop;
|
||||
return async function (filter) {
|
||||
return await fn(filter).catch(function (result) {
|
||||
export const generateMappingChain = (fn: Function, next: Function = noop) => {
|
||||
return async (filter: Filter) => {
|
||||
return await fn(filter).catch((result: any) => {
|
||||
if (result === filter) {
|
||||
return next(filter);
|
||||
}
|
||||
throw result;
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { Filter } from '@kbn/es-query';
|
||||
import { mapAndFlattenFilters } from './map_and_flatten_filters';
|
||||
import { StubIndexPatterns } from '../test_helpers/stub_index_pattern';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapAndFlattenFilters()', () => {
|
||||
let mockIndexPatterns: unknown;
|
||||
let filters: unknown;
|
||||
|
||||
beforeEach(() => {
|
||||
mockIndexPatterns = new StubIndexPatterns();
|
||||
filters = [
|
||||
null,
|
||||
[
|
||||
{ meta: { index: 'logstash-*' }, exists: { field: '_type' } },
|
||||
{ meta: { index: 'logstash-*' }, missing: { field: '_type' } },
|
||||
],
|
||||
{ meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } },
|
||||
{ meta: { index: 'logstash-*' }, range: { bytes: { lt: 2048, gt: 1024 } } },
|
||||
{
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { match: { _type: { query: 'apache', type: 'phrase' } } },
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
test('should map and flatten the filters', async () => {
|
||||
const results = await mapAndFlattenFilters(
|
||||
mockIndexPatterns as IndexPatterns,
|
||||
filters as Filter[]
|
||||
);
|
||||
|
||||
expect(results).toHaveLength(5);
|
||||
expect(results[0]).toHaveProperty('meta');
|
||||
expect(results[1]).toHaveProperty('meta');
|
||||
expect(results[2]).toHaveProperty('meta');
|
||||
expect(results[3]).toHaveProperty('meta');
|
||||
expect(results[4]).toHaveProperty('meta');
|
||||
expect(results[0].meta).toHaveProperty('key', '_type');
|
||||
expect(results[0].meta).toHaveProperty('value', 'exists');
|
||||
expect(results[1].meta).toHaveProperty('key', '_type');
|
||||
expect(results[1].meta).toHaveProperty('value', 'missing');
|
||||
expect(results[2].meta).toHaveProperty('key', 'query');
|
||||
expect(results[2].meta).toHaveProperty('value', 'foo:bar');
|
||||
expect(results[3].meta).toHaveProperty('key', 'bytes');
|
||||
expect(results[3].meta).toHaveProperty('value', '1024 to 2048');
|
||||
expect(results[4].meta).toHaveProperty('key', '_type');
|
||||
expect(results[4].meta).toHaveProperty('value', 'apache');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { compact, flatten } from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { mapFilter } from './map_filter';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
export const mapAndFlattenFilters = (indexPatterns: IndexPatterns, filters: Filter[]) => {
|
||||
const promises = compact(flatten(filters)).map((item: Filter) => mapFilter(indexPatterns, item));
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
|
@ -16,29 +16,27 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { CustomFilter, buildEmptyFilter, buildQueryFilter } from '@kbn/es-query';
|
||||
import { mapDefault } from './map_default';
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { mapMissing } from '../map_missing';
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapDefault()', () => {
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
const filter: CustomFilter = buildQueryFilter({ match_all: {} }, 'index');
|
||||
const result = await mapDefault(filter);
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapMissing()', function () {
|
||||
|
||||
it('should return the key and value for matching filters', function (done) {
|
||||
const filter = { missing: { field: '_type' } };
|
||||
mapMissing(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', '_type');
|
||||
expect(result).to.have.property('value', 'missing');
|
||||
done();
|
||||
});
|
||||
expect(result).toHaveProperty('key', 'query');
|
||||
expect(result).toHaveProperty('value', '{"match_all":{}}');
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { query: { match: { query: 'foo' } } };
|
||||
mapMissing(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
test('should return undefined if there is no valid key', async () => {
|
||||
const filter = buildEmptyFilter(true) as CustomFilter;
|
||||
|
||||
try {
|
||||
await mapDefault(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,21 +17,19 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import { Filter, FILTERS } from '@kbn/es-query';
|
||||
import { find, keys, get } from 'lodash';
|
||||
|
||||
export async function mapDefault(filter) {
|
||||
export const mapDefault = async (filter: Filter) => {
|
||||
const metaProperty = /(^\$|meta)/;
|
||||
|
||||
const key = _.find(_.keys(filter), function (key) {
|
||||
return !key.match(metaProperty);
|
||||
});
|
||||
const key = find(keys(filter), item => !item.match(metaProperty));
|
||||
|
||||
if (key) {
|
||||
const type = 'custom';
|
||||
const value = angular.toJson(filter[key]);
|
||||
const type = FILTERS.CUSTOM;
|
||||
const value = JSON.stringify(get(filter, key, {}));
|
||||
|
||||
return { type, key, value };
|
||||
}
|
||||
|
||||
throw filter;
|
||||
}
|
||||
};
|
|
@ -16,29 +16,29 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ExistsFilter, buildEmptyFilter, buildExistsFilter } from '@kbn/es-query';
|
||||
import { mapExists } from './map_exists';
|
||||
import { mapQueryString } from './map_query_string';
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { mapQueryString } from '../map_query_string';
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapExists()', () => {
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
const filter: ExistsFilter = buildExistsFilter({ name: '_type' }, 'index');
|
||||
const result = await mapExists(filter);
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapQueryString()', function () {
|
||||
|
||||
it('should return the key and value for matching filters', function (done) {
|
||||
const filter = { query: { query_string: { query: 'foo:bar' } } };
|
||||
mapQueryString(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', 'query');
|
||||
expect(result).to.have.property('value', 'foo:bar');
|
||||
done();
|
||||
});
|
||||
expect(result).toHaveProperty('key', '_type');
|
||||
expect(result).toHaveProperty('value', 'exists');
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { query: { match: { query: 'foo' } } };
|
||||
mapQueryString(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = buildEmptyFilter(true) as ExistsFilter;
|
||||
|
||||
try {
|
||||
await mapQueryString(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,12 +17,16 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export async function mapQueryString(filter) {
|
||||
if (filter.query && filter.query.query_string) {
|
||||
const type = 'query_string';
|
||||
const key = 'query';
|
||||
const value = filter.query.query_string.query;
|
||||
return { type, key, value };
|
||||
import { Filter, isExistsFilter, FILTERS } from '@kbn/es-query';
|
||||
import { get } from 'lodash';
|
||||
|
||||
export const mapExists = async (filter: Filter) => {
|
||||
if (isExistsFilter(filter)) {
|
||||
return {
|
||||
type: FILTERS.EXISTS,
|
||||
value: FILTERS.EXISTS,
|
||||
key: get(filter, 'exists.field'),
|
||||
};
|
||||
}
|
||||
throw filter;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { Filter } from '@kbn/es-query';
|
||||
import { mapFilter } from './map_filter';
|
||||
import { StubIndexPatterns } from '../test_helpers/stub_index_pattern';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
let indexPatterns: IndexPatterns;
|
||||
|
||||
beforeEach(() => {
|
||||
const stubIndexPatterns: unknown = new StubIndexPatterns();
|
||||
|
||||
indexPatterns = stubIndexPatterns as IndexPatterns;
|
||||
});
|
||||
|
||||
describe('mapFilter()', () => {
|
||||
test('should map query filters', async () => {
|
||||
const before = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { match: { _type: { query: 'apache' } } },
|
||||
};
|
||||
const after = await mapFilter(indexPatterns, before as Filter);
|
||||
|
||||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', '_type');
|
||||
expect(after.meta).toHaveProperty('value', 'apache');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
||||
test('should map exists filters', async () => {
|
||||
const before: any = { meta: { index: 'logstash-*' }, exists: { field: '@timestamp' } };
|
||||
const after = await mapFilter(indexPatterns, before as Filter);
|
||||
|
||||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', '@timestamp');
|
||||
expect(after.meta).toHaveProperty('value', 'exists');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
||||
test('should map missing filters', async () => {
|
||||
const before: any = { meta: { index: 'logstash-*' }, missing: { field: '@timestamp' } };
|
||||
const after = await mapFilter(indexPatterns, before as Filter);
|
||||
|
||||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', '@timestamp');
|
||||
expect(after.meta).toHaveProperty('value', 'missing');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
||||
test('should map json filter', async () => {
|
||||
const before: any = { meta: { index: 'logstash-*' }, query: { match_all: {} } };
|
||||
const after = await mapFilter(indexPatterns, before as Filter);
|
||||
|
||||
expect(after).toHaveProperty('meta');
|
||||
expect(after.meta).toHaveProperty('key', 'query');
|
||||
expect(after.meta).toHaveProperty('value', '{"match_all":{}}');
|
||||
expect(after.meta).toHaveProperty('disabled', false);
|
||||
expect(after.meta).toHaveProperty('negate', false);
|
||||
});
|
||||
|
||||
test('should finish with a catch', async done => {
|
||||
const before: any = { meta: { index: 'logstash-*' } };
|
||||
|
||||
try {
|
||||
await mapFilter(indexPatterns, before as Filter);
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
expect(e.message).toBe('No mappings have been found for filter.');
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,7 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { reduceRight } from 'lodash';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
import { mapMatchAll } from './map_match_all';
|
||||
import { mapPhrase } from './map_phrase';
|
||||
import { mapPhrases } from './map_phrases';
|
||||
|
@ -30,7 +33,7 @@ import { mapGeoPolygon } from './map_geo_polygon';
|
|||
import { mapDefault } from './map_default';
|
||||
import { generateMappingChain } from './generate_mapping_chain';
|
||||
|
||||
export async function mapFilter(indexPatterns, filter) {
|
||||
export async function mapFilter(indexPatterns: IndexPatterns, filter: Filter) {
|
||||
/** Mappers **/
|
||||
|
||||
// Each mapper is a simple promise function that test if the mapper can
|
||||
|
@ -60,16 +63,17 @@ export async function mapFilter(indexPatterns, filter) {
|
|||
mapDefault,
|
||||
];
|
||||
|
||||
const noop = function () {
|
||||
const noop = () => {
|
||||
throw new Error('No mappings have been found for filter.');
|
||||
};
|
||||
|
||||
// Create a chain of responsibility by reducing all the
|
||||
// mappers down into one function.
|
||||
const mapFn = _.reduceRight(mappers, function (memo, map) {
|
||||
return generateMappingChain(map, memo);
|
||||
}, noop);
|
||||
|
||||
const mapFn = reduceRight<Function, Function>(
|
||||
mappers,
|
||||
(memo, map) => generateMappingChain(map, memo),
|
||||
noop
|
||||
);
|
||||
const mapped = await mapFn(filter);
|
||||
|
||||
// Map the filter into an object with the key and value exposed so it's
|
||||
|
@ -79,8 +83,8 @@ export async function mapFilter(indexPatterns, filter) {
|
|||
filter.meta.key = mapped.key;
|
||||
filter.meta.value = mapped.value;
|
||||
filter.meta.params = mapped.params;
|
||||
filter.meta.disabled = !!(filter.meta.disabled);
|
||||
filter.meta.negate = !!(filter.meta.negate);
|
||||
filter.meta.disabled = Boolean(filter.meta.disabled);
|
||||
filter.meta.negate = Boolean(filter.meta.negate);
|
||||
filter.meta.alias = filter.meta.alias || null;
|
||||
|
||||
return filter;
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 _ from 'lodash';
|
||||
import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public';
|
||||
|
||||
function getParams(filter, indexPattern) {
|
||||
const type = 'geo_bounding_box';
|
||||
const key = _.keys(filter.geo_bounding_box)
|
||||
.filter(key => key !== 'ignore_unmapped')[0];
|
||||
const params = filter.geo_bounding_box[key];
|
||||
|
||||
// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
|
||||
// for example a user might manually edit the url or the index pattern's ID might change due to
|
||||
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
|
||||
// on displaying the raw value if the index is invalid.
|
||||
const topLeft = indexPattern
|
||||
? indexPattern.fields.byName[key].format.convert(params.top_left)
|
||||
: JSON.stringify(params.top_left);
|
||||
const bottomRight = indexPattern
|
||||
? indexPattern.fields.byName[key].format.convert(params.bottom_right)
|
||||
: JSON.stringify(params.bottom_right);
|
||||
const value = topLeft + ' to ' + bottomRight;
|
||||
return { type, key, value, params };
|
||||
}
|
||||
|
||||
export function mapGeoBoundingBox(indexPatterns) {
|
||||
return async function (filter) {
|
||||
if (!filter.geo_bounding_box) {
|
||||
throw filter;
|
||||
}
|
||||
try {
|
||||
const indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
return getParams(filter, indexPattern);
|
||||
} catch (error) {
|
||||
if (error instanceof SavedObjectNotFound) {
|
||||
return getParams(filter);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { mapGeoBoundingBox } from './map_geo_bounding_box';
|
||||
import { StubIndexPatterns } from '../test_helpers/stub_index_pattern';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapGeoBoundingBox()', () => {
|
||||
let mapGeoBoundingBoxFn: Function;
|
||||
|
||||
beforeEach(() => {
|
||||
const indexPatterns: unknown = new StubIndexPatterns();
|
||||
|
||||
mapGeoBoundingBoxFn = mapGeoBoundingBox(indexPatterns as IndexPatterns);
|
||||
});
|
||||
|
||||
test('should return the key and value for matching filters with bounds', async () => {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
},
|
||||
geo_bounding_box: {
|
||||
point: {
|
||||
// field name
|
||||
top_left: { lat: 5, lon: 10 },
|
||||
bottom_right: { lat: 15, lon: 20 },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await mapGeoBoundingBoxFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'point');
|
||||
expect(result).toHaveProperty('value');
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).toBe(
|
||||
'lat5lon10tolat15lon20'
|
||||
);
|
||||
});
|
||||
|
||||
test('should return the key and value even when using ignore_unmapped', async () => {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
},
|
||||
geo_bounding_box: {
|
||||
ignore_unmapped: true,
|
||||
point: {
|
||||
// field name
|
||||
top_left: { lat: 5, lon: 10 },
|
||||
bottom_right: { lat: 15, lon: 20 },
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = await mapGeoBoundingBoxFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'point');
|
||||
expect(result).toHaveProperty('value');
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).toBe(
|
||||
'lat5lon10tolat15lon20'
|
||||
);
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { query_string: { query: 'foo:bar' } },
|
||||
};
|
||||
|
||||
try {
|
||||
await mapGeoBoundingBoxFn(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { get } from 'lodash';
|
||||
import { GeoBoundingBoxFilter, Filter, FILTERS, isGeoBoundingBoxFilter } from '@kbn/es-query';
|
||||
import { IndexPatterns, IndexPattern } from '../../../index_patterns';
|
||||
import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public';
|
||||
|
||||
const getFormattedValue = (params: any, key: string, indexPattern?: IndexPattern) => {
|
||||
const formatter: any =
|
||||
indexPattern && key && get(indexPattern, ['fields', 'byName', key, 'format']);
|
||||
|
||||
return formatter
|
||||
? {
|
||||
topLeft: formatter.convert(params.top_left),
|
||||
bottomRight: formatter.convert(params.bottom_right),
|
||||
}
|
||||
: {
|
||||
topLeft: JSON.stringify(params.top_left),
|
||||
bottomRight: JSON.stringify(params.bottom_right),
|
||||
};
|
||||
};
|
||||
|
||||
const getParams = (filter: GeoBoundingBoxFilter, indexPattern?: IndexPattern) => {
|
||||
const key = Object.keys(filter.geo_bounding_box).filter(k => k !== 'ignore_unmapped')[0];
|
||||
const params = filter.geo_bounding_box[key];
|
||||
const { topLeft, bottomRight } = getFormattedValue(params, key, indexPattern);
|
||||
|
||||
return {
|
||||
key,
|
||||
params,
|
||||
type: FILTERS.GEO_BOUNDING_BOX,
|
||||
value: topLeft + ' to ' + bottomRight,
|
||||
};
|
||||
};
|
||||
|
||||
export const mapGeoBoundingBox = (indexPatterns: IndexPatterns) => {
|
||||
return async (filter: Filter) => {
|
||||
if (!isGeoBoundingBoxFilter(filter)) {
|
||||
throw filter;
|
||||
}
|
||||
|
||||
try {
|
||||
let indexPattern;
|
||||
|
||||
if (filter.meta.index) {
|
||||
indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
}
|
||||
|
||||
return getParams(filter, indexPattern);
|
||||
} catch (error) {
|
||||
if (error instanceof SavedObjectNotFound) {
|
||||
return getParams(filter);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { mapGeoPolygon } from './map_geo_polygon';
|
||||
import { StubIndexPatterns } from '../test_helpers/stub_index_pattern';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapGeoPolygon()', () => {
|
||||
let mapGeoPolygonFn: Function;
|
||||
|
||||
beforeEach(() => {
|
||||
const indexPatterns: unknown = new StubIndexPatterns();
|
||||
|
||||
mapGeoPolygonFn = mapGeoPolygon(indexPatterns as IndexPatterns);
|
||||
});
|
||||
|
||||
test('should return the key and value for matching filters with bounds', async () => {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
},
|
||||
geo_polygon: {
|
||||
point: {
|
||||
points: [{ lat: 5, lon: 10 }, { lat: 15, lon: 20 }],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await mapGeoPolygonFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'point');
|
||||
expect(result).toHaveProperty('value');
|
||||
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).toBe(
|
||||
'lat5lon10lat15lon20'
|
||||
);
|
||||
});
|
||||
|
||||
test('should return the key and value even when using ignore_unmapped', async () => {
|
||||
const filter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
},
|
||||
geo_polygon: {
|
||||
ignore_unmapped: true,
|
||||
point: {
|
||||
points: [{ lat: 5, lon: 10 }, { lat: 15, lon: 20 }],
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = await mapGeoPolygonFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'point');
|
||||
expect(result).toHaveProperty('value');
|
||||
|
||||
// remove html entities and non-alphanumerics to get the gist of the value
|
||||
expect(result.value.replace(/&[a-z]+?;/g, '').replace(/[^a-z0-9]/g, '')).toBe(
|
||||
'lat5lon10lat15lon20'
|
||||
);
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { query_string: { query: 'foo:bar' } },
|
||||
};
|
||||
|
||||
try {
|
||||
await mapGeoPolygonFn(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,37 +16,47 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { get } from 'lodash';
|
||||
import { GeoPolygonFilter, Filter, FILTERS, isGeoPolygonFilter } from '@kbn/es-query';
|
||||
import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public';
|
||||
import { IndexPatterns, IndexPattern } from '../../../index_patterns';
|
||||
|
||||
function getParams(filter, indexPattern) {
|
||||
const type = 'geo_polygon';
|
||||
const key = _.keys(filter.geo_polygon)
|
||||
.filter(key => key !== 'ignore_unmapped')[0];
|
||||
const POINTS_SEPARATOR = ', ';
|
||||
|
||||
const getFormattedValue = (value: any, key: string, indexPattern?: IndexPattern) => {
|
||||
const formatter: any =
|
||||
indexPattern && key && get(indexPattern, ['fields', 'byName', key, 'format']);
|
||||
|
||||
return formatter ? formatter.convert(value) : JSON.stringify(value);
|
||||
};
|
||||
|
||||
function getParams(filter: GeoPolygonFilter, indexPattern?: IndexPattern) {
|
||||
const key = Object.keys(filter.geo_polygon).filter(k => k !== 'ignore_unmapped')[0];
|
||||
const params = filter.geo_polygon[key];
|
||||
|
||||
// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
|
||||
// for example a user might manually edit the url or the index pattern's ID might change due to
|
||||
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
|
||||
// on displaying the raw value if the index is invalid.
|
||||
const points = params.points.map((point) => {
|
||||
return indexPattern
|
||||
? indexPattern.fields.byName[key].format.convert(point)
|
||||
: JSON.stringify(point);
|
||||
});
|
||||
const value = points.join(', ');
|
||||
return { type, key, value, params };
|
||||
return {
|
||||
key,
|
||||
params,
|
||||
type: FILTERS.GEO_POLYGON,
|
||||
value: (params.points || [])
|
||||
.map((point: string) => getFormattedValue(point, key, indexPattern))
|
||||
.join(POINTS_SEPARATOR),
|
||||
};
|
||||
}
|
||||
|
||||
export function mapGeoPolygon(indexPatterns) {
|
||||
return async function (filter) {
|
||||
if (!filter.geo_polygon) {
|
||||
export function mapGeoPolygon(indexPatterns: IndexPatterns) {
|
||||
return async function(filter: Filter) {
|
||||
if (!isGeoPolygonFilter(filter)) {
|
||||
throw filter;
|
||||
}
|
||||
|
||||
try {
|
||||
const indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
let indexPattern;
|
||||
|
||||
if (filter.meta.index) {
|
||||
indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
}
|
||||
|
||||
return getParams(filter, indexPattern);
|
||||
} catch (error) {
|
||||
if (error instanceof SavedObjectNotFound) {
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { MatchAllFilter } from '@kbn/es-query';
|
||||
import { mapMatchAll } from './map_match_all';
|
||||
|
||||
describe('filter_manager/lib', () => {
|
||||
describe('mapMatchAll()', () => {
|
||||
let filter: MatchAllFilter;
|
||||
|
||||
beforeEach(() => {
|
||||
filter = {
|
||||
match_all: {},
|
||||
meta: {
|
||||
alias: null,
|
||||
negate: true,
|
||||
disabled: false,
|
||||
field: 'foo',
|
||||
formattedValue: 'bar',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('when given a filter that is not match_all', () => {
|
||||
test('filter is rejected', async done => {
|
||||
delete filter.match_all;
|
||||
|
||||
try {
|
||||
await mapMatchAll(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a match_all filter', () => {
|
||||
test('key is set to meta field', async () => {
|
||||
const result = await mapMatchAll(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', filter.meta.field);
|
||||
});
|
||||
|
||||
test('value is set to meta formattedValue', async () => {
|
||||
const result = await mapMatchAll(filter);
|
||||
|
||||
expect(result).toHaveProperty('value', filter.meta.formattedValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,13 +16,15 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Filter, FILTERS, isMatchAllFilter } from '@kbn/es-query';
|
||||
|
||||
export async function mapMatchAll(filter) {
|
||||
if (filter.match_all) {
|
||||
const type = 'match_all';
|
||||
const key = filter.meta.field;
|
||||
const value = filter.meta.formattedValue || 'all';
|
||||
return { type, key, value };
|
||||
export const mapMatchAll = async (filter: Filter) => {
|
||||
if (isMatchAllFilter(filter)) {
|
||||
return {
|
||||
type: FILTERS.MATCH_ALL,
|
||||
key: filter.meta.field,
|
||||
value: filter.meta.formattedValue || 'all',
|
||||
};
|
||||
}
|
||||
throw filter;
|
||||
}
|
||||
};
|
|
@ -16,32 +16,31 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { MissingFilter, buildEmptyFilter, ExistsFilter } from '@kbn/es-query';
|
||||
import { mapMissing } from './map_missing';
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { mapExists } from '../map_exists';
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapMissing()', () => {
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
const filter: MissingFilter = {
|
||||
missing: { field: '_type' },
|
||||
...buildEmptyFilter(true),
|
||||
};
|
||||
const result = await mapMissing(filter);
|
||||
|
||||
describe('Filter Bar Directive', function () {
|
||||
describe('mapExists()', function () {
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
it('should return the key and value for matching filters', function (done) {
|
||||
const filter = { exists: { field: '_type' } };
|
||||
mapExists(filter).then(function (result) {
|
||||
expect(result).to.have.property('key', '_type');
|
||||
expect(result).to.have.property('value', 'exists');
|
||||
done();
|
||||
});
|
||||
expect(result).toHaveProperty('key', '_type');
|
||||
expect(result).toHaveProperty('value', 'missing');
|
||||
});
|
||||
|
||||
it('should return undefined for none matching', function (done) {
|
||||
const filter = { query: { match: { query: 'foo' } } };
|
||||
mapExists(filter).catch(function (result) {
|
||||
expect(result).to.be(filter);
|
||||
done();
|
||||
});
|
||||
});
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = buildEmptyFilter(true) as ExistsFilter;
|
||||
|
||||
try {
|
||||
await mapMissing(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,13 +16,16 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Filter, FILTERS, isMissingFilter } from '@kbn/es-query';
|
||||
|
||||
export async function mapMissing(filter) {
|
||||
if (filter.missing) {
|
||||
const type = 'missing';
|
||||
const key = filter.missing.field;
|
||||
const value = type;
|
||||
return { type, key, value };
|
||||
export const mapMissing = async (filter: Filter) => {
|
||||
if (isMissingFilter(filter)) {
|
||||
return {
|
||||
type: FILTERS.MISSING,
|
||||
value: FILTERS.MISSING,
|
||||
key: filter.missing.field,
|
||||
};
|
||||
}
|
||||
|
||||
throw filter;
|
||||
}
|
||||
};
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 _ from 'lodash';
|
||||
import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public';
|
||||
|
||||
function isScriptedPhrase(filter) {
|
||||
const value = _.get(filter, ['script', 'script', 'params', 'value']);
|
||||
return typeof value !== 'undefined';
|
||||
}
|
||||
|
||||
function getParams(filter, indexPattern) {
|
||||
const isScriptedPhraseFilter = isScriptedPhrase(filter);
|
||||
const type = 'phrase';
|
||||
const key = isScriptedPhraseFilter ? filter.meta.field : Object.keys(filter.query.match)[0];
|
||||
const query = isScriptedPhraseFilter ? filter.script.script.params.value : filter.query.match[key].query;
|
||||
const params = { query };
|
||||
|
||||
// Sometimes a filter will end up with an invalid index or field param. This could happen for a lot of reasons,
|
||||
// for example a user might manually edit the url or the index pattern's ID might change due to
|
||||
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
|
||||
// on displaying the raw value if the index or field is invalid.
|
||||
const value = (
|
||||
indexPattern &&
|
||||
indexPattern.fields &&
|
||||
indexPattern.fields.byName[key]
|
||||
) ? indexPattern.fields.byName[key].format.convert(query) : query;
|
||||
return { type, key, value, params };
|
||||
}
|
||||
|
||||
export function mapPhrase(indexPatterns) {
|
||||
return async function (filter) {
|
||||
const isScriptedPhraseFilter = isScriptedPhrase(filter);
|
||||
if (!_.has(filter, ['query', 'match']) && !isScriptedPhraseFilter) {
|
||||
throw filter;
|
||||
}
|
||||
|
||||
try {
|
||||
const indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
return getParams(filter, indexPattern);
|
||||
} catch (error) {
|
||||
if (error instanceof SavedObjectNotFound) {
|
||||
return getParams(filter);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { mapPhrase } from './map_phrase';
|
||||
import { StubIndexPatterns } from '../test_helpers/stub_index_pattern';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapPhrase()', () => {
|
||||
let mapPhraseFn: Function;
|
||||
|
||||
beforeEach(() => {
|
||||
const indexPatterns: unknown = new StubIndexPatterns();
|
||||
|
||||
mapPhraseFn = mapPhrase(indexPatterns as IndexPatterns);
|
||||
});
|
||||
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { match: { _type: { query: 'apache', type: 'phrase' } } },
|
||||
};
|
||||
const result = await mapPhraseFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', '_type');
|
||||
expect(result).toHaveProperty('value', 'apache');
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { query_string: { query: 'foo:bar' } },
|
||||
};
|
||||
|
||||
try {
|
||||
await mapPhraseFn(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { get } from 'lodash';
|
||||
import {
|
||||
PhraseFilter,
|
||||
Filter,
|
||||
FILTERS,
|
||||
isPhraseFilter,
|
||||
isScriptedPhraseFilter,
|
||||
} from '@kbn/es-query';
|
||||
import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public';
|
||||
import { IndexPatterns, IndexPattern } from '../../../index_patterns';
|
||||
|
||||
const getScriptedPhraseValue = (filter: PhraseFilter) =>
|
||||
get(filter, ['script', 'script', 'params', 'value']);
|
||||
|
||||
const getFormattedValue = (value: any, key: string, indexPattern?: IndexPattern) => {
|
||||
const formatter: any =
|
||||
indexPattern && key && get(indexPattern, ['fields', 'byName', key, 'format']);
|
||||
|
||||
return formatter ? formatter.convert(value) : value;
|
||||
};
|
||||
|
||||
const getParams = (filter: PhraseFilter, indexPattern?: IndexPattern) => {
|
||||
const scriptedPhraseValue = getScriptedPhraseValue(filter);
|
||||
const isScriptedFilter = Boolean(scriptedPhraseValue);
|
||||
const key = isScriptedFilter ? filter.meta.field || '' : Object.keys(filter.query.match)[0];
|
||||
const query = scriptedPhraseValue || get(filter, ['query', 'match', key, 'query']);
|
||||
const params = { query };
|
||||
|
||||
return {
|
||||
key,
|
||||
params,
|
||||
type: FILTERS.PHRASE,
|
||||
value: getFormattedValue(query, key, indexPattern),
|
||||
};
|
||||
};
|
||||
|
||||
export const isMapPhraseFilter = (filter: any): filter is PhraseFilter =>
|
||||
isPhraseFilter(filter) || isScriptedPhraseFilter(filter);
|
||||
|
||||
export const mapPhrase = (indexPatterns: IndexPatterns) => {
|
||||
return async (filter: Filter) => {
|
||||
if (!isMapPhraseFilter(filter)) {
|
||||
throw filter;
|
||||
}
|
||||
|
||||
try {
|
||||
let indexPattern;
|
||||
|
||||
if (filter.meta.index) {
|
||||
indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
}
|
||||
|
||||
return getParams(filter, indexPattern);
|
||||
} catch (error) {
|
||||
if (error instanceof SavedObjectNotFound) {
|
||||
return getParams(filter);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -17,11 +17,14 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export async function mapPhrases(filter) {
|
||||
const { type, key, value, params } = filter.meta;
|
||||
if (type !== 'phrases') {
|
||||
import { Filter, isPhrasesFilter } from '@kbn/es-query';
|
||||
|
||||
export const mapPhrases = async (filter: Filter) => {
|
||||
if (!isPhrasesFilter(filter)) {
|
||||
throw filter;
|
||||
} else {
|
||||
return { type, key, value, params };
|
||||
}
|
||||
}
|
||||
|
||||
const { type, key, value, params } = filter.meta;
|
||||
|
||||
return { type, key, value, params };
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { QueryStringFilter, buildQueryFilter, buildEmptyFilter } from '@kbn/es-query';
|
||||
import { mapQueryString } from './map_query_string';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapQueryString()', () => {
|
||||
test('should return the key and value for matching filters', async () => {
|
||||
const filter: QueryStringFilter = buildQueryFilter(
|
||||
{ query_string: { query: 'foo:bar' } },
|
||||
'index'
|
||||
);
|
||||
const result = await mapQueryString(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'query');
|
||||
expect(result).toHaveProperty('value', 'foo:bar');
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = buildEmptyFilter(true) as QueryStringFilter;
|
||||
|
||||
try {
|
||||
await mapQueryString(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,13 +16,16 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Filter, FILTERS, isQueryStringFilter } from '@kbn/es-query';
|
||||
|
||||
export async function mapExists(filter) {
|
||||
if (filter.exists) {
|
||||
const type = 'exists';
|
||||
const key = filter.exists.field;
|
||||
const value = type;
|
||||
return { type, key, value };
|
||||
export const mapQueryString = async (filter: Filter) => {
|
||||
if (isQueryStringFilter(filter)) {
|
||||
return {
|
||||
type: FILTERS.QUERY_STRING,
|
||||
key: 'query',
|
||||
value: filter.query.query_string.query,
|
||||
};
|
||||
}
|
||||
|
||||
throw filter;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { mapRange } from './map_range';
|
||||
import { StubIndexPatterns } from '../test_helpers/stub_index_pattern';
|
||||
import { IndexPatterns } from '../../../index_patterns';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('mapRange()', () => {
|
||||
let mapRangeFn: Function;
|
||||
|
||||
beforeEach(() => {
|
||||
const indexPatterns: unknown = new StubIndexPatterns();
|
||||
|
||||
mapRangeFn = mapRange(indexPatterns as IndexPatterns);
|
||||
});
|
||||
|
||||
test('should return the key and value for matching filters with gt/lt', async () => {
|
||||
const filter = { meta: { index: 'logstash-*' }, range: { bytes: { lt: 2048, gt: 1024 } } };
|
||||
const result = await mapRangeFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'bytes');
|
||||
expect(result).toHaveProperty('value', '1024 to 2048');
|
||||
});
|
||||
|
||||
test('should return the key and value for matching filters with gte/lte', async () => {
|
||||
const filter = { meta: { index: 'logstash-*' }, range: { bytes: { lte: 2048, gte: 1024 } } };
|
||||
const result = await mapRangeFn(filter);
|
||||
|
||||
expect(result).toHaveProperty('key', 'bytes');
|
||||
expect(result).toHaveProperty('value', '1024 to 2048');
|
||||
});
|
||||
|
||||
test('should return undefined for none matching', async done => {
|
||||
const filter = {
|
||||
meta: { index: 'logstash-*' },
|
||||
query: { query_string: { query: 'foo:bar' } },
|
||||
};
|
||||
|
||||
try {
|
||||
await mapRangeFn(filter);
|
||||
} catch (e) {
|
||||
expect(e).toBe(filter);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,20 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { has, get } from 'lodash';
|
||||
import { Filter, RangeFilter, FILTERS, isRangeFilter, isScriptedRangeFilter } from '@kbn/es-query';
|
||||
import { get, has } from 'lodash';
|
||||
import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public';
|
||||
import { IndexPatterns, IndexPattern } from '../../../index_patterns';
|
||||
|
||||
const getFirstRangeKey = (filter: RangeFilter) => filter.range && Object.keys(filter.range)[0];
|
||||
const getRangeByKey = (filter: RangeFilter, key: string) => get(filter, ['range', key]);
|
||||
|
||||
function isScriptedRange(filter) {
|
||||
const params = get(filter, ['script', 'script', 'params']);
|
||||
return params && Object.keys(params).find(key => ['gte', 'gt', 'lte', 'lt'].includes(key));
|
||||
}
|
||||
|
||||
function getParams(filter, indexPattern) {
|
||||
const isScriptedRangeFilter = isScriptedRange(filter);
|
||||
const type = 'range';
|
||||
const key = isScriptedRangeFilter ? filter.meta.field : Object.keys(filter.range)[0];
|
||||
const params = isScriptedRangeFilter ? filter.script.script.params : filter.range[key];
|
||||
function getParams(filter: RangeFilter, indexPattern?: IndexPattern) {
|
||||
const isScriptedRange = isScriptedRangeFilter(filter);
|
||||
const key: string = (isScriptedRange ? filter.meta.field : getFirstRangeKey(filter)) || '';
|
||||
const params: any = isScriptedRange
|
||||
? get(filter, 'script.script.params')
|
||||
: getRangeByKey(filter, key);
|
||||
|
||||
let left = has(params, 'gte') ? params.gte : params.gt;
|
||||
if (left == null) left = -Infinity;
|
||||
|
@ -38,28 +38,37 @@ function getParams(filter, indexPattern) {
|
|||
let right = has(params, 'lte') ? params.lte : params.lt;
|
||||
if (right == null) right = Infinity;
|
||||
|
||||
let value = `${left} to ${right}`;
|
||||
|
||||
// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
|
||||
// for example a user might manually edit the url or the index pattern's ID might change due to
|
||||
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
|
||||
// on displaying the raw value if the index is invalid.
|
||||
let value = `${left} to ${right}`;
|
||||
if (indexPattern && indexPattern.fields.byName[key]) {
|
||||
if (key && indexPattern && indexPattern.fields.byName[key]) {
|
||||
const convert = indexPattern.fields.byName[key].format.getConverterFor('text');
|
||||
|
||||
value = `${convert(left)} to ${convert(right)}`;
|
||||
}
|
||||
|
||||
return { type, key, value, params };
|
||||
return { type: FILTERS.RANGE, key, value, params };
|
||||
}
|
||||
|
||||
export function mapRange(indexPatterns) {
|
||||
return async function (filter) {
|
||||
const isScriptedRangeFilter = isScriptedRange(filter);
|
||||
if (!filter.range && !isScriptedRangeFilter) {
|
||||
export const isMapRangeFilter = (filter: any): filter is RangeFilter =>
|
||||
isRangeFilter(filter) || isScriptedRangeFilter(filter);
|
||||
|
||||
export const mapRange = (indexPatterns: IndexPatterns) => {
|
||||
return async (filter: Filter) => {
|
||||
if (!isMapRangeFilter(filter)) {
|
||||
throw filter;
|
||||
}
|
||||
|
||||
try {
|
||||
const indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
let indexPattern;
|
||||
|
||||
if (filter.meta.index) {
|
||||
indexPattern = await indexPatterns.get(filter.meta.index);
|
||||
}
|
||||
|
||||
return getParams(filter, indexPattern);
|
||||
} catch (error) {
|
||||
if (error instanceof SavedObjectNotFound) {
|
||||
|
@ -68,4 +77,4 @@ export function mapRange(indexPatterns) {
|
|||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
|
@ -18,83 +18,89 @@
|
|||
*/
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
|
||||
import { onlyDisabledFiltersChanged } from './only_disabled';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
describe('Filter Bar Directive', function() {
|
||||
describe('onlyDisabledFiltersChanged()', function() {
|
||||
it('should return true if all filters are disabled', function() {
|
||||
describe('filter manager utilities', () => {
|
||||
describe('onlyDisabledFiltersChanged()', () => {
|
||||
test('should return true if all filters are disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
] as Filter[];
|
||||
const newFilters = [{ meta: { disabled: true } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(true);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if there are no old filters', function() {
|
||||
test('should return false if there are no old filters', () => {
|
||||
const newFilters = [{ meta: { disabled: false } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, undefined)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if there are no new filters', function() {
|
||||
test('should return false if there are no new filters', () => {
|
||||
const filters = [{ meta: { disabled: false } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(undefined, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(undefined, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if all filters are not disabled', function() {
|
||||
test('should return false if all filters are not disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
] as Filter[];
|
||||
const newFilters = [{ meta: { disabled: false } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if only old filters are disabled', function() {
|
||||
test('should return false if only old filters are disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
] as Filter[];
|
||||
const newFilters = [{ meta: { disabled: false } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if new filters are not disabled', function() {
|
||||
test('should return false if new filters are not disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
] as Filter[];
|
||||
const newFilters = [{ meta: { disabled: true } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when all removed filters were disabled', function() {
|
||||
test('should return true when all removed filters were disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: true } },
|
||||
] as Filter[];
|
||||
const newFilters = [] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(true);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when all removed filters were not disabled', function() {
|
||||
test('should return false when all removed filters were not disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
] as Filter[];
|
||||
const newFilters = [] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if all changed filters are disabled', function() {
|
||||
test('should return true if all changed filters are disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: true, negate: false } },
|
||||
{ meta: { disabled: true, negate: false } },
|
||||
|
@ -103,35 +109,39 @@ describe('Filter Bar Directive', function() {
|
|||
{ meta: { disabled: true, negate: true } },
|
||||
{ meta: { disabled: true, negate: true } },
|
||||
] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(true);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if all filters remove were not disabled', function() {
|
||||
test('should return false if all filters remove were not disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: true } },
|
||||
] as Filter[];
|
||||
const newFilters = [{ meta: { disabled: false } }] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when all removed filters are not disabled', function() {
|
||||
test('should return false when all removed filters are not disabled', () => {
|
||||
const filters = [
|
||||
{ meta: { disabled: true } },
|
||||
{ meta: { disabled: false } },
|
||||
{ meta: { disabled: true } },
|
||||
] as Filter[];
|
||||
const newFilters = [] as Filter[];
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).to.be(false);
|
||||
|
||||
expect(onlyDisabledFiltersChanged(newFilters, filters)).toBe(false);
|
||||
});
|
||||
|
||||
it('should not throw with null filters', function() {
|
||||
test('should not throw with null filters', () => {
|
||||
const filters = [null, { meta: { disabled: true } }] as Filter[];
|
||||
const newFilters = [] as Filter[];
|
||||
expect(function() {
|
||||
|
||||
expect(() => {
|
||||
onlyDisabledFiltersChanged(newFilters, filters);
|
||||
}).to.not.throwError();
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,20 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { filter, isEqual } from 'lodash';
|
||||
|
||||
const isEnabled = (f: Filter) => f && f.meta && !f.meta.disabled;
|
||||
|
||||
const isEnabled = function(filter: Filter) {
|
||||
return filter && filter.meta && !filter.meta.disabled;
|
||||
};
|
||||
/**
|
||||
* Checks to see if only disabled filters have been changed
|
||||
*
|
||||
* @returns {bool} Only disabled filters
|
||||
*/
|
||||
export function onlyDisabledFiltersChanged(newFilters?: Filter[], oldFilters?: Filter[]) {
|
||||
export const onlyDisabledFiltersChanged = (newFilters?: Filter[], oldFilters?: Filter[]) => {
|
||||
// If it's the same - compare only enabled filters
|
||||
const newEnabledFilters = _.filter(newFilters || [], isEnabled);
|
||||
const oldEnabledFilters = _.filter(oldFilters || [], isEnabled);
|
||||
const newEnabledFilters = filter(newFilters || [], isEnabled);
|
||||
const oldEnabledFilters = filter(oldFilters || [], isEnabled);
|
||||
|
||||
return _.isEqual(oldEnabledFilters, newEnabledFilters);
|
||||
}
|
||||
return isEqual(oldEnabledFilters, newEnabledFilters);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you 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 { Filter, buildQueryFilter, FilterStateStore } from '@kbn/es-query';
|
||||
import { uniqFilters } from './uniq_filters';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('niqFilter', () => {
|
||||
test('should filter out dups', () => {
|
||||
const before: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
];
|
||||
const results = uniqFilters(before);
|
||||
|
||||
expect(results).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should filter out duplicates, ignoring meta attributes', () => {
|
||||
const before: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index1'),
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index2'),
|
||||
];
|
||||
const results = uniqFilters(before);
|
||||
|
||||
expect(results).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should filter out duplicates, ignoring $state attributes', () => {
|
||||
const before: Filter[] = [
|
||||
{
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
},
|
||||
{
|
||||
$state: { store: FilterStateStore.GLOBAL_STATE },
|
||||
...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index'),
|
||||
},
|
||||
];
|
||||
const results = uniqFilters(before);
|
||||
|
||||
expect(results).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,19 +16,24 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { each, union } from 'lodash';
|
||||
import { dedupFilters } from './dedup_filters';
|
||||
|
||||
/**
|
||||
* Remove duplicate filters from an array of filters
|
||||
*
|
||||
* @param {array} filters The filters to remove duplicates from
|
||||
* @param {object} comparatorOptions - Parameters to use for comparison
|
||||
|
||||
* @returns {object} The original filters array with duplicates removed
|
||||
*/
|
||||
export function uniqFilters(filters, comparatorOptions) {
|
||||
let results = [];
|
||||
_.each(filters, function (filter) {
|
||||
results = _.union(results, dedupFilters(results, [filter], comparatorOptions));
|
||||
export const uniqFilters = (filters: Filter[], comparatorOptions: any = {}) => {
|
||||
let results: Filter[] = [];
|
||||
|
||||
each(filters, (filter: Filter) => {
|
||||
results = union(results, dedupFilters(results, [filter]), comparatorOptions);
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue