Moved filter generator ⇒ NP (#50118)
* Moved filter generator to NP * Deleted unused test * Fixed browser test + fix to discover actions * Added jsdcos
This commit is contained in:
parent
4f888196b7
commit
6219cfdc16
|
@ -26,9 +26,6 @@ import { IInjector } from 'ui/chrome';
|
|||
// @ts-ignore
|
||||
import * as filterActions from 'plugins/kibana/discover/doc_table/actions/filter';
|
||||
|
||||
// @ts-ignore
|
||||
import { getFilterGenerator } from 'ui/filter_manager';
|
||||
|
||||
import {
|
||||
AppStateClass as TAppStateClass,
|
||||
AppState as TAppState,
|
||||
|
|
|
@ -26,7 +26,8 @@ export function createIndexPatternsStub() {
|
|||
get: sinon.spy(indexPatternId =>
|
||||
Promise.resolve({
|
||||
id: indexPatternId,
|
||||
isTimeNanosBased: () => false
|
||||
isTimeNanosBased: () => false,
|
||||
popularizeField: () => {},
|
||||
})
|
||||
),
|
||||
};
|
||||
|
|
|
@ -19,32 +19,33 @@
|
|||
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import sinon from 'sinon';
|
||||
import { getServices } from '../../../../kibana_services';
|
||||
import { createStateStub } from './_utils';
|
||||
import { QueryParameterActionsProvider } from '../actions';
|
||||
|
||||
import { createIndexPatternsStub } from '../../api/__tests__/_stubs';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
describe('context app', function () {
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
|
||||
beforeEach(ngMock.module(function createServiceStubs($provide) {
|
||||
$provide.value('indexPatterns', createIndexPatternsStub());
|
||||
}));
|
||||
|
||||
describe('action addFilter', function () {
|
||||
let filterManagerStub;
|
||||
let addFilter;
|
||||
|
||||
beforeEach(ngMock.inject(function createPrivateStubs(Private) {
|
||||
filterManagerStub = createQueryFilterStub();
|
||||
Private.stub(getServices().FilterBarQueryFilterProvider, filterManagerStub);
|
||||
|
||||
Private.stub(getServices().FilterBarQueryFilterProvider);
|
||||
addFilter = Private(QueryParameterActionsProvider).addFilter;
|
||||
}));
|
||||
|
||||
it('should pass the given arguments to the filterManager', function () {
|
||||
const state = createStateStub();
|
||||
const filterManagerAddStub = npStart.plugins.data.query.filterManager.addFilters;
|
||||
|
||||
addFilter(state)('FIELD_NAME', 'FIELD_VALUE', 'FILTER_OPERATION');
|
||||
|
||||
const filterManagerAddStub = filterManagerStub.addFilters;
|
||||
//get the generated filter
|
||||
const generatedFilter = filterManagerAddStub.firstCall.args[0][0];
|
||||
const queryKeys = Object.keys(generatedFilter.query.match_phrase);
|
||||
|
@ -55,20 +56,12 @@ describe('context app', function () {
|
|||
|
||||
it('should pass the index pattern id to the filterManager', function () {
|
||||
const state = createStateStub();
|
||||
const filterManagerAddStub = npStart.plugins.data.query.filterManager.addFilters;
|
||||
|
||||
addFilter(state)('FIELD_NAME', 'FIELD_VALUE', 'FILTER_OPERATION');
|
||||
|
||||
const filterManagerAddStub = filterManagerStub.addFilters;
|
||||
const generatedFilter = filterManagerAddStub.firstCall.args[0][0];
|
||||
expect(filterManagerAddStub.calledOnce).to.be(true);
|
||||
expect(generatedFilter.meta.index).to.eql('INDEX_PATTERN_ID');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createQueryFilterStub() {
|
||||
return {
|
||||
addFilters: sinon.stub(),
|
||||
getAppFilters: sinon.stub(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getServices, getFilterGenerator } from '../../../kibana_services';
|
||||
import { generateFilters } from '../../../../../../../../plugins/data/public';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
import {
|
||||
MAX_CONTEXT_SIZE,
|
||||
|
@ -27,9 +28,8 @@ import {
|
|||
} from './constants';
|
||||
|
||||
|
||||
export function QueryParameterActionsProvider(indexPatterns, Private) {
|
||||
const queryFilter = Private(getServices().FilterBarQueryFilterProvider);
|
||||
const filterGen = getFilterGenerator(queryFilter);
|
||||
export function QueryParameterActionsProvider(indexPatterns) {
|
||||
const { filterManager } = npStart.plugins.data.query;
|
||||
|
||||
const setPredecessorCount = (state) => (predecessorCount) => (
|
||||
state.queryParameters.predecessorCount = clamp(
|
||||
|
@ -55,13 +55,13 @@ export function QueryParameterActionsProvider(indexPatterns, Private) {
|
|||
);
|
||||
|
||||
const updateFilters = () => filters => {
|
||||
queryFilter.setFilters(filters);
|
||||
filterManager.setFilters(filters);
|
||||
};
|
||||
|
||||
const addFilter = (state) => async (field, values, operation) => {
|
||||
const indexPatternId = state.queryParameters.indexPatternId;
|
||||
const newFilters = filterGen.generate(field, values, operation, indexPatternId);
|
||||
queryFilter.addFilters(newFilters);
|
||||
const newFilters = generateFilters(filterManager, field, values, operation, indexPatternId);
|
||||
filterManager.addFilters(newFilters);
|
||||
const indexPattern = await indexPatterns.get(indexPatternId);
|
||||
indexPattern.popularizeField(field.name, 1);
|
||||
};
|
||||
|
|
|
@ -31,7 +31,6 @@ import './doc_table';
|
|||
import { getSort } from './doc_table/lib/get_sort';
|
||||
import { getSortForSearchSource } from './doc_table/lib/get_sort_for_search_source';
|
||||
import * as columnActions from './doc_table/actions/columns';
|
||||
import * as filterActions from './doc_table/actions/filter';
|
||||
|
||||
import indexTemplate from './discover.html';
|
||||
import { showOpenSearchPanel } from '../top_nav/show_open_search_panel';
|
||||
|
@ -41,7 +40,6 @@ import { getPainlessError } from './get_painless_error';
|
|||
import {
|
||||
angular,
|
||||
buildVislibDimensions,
|
||||
getFilterGenerator,
|
||||
getRequestInspectorStats,
|
||||
getResponseInspectorStats,
|
||||
getServices,
|
||||
|
@ -76,7 +74,7 @@ const {
|
|||
import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../breadcrumbs';
|
||||
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
|
||||
import { start as data } from '../../../../data/public/legacy';
|
||||
|
||||
import { generateFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
const { savedQueryService } = data.search.services;
|
||||
|
||||
|
@ -195,7 +193,6 @@ function discoverController(
|
|||
const shareContextMenuExtensions = Private(ShareContextMenuExtensionsRegistryProvider);
|
||||
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const filterGen = getFilterGenerator(queryFilter);
|
||||
|
||||
const inspectorAdapters = {
|
||||
requests: new RequestAdapter()
|
||||
|
@ -900,7 +897,8 @@ function discoverController(
|
|||
// TODO: On array fields, negating does not negate the combination, rather all terms
|
||||
$scope.filterQuery = function (field, values, operation) {
|
||||
$scope.indexPattern.popularizeField(field, 1);
|
||||
filterActions.addFilter(field, values, operation, $scope.indexPattern.id, $scope.state, filterGen);
|
||||
const newFilters = generateFilters(queryFilter, field, values, operation, $scope.indexPattern.id);
|
||||
return queryFilter.addFilters(newFilters);
|
||||
};
|
||||
|
||||
$scope.addColumn = function addColumn(columnName) {
|
||||
|
|
|
@ -1,66 +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 { addFilter } from '../../actions/filter';
|
||||
import StubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
import NoDigestPromises from 'test_utils/no_digest_promises';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import sinon from 'sinon';
|
||||
|
||||
function getFilterGeneratorStub() {
|
||||
return {
|
||||
add: sinon.stub()
|
||||
};
|
||||
}
|
||||
|
||||
describe('doc table filter actions', function () {
|
||||
NoDigestPromises.activateForSuite();
|
||||
|
||||
let filterGen;
|
||||
let indexPattern;
|
||||
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
function ($provide) {
|
||||
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
|
||||
}
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
indexPattern = Private(StubbedLogstashIndexPatternProvider);
|
||||
filterGen = getFilterGeneratorStub();
|
||||
}));
|
||||
|
||||
describe('add', function () {
|
||||
|
||||
it('should defer to the FilterManager when dealing with a lucene query', function () {
|
||||
const state = {
|
||||
query: { query: 'foo', language: 'lucene' }
|
||||
};
|
||||
const args = ['foo', ['bar'], '+', indexPattern, ];
|
||||
addFilter('foo', ['bar'], '+', indexPattern, state, filterGen);
|
||||
expect(filterGen.add.calledOnce).to.be(true);
|
||||
expect(filterGen.add.calledWith(...args)).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
|
@ -1,26 +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.
|
||||
*/
|
||||
|
||||
export function addFilter(field, values = [], operation, index, state, filterGen) {
|
||||
if (!Array.isArray(values)) {
|
||||
values = [values];
|
||||
}
|
||||
|
||||
filterGen.add(field, values, operation, index);
|
||||
}
|
|
@ -25,7 +25,9 @@ import { npStart } from 'ui/new_platform';
|
|||
import {
|
||||
esFilters,
|
||||
TimeRange,
|
||||
FilterManager,
|
||||
onlyDisabledFiltersChanged,
|
||||
generateFilters,
|
||||
getTime,
|
||||
Query,
|
||||
} from '../../../../../../plugins/data/public';
|
||||
|
@ -43,7 +45,6 @@ import { getSortForSearchSource } from '../angular/doc_table/lib/get_sort_for_se
|
|||
import {
|
||||
Adapters,
|
||||
angular,
|
||||
getFilterGenerator,
|
||||
getRequestInspectorStats,
|
||||
getResponseInspectorStats,
|
||||
getServices,
|
||||
|
@ -72,18 +73,6 @@ interface SearchScope extends ng.IScope {
|
|||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export interface FilterManager {
|
||||
generate: (
|
||||
field: {
|
||||
name: string;
|
||||
scripted: boolean;
|
||||
},
|
||||
values: string | string[],
|
||||
operation: string,
|
||||
index: number
|
||||
) => esFilters.Filter[];
|
||||
}
|
||||
|
||||
interface SearchEmbeddableConfig {
|
||||
$rootScope: ng.IRootScopeService;
|
||||
$compile: ng.ICompileService;
|
||||
|
@ -107,7 +96,7 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
private autoRefreshFetchSubscription?: Subscription;
|
||||
private subscription?: Subscription;
|
||||
public readonly type = SEARCH_EMBEDDABLE_TYPE;
|
||||
private filterGen: FilterManager;
|
||||
private filterManager: FilterManager;
|
||||
private abortController?: AbortController;
|
||||
|
||||
private prevTimeRange?: TimeRange;
|
||||
|
@ -134,7 +123,7 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
parent
|
||||
);
|
||||
|
||||
this.filterGen = getFilterGenerator(queryFilter);
|
||||
this.filterManager = queryFilter as FilterManager;
|
||||
this.savedSearch = savedSearch;
|
||||
this.$rootScope = $rootScope;
|
||||
this.$compile = $compile;
|
||||
|
@ -251,7 +240,7 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
};
|
||||
|
||||
searchScope.filter = async (field, value, operator) => {
|
||||
let filters = this.filterGen.generate(field, value, operator, indexPattern.id);
|
||||
let filters = generateFilters(this.filterManager, field, value, operator, indexPattern.id);
|
||||
filters = filters.map(filter => ({
|
||||
...filter,
|
||||
$state: { store: esFilters.FilterStateStore.APP_STATE },
|
||||
|
|
|
@ -84,8 +84,6 @@ export { angular };
|
|||
export { buildVislibDimensions } from 'ui/visualize/loader/pipeline_helpers/build_pipeline';
|
||||
// @ts-ignore
|
||||
export { callAfterBindingsWorkaround } from 'ui/compat';
|
||||
// @ts-ignore
|
||||
export { getFilterGenerator } from 'ui/filter_manager';
|
||||
export {
|
||||
getRequestInspectorStats,
|
||||
getResponseInspectorStats,
|
||||
|
|
|
@ -1,166 +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 sinon from 'sinon';
|
||||
import MockState from 'fixtures/mock_state';
|
||||
import expect from '@kbn/expect';
|
||||
import ngMock from 'ng_mock';
|
||||
import { getFilterGenerator } from '..';
|
||||
import { FilterBarQueryFilterProvider } from '../../filter_manager/query_filter';
|
||||
import { uniqFilters, esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
let queryFilter;
|
||||
let filterGen;
|
||||
let appState;
|
||||
|
||||
function checkAddFilters(length, comps, idx) {
|
||||
idx = idx || 0;
|
||||
const filters = queryFilter.addFilters.getCall(idx).args[0];
|
||||
|
||||
expect(filters.length).to.be(length);
|
||||
if (!Array.isArray(comps)) return;
|
||||
comps.forEach(function (comp, i) {
|
||||
expect(filters[i]).to.eql(comp);
|
||||
});
|
||||
}
|
||||
|
||||
describe('Filter Manager', function () {
|
||||
beforeEach(ngMock.module(
|
||||
'kibana',
|
||||
'kibana/global_state',
|
||||
function ($provide) {
|
||||
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
|
||||
|
||||
appState = new MockState({ filters: [] });
|
||||
$provide.service('getAppState', function () {
|
||||
return function () { return appState; };
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
beforeEach(ngMock.inject(function (_$rootScope_, Private) {
|
||||
|
||||
// mock required queryFilter methods, used in the manager
|
||||
queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
filterGen = getFilterGenerator(queryFilter);
|
||||
sinon.stub(queryFilter, 'getAppFilters').callsFake(() => appState.filters);
|
||||
sinon.stub(queryFilter, 'addFilters').callsFake((filters) => {
|
||||
if (!Array.isArray(filters)) filters = [filters];
|
||||
appState.filters = uniqFilters(appState.filters.concat(filters));
|
||||
});
|
||||
}));
|
||||
|
||||
it('should have an `add` function', function () {
|
||||
expect(filterGen.add).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should add a filter', function () {
|
||||
filterGen.add('myField', 1, '+', 'myIndex');
|
||||
expect(queryFilter.addFilters.callCount).to.be(1);
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
query: { match_phrase: { myField: 1 } }
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should add multiple filters if passed an array of values', function () {
|
||||
filterGen.add('myField', [1, 2, 3], '+', 'myIndex');
|
||||
expect(queryFilter.addFilters.callCount).to.be(1);
|
||||
checkAddFilters(3, [{
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
query: { match_phrase: { myField: 1 } }
|
||||
}, {
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
query: { match_phrase: { myField: 2 } }
|
||||
}, {
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
query: { match_phrase: { myField: 3 } }
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should add an exists filter if _exists_ is used as the field', function () {
|
||||
filterGen.add('_exists_', 'myField', '+', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
exists: { field: 'myField' }
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should negate existing filter instead of added a conflicting filter', function () {
|
||||
filterGen.add('myField', 1, '+', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
query: { match_phrase: { myField: 1 } }
|
||||
}], 0);
|
||||
expect(appState.filters).to.have.length(1);
|
||||
|
||||
// NOTE: negating exists filters also forces disabled to false
|
||||
filterGen.add('myField', 1, '-', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: true, disabled: false },
|
||||
query: { match_phrase: { myField: 1 } }
|
||||
}], 1);
|
||||
expect(appState.filters).to.have.length(1);
|
||||
|
||||
filterGen.add('_exists_', 'myField', '+', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: false },
|
||||
exists: { field: 'myField' }
|
||||
}], 2);
|
||||
expect(appState.filters).to.have.length(2);
|
||||
|
||||
filterGen.add('_exists_', 'myField', '-', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: true, disabled: false },
|
||||
exists: { field: 'myField' }
|
||||
}], 3);
|
||||
expect(appState.filters).to.have.length(2);
|
||||
|
||||
const scriptedField = { name: 'scriptedField', scripted: true, script: 1, lang: 'painless' };
|
||||
filterGen.add(scriptedField, 1, '+', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: false, field: 'scriptedField' },
|
||||
script: esFilters.getPhraseScript(scriptedField, 1)
|
||||
}], 4);
|
||||
expect(appState.filters).to.have.length(3);
|
||||
|
||||
filterGen.add(scriptedField, 1, '-', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: true, disabled: false, field: 'scriptedField' },
|
||||
script: esFilters.getPhraseScript(scriptedField, 1)
|
||||
}], 5);
|
||||
expect(appState.filters).to.have.length(3);
|
||||
});
|
||||
|
||||
it('should enable matching filters being changed', function () {
|
||||
_.each([true, false], function (negate) {
|
||||
appState.filters = [{
|
||||
query: { match_phrase: { myField: 1 } },
|
||||
meta: { disabled: true, negate: negate }
|
||||
}];
|
||||
expect(appState.filters.length).to.be(1);
|
||||
expect(appState.filters[0].meta.disabled).to.be(true);
|
||||
|
||||
filterGen.add('myField', 1, '+', 'myIndex');
|
||||
expect(appState.filters.length).to.be(1);
|
||||
expect(appState.filters[0].meta.disabled).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,98 +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 { esFilters } from '../../../../plugins/data/public';
|
||||
|
||||
// Adds a filter to a passed state
|
||||
export function getFilterGenerator(queryFilter) {
|
||||
const filterGen = {};
|
||||
|
||||
filterGen.generate = (field, values, operation, index) => {
|
||||
values = Array.isArray(values) ? values : [values];
|
||||
const fieldName = _.isObject(field) ? field.name : field;
|
||||
const filters = _.flatten([queryFilter.getAppFilters()]);
|
||||
const newFilters = [];
|
||||
|
||||
const negate = (operation === '-');
|
||||
|
||||
// TODO: On array fields, negating does not negate the combination, rather all terms
|
||||
_.each(values, function (value) {
|
||||
let filter;
|
||||
const existing = _.find(filters, function (filter) {
|
||||
if (!filter) return;
|
||||
|
||||
if (fieldName === '_exists_' && filter.exists) {
|
||||
return filter.exists.field === value;
|
||||
}
|
||||
|
||||
if (esFilters.isPhraseFilter(filter)) {
|
||||
return esFilters.getPhraseFilterField(filter) === fieldName && esFilters.getPhraseFilterValue(filter) === value;
|
||||
}
|
||||
|
||||
if (filter.script) {
|
||||
return filter.meta.field === fieldName && filter.script.script.params.value === value;
|
||||
}
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
existing.meta.disabled = false;
|
||||
if (existing.meta.negate !== negate) {
|
||||
existing.meta.negate = !existing.meta.negate;
|
||||
}
|
||||
newFilters.push(existing);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fieldName) {
|
||||
case '_exists_':
|
||||
filter = {
|
||||
meta: { negate, index },
|
||||
exists: {
|
||||
field: value
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
if (field.scripted) {
|
||||
filter = {
|
||||
meta: { negate, index, field: fieldName },
|
||||
script: esFilters.getPhraseScript(field, value)
|
||||
};
|
||||
} else {
|
||||
filter = { meta: { negate, index }, query: { match_phrase: {} } };
|
||||
filter.query.match_phrase[fieldName] = value;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
newFilters.push(filter);
|
||||
});
|
||||
|
||||
return newFilters;
|
||||
};
|
||||
|
||||
filterGen.add = function (field, values, operation, index) {
|
||||
const newFilters = this.generate(field, values, operation, index);
|
||||
return queryFilter.addFilters(newFilters);
|
||||
};
|
||||
|
||||
return filterGen;
|
||||
}
|
|
@ -17,4 +17,3 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { getFilterGenerator } from './filter_generator';
|
||||
|
|
|
@ -22,3 +22,4 @@ export { FilterManager } from './filter_manager';
|
|||
export { uniqFilters } from './lib/uniq_filters';
|
||||
export { mapAndFlattenFilters } from './lib/map_and_flatten_filters';
|
||||
export { onlyDisabledFiltersChanged } from './lib/only_disabled';
|
||||
export { generateFilters } from './lib/generate_filters';
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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 { generateFilters } from './generate_filters';
|
||||
import { FilterManager } from '../filter_manager';
|
||||
import { esFilters } from '../../..';
|
||||
|
||||
const INDEX_NAME = 'my-index';
|
||||
const EXISTS_FIELD_NAME = '_exists_';
|
||||
const FIELD = {
|
||||
name: 'my-field',
|
||||
};
|
||||
const PHRASE_VALUE = 'my-value';
|
||||
|
||||
describe('Generate filters', () => {
|
||||
let mockFilterManager: FilterManager;
|
||||
let filtersArray: esFilters.Filter[];
|
||||
|
||||
beforeEach(() => {
|
||||
filtersArray = [];
|
||||
mockFilterManager = {
|
||||
getAppFilters: () => {
|
||||
return filtersArray;
|
||||
},
|
||||
} as FilterManager;
|
||||
});
|
||||
|
||||
it('should create exists filter', () => {
|
||||
const filters = generateFilters(
|
||||
mockFilterManager,
|
||||
EXISTS_FIELD_NAME,
|
||||
FIELD.name,
|
||||
'',
|
||||
INDEX_NAME
|
||||
);
|
||||
expect(filters).toHaveLength(1);
|
||||
expect(filters[0].meta.index === INDEX_NAME);
|
||||
expect(filters[0].meta.negate).toBeFalsy();
|
||||
expect(esFilters.isExistsFilter(filters[0])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create negated exists filter', () => {
|
||||
const filters = generateFilters(
|
||||
mockFilterManager,
|
||||
EXISTS_FIELD_NAME,
|
||||
FIELD.name,
|
||||
'-',
|
||||
INDEX_NAME
|
||||
);
|
||||
expect(filters).toHaveLength(1);
|
||||
expect(filters[0].meta.index === INDEX_NAME);
|
||||
expect(filters[0].meta.negate).toBeTruthy();
|
||||
expect(esFilters.isExistsFilter(filters[0])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update and re-enable EXISTING exists filter', () => {
|
||||
const filter = esFilters.buildExistsFilter(FIELD, { id: INDEX_NAME });
|
||||
filter.meta.disabled = true;
|
||||
filtersArray.push(filter);
|
||||
|
||||
const filters = generateFilters(mockFilterManager, '_exists_', FIELD.name, '-', INDEX_NAME);
|
||||
expect(filters).toHaveLength(1);
|
||||
expect(filters[0].meta.index === INDEX_NAME);
|
||||
expect(filters[0].meta.negate).toBeTruthy();
|
||||
expect(filters[0].meta.disabled).toBeFalsy();
|
||||
expect(esFilters.isExistsFilter(filters[0])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create phrase filter', () => {
|
||||
const filters = generateFilters(mockFilterManager, FIELD, PHRASE_VALUE, '', INDEX_NAME);
|
||||
expect(filters).toHaveLength(1);
|
||||
expect(filters[0].meta.index === INDEX_NAME);
|
||||
expect(filters[0].meta.negate).toBeFalsy();
|
||||
expect(esFilters.isPhraseFilter(filters[0])).toBeTruthy();
|
||||
expect((filters[0] as esFilters.PhraseFilter).query.match_phrase).toEqual({
|
||||
[FIELD.name]: PHRASE_VALUE,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create negated phrase filter', () => {
|
||||
const filters = generateFilters(mockFilterManager, FIELD, PHRASE_VALUE, '-', INDEX_NAME);
|
||||
expect(filters).toHaveLength(1);
|
||||
expect(filters[0].meta.index === INDEX_NAME);
|
||||
expect(filters[0].meta.negate).toBeTruthy();
|
||||
expect(esFilters.isPhraseFilter(filters[0])).toBeTruthy();
|
||||
expect((filters[0] as esFilters.PhraseFilter).query.match_phrase).toEqual({
|
||||
[FIELD.name]: PHRASE_VALUE,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create multiple phrase filters', () => {
|
||||
const ANOTHER_PHRASE = 'another-value';
|
||||
const filters = generateFilters(
|
||||
mockFilterManager,
|
||||
FIELD,
|
||||
[PHRASE_VALUE, ANOTHER_PHRASE],
|
||||
'',
|
||||
INDEX_NAME
|
||||
);
|
||||
expect(filters).toHaveLength(2);
|
||||
expect(filters[0].meta.index === INDEX_NAME);
|
||||
expect(filters[0].meta.negate).toBeFalsy();
|
||||
expect(filters[1].meta.index === INDEX_NAME);
|
||||
expect(filters[1].meta.negate).toBeFalsy();
|
||||
expect(esFilters.isPhraseFilter(filters[0])).toBeTruthy();
|
||||
expect(esFilters.isPhraseFilter(filters[1])).toBeTruthy();
|
||||
expect((filters[0] as esFilters.PhraseFilter).query.match_phrase).toEqual({
|
||||
[FIELD.name]: PHRASE_VALUE,
|
||||
});
|
||||
expect((filters[1] as esFilters.PhraseFilter).query.match_phrase).toEqual({
|
||||
[FIELD.name]: ANOTHER_PHRASE,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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 { FilterManager, esFilters, Field } from '../../..';
|
||||
|
||||
function getExistingFilter(
|
||||
appFilters: esFilters.Filter[],
|
||||
fieldName: string,
|
||||
value: any
|
||||
): esFilters.Filter | undefined {
|
||||
// TODO: On array fields, negating does not negate the combination, rather all terms
|
||||
return _.find(appFilters, function(filter) {
|
||||
if (!filter) return;
|
||||
|
||||
if (fieldName === '_exists_' && esFilters.isExistsFilter(filter)) {
|
||||
return filter.exists!.field === value;
|
||||
}
|
||||
|
||||
if (esFilters.isPhraseFilter(filter)) {
|
||||
return (
|
||||
esFilters.getPhraseFilterField(filter) === fieldName &&
|
||||
esFilters.getPhraseFilterValue(filter) === value
|
||||
);
|
||||
}
|
||||
|
||||
if (esFilters.isScriptedPhraseFilter(filter)) {
|
||||
return filter.meta.field === fieldName && filter.meta.script!.script.params.value === value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateExistingFilter(existingFilter: esFilters.Filter, negate: boolean) {
|
||||
existingFilter.meta.disabled = false;
|
||||
if (existingFilter.meta.negate !== negate) {
|
||||
existingFilter.meta.negate = !existingFilter.meta.negate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate filter objects, as a result of triggering a filter action on a
|
||||
* specific index pattern field.
|
||||
*
|
||||
* @param {FilterManager} filterManager - The active filter manager to lookup for existing filters
|
||||
* @param {Field | string} field - The field for which filters should be generated
|
||||
* @param {any} values - One or more values to filter for.
|
||||
* @param {string} operation - "-" to create a negated filter
|
||||
* @param {string} index - Index string to generate filters for
|
||||
*
|
||||
* @returns {object} An array of filters to be added back to filterManager
|
||||
*/
|
||||
export function generateFilters(
|
||||
filterManager: FilterManager,
|
||||
field: Field | string,
|
||||
values: any,
|
||||
operation: string,
|
||||
index: string
|
||||
): esFilters.Filter[] {
|
||||
values = Array.isArray(values) ? values : [values];
|
||||
const fieldObj = _.isObject(field)
|
||||
? field
|
||||
: {
|
||||
name: field,
|
||||
};
|
||||
const fieldName = fieldObj.name;
|
||||
const newFilters: esFilters.Filter[] = [];
|
||||
const appFilters = filterManager.getAppFilters();
|
||||
|
||||
const negate = operation === '-';
|
||||
let filter;
|
||||
|
||||
_.each(values, function(value) {
|
||||
const existing = getExistingFilter(appFilters, fieldName, value);
|
||||
|
||||
if (existing) {
|
||||
updateExistingFilter(existing, negate);
|
||||
filter = existing;
|
||||
} else {
|
||||
const tmpIndexPattern = { id: index };
|
||||
switch (fieldName) {
|
||||
case '_exists_':
|
||||
filter = esFilters.buildExistsFilter(fieldObj, tmpIndexPattern);
|
||||
break;
|
||||
default:
|
||||
filter = esFilters.buildPhraseFilter(fieldObj, value, tmpIndexPattern);
|
||||
break;
|
||||
}
|
||||
|
||||
filter.meta.negate = negate;
|
||||
}
|
||||
|
||||
newFilters.push(filter);
|
||||
});
|
||||
|
||||
return newFilters;
|
||||
}
|
Loading…
Reference in a new issue