mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Move @kbn/es-query into data plugin - filters folder (#49843)
Dismissing reviews from ml and canvas as this is only an import change. * Move @kbn/es-query into data plugin - filters folder * fix PR comments
This commit is contained in:
parent
4baf5d9751
commit
c3951e9374
197 changed files with 1965 additions and 1589 deletions
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getConvertedValueForField } from '../filters';
|
||||
import { getConvertedValueForField } from '../utils/filters';
|
||||
|
||||
export function migrateFilter(filter, indexPattern) {
|
||||
if (filter.match) {
|
||||
|
|
|
@ -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 { buildInlineScriptForPhraseFilter, buildPhraseFilter } from '../phrase';
|
||||
import expect from '@kbn/expect';
|
||||
import _ from 'lodash';
|
||||
import indexPattern from '../../__fixtures__/index_pattern_response.json';
|
||||
import filterSkeleton from '../../__fixtures__/filter_skeleton';
|
||||
|
||||
let expected;
|
||||
|
||||
describe('Filter Manager', function () {
|
||||
describe('Phrase filter builder', function () {
|
||||
beforeEach(() => {
|
||||
expected = _.cloneDeep(filterSkeleton);
|
||||
});
|
||||
|
||||
it('should be a function', function () {
|
||||
expect(buildPhraseFilter).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should return a match query filter when passed a standard field', function () {
|
||||
const field = getField(indexPattern, 'bytes');
|
||||
expected.query = {
|
||||
match_phrase: {
|
||||
bytes: 5
|
||||
}
|
||||
};
|
||||
expect(buildPhraseFilter(field, 5, indexPattern)).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should return a script filter when passed a scripted field', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
expected.meta.field = 'script number';
|
||||
_.set(expected, 'script.script', {
|
||||
source: '(' + field.script + ') == value',
|
||||
lang: 'expression',
|
||||
params: {
|
||||
value: 5,
|
||||
}
|
||||
});
|
||||
expect(buildPhraseFilter(field, 5, indexPattern)).to.eql(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildInlineScriptForPhraseFilter', function () {
|
||||
|
||||
it('should wrap painless scripts in a lambda', function () {
|
||||
const field = {
|
||||
lang: 'painless',
|
||||
script: 'return foo;',
|
||||
};
|
||||
|
||||
const expected = `boolean compare(Supplier s, def v) {return s.get() == v;}` +
|
||||
`compare(() -> { return foo; }, params.value);`;
|
||||
|
||||
expect(buildInlineScriptForPhraseFilter(field)).to.be(expected);
|
||||
});
|
||||
|
||||
it('should create a simple comparison for other langs', function () {
|
||||
const field = {
|
||||
lang: 'expression',
|
||||
script: 'doc[bytes].value',
|
||||
};
|
||||
|
||||
const expected = `(doc[bytes].value) == value`;
|
||||
|
||||
expect(buildInlineScriptForPhraseFilter(field)).to.be(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getField(indexPattern, name) {
|
||||
return indexPattern.fields.find(field => field.name === name);
|
||||
}
|
|
@ -1,46 +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 { buildQueryFilter } from '../query';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
import indexPattern from '../../__fixtures__/index_pattern_response.json';
|
||||
import filterSkeleton from '../../__fixtures__/filter_skeleton';
|
||||
|
||||
let expected;
|
||||
|
||||
describe('Filter Manager', function () {
|
||||
describe('Phrase filter builder', function () {
|
||||
beforeEach(() => {
|
||||
expected = cloneDeep(filterSkeleton);
|
||||
});
|
||||
|
||||
it('should be a function', function () {
|
||||
expect(buildQueryFilter).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should return a query filter when passed a standard field', function () {
|
||||
expected.query = {
|
||||
foo: 'bar'
|
||||
};
|
||||
expect(buildQueryFilter({ foo: 'bar' }, indexPattern.id)).to.eql(expected);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -1,156 +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 { buildRangeFilter } from '../range';
|
||||
import expect from '@kbn/expect';
|
||||
import _ from 'lodash';
|
||||
import indexPattern from '../../__fixtures__/index_pattern_response.json';
|
||||
import filterSkeleton from '../../__fixtures__/filter_skeleton';
|
||||
|
||||
let expected;
|
||||
|
||||
describe('Filter Manager', function () {
|
||||
describe('Range filter builder', function () {
|
||||
beforeEach(() => {
|
||||
expected = _.cloneDeep(filterSkeleton);
|
||||
});
|
||||
|
||||
it('should be a function', function () {
|
||||
expect(buildRangeFilter).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should return a range filter when passed a standard field', function () {
|
||||
const field = getField(indexPattern, 'bytes');
|
||||
expected.range = {
|
||||
bytes: {
|
||||
gte: 1,
|
||||
lte: 3
|
||||
}
|
||||
};
|
||||
expect(buildRangeFilter(field, { gte: 1, lte: 3 }, indexPattern)).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should return a script filter when passed a scripted field', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
expected.meta.field = 'script number';
|
||||
_.set(expected, 'script.script', {
|
||||
lang: 'expression',
|
||||
source: '(' + field.script + ')>=gte && (' + field.script + ')<=lte',
|
||||
params: {
|
||||
value: '>=1 <=3',
|
||||
gte: 1,
|
||||
lte: 3
|
||||
}
|
||||
});
|
||||
expect(buildRangeFilter(field, { gte: 1, lte: 3 }, indexPattern)).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should wrap painless scripts in comparator lambdas', function () {
|
||||
const field = getField(indexPattern, 'script date');
|
||||
const expected = `boolean gte(Supplier s, def v) {return !s.get().toInstant().isBefore(Instant.parse(v))} ` +
|
||||
`boolean lte(Supplier s, def v) {return !s.get().toInstant().isAfter(Instant.parse(v))}` +
|
||||
`gte(() -> { ${field.script} }, params.gte) && ` +
|
||||
`lte(() -> { ${field.script} }, params.lte)`;
|
||||
|
||||
const inlineScript = buildRangeFilter(field, { gte: 1, lte: 3 }, indexPattern).script.script.source;
|
||||
expect(inlineScript).to.be(expected);
|
||||
});
|
||||
|
||||
it('should throw an error when gte and gt, or lte and lt are both passed', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
expect(function () {
|
||||
buildRangeFilter(field, { gte: 1, gt: 3 }, indexPattern);
|
||||
}).to.throwError();
|
||||
expect(function () {
|
||||
buildRangeFilter(field, { lte: 1, lt: 3 }, indexPattern);
|
||||
}).to.throwError();
|
||||
});
|
||||
|
||||
it('to use the right operator for each of gte, gt, lt and lte', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
_.each({ gte: '>=', gt: '>', lte: '<=', lt: '<' }, function (operator, key) {
|
||||
const params = {};
|
||||
params[key] = 5;
|
||||
const filter = buildRangeFilter(field, params, indexPattern);
|
||||
|
||||
expect(filter.script.script.source).to.be(
|
||||
'(' + field.script + ')' + operator + key);
|
||||
expect(filter.script.script.params[key]).to.be(5);
|
||||
expect(filter.script.script.params.value).to.be(operator + 5);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given params where one side is infinite', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
let filter;
|
||||
beforeEach(function () {
|
||||
filter = buildRangeFilter(field, { gte: 0, lt: Infinity }, indexPattern);
|
||||
});
|
||||
|
||||
describe('returned filter', function () {
|
||||
it('is a script filter', function () {
|
||||
expect(filter).to.have.property('script');
|
||||
});
|
||||
|
||||
it('contain a param for the finite side', function () {
|
||||
expect(filter.script.script.params).to.have.property('gte', 0);
|
||||
});
|
||||
|
||||
it('does not contain a param for the infinite side', function () {
|
||||
expect(filter.script.script.params).not.to.have.property('lt');
|
||||
});
|
||||
|
||||
it('does not contain a script condition for the infinite side', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
const script = field.script;
|
||||
expect(filter.script.script.source).to.equal(`(${script})>=gte`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given params where both sides are infinite', function () {
|
||||
const field = getField(indexPattern, 'script number');
|
||||
let filter;
|
||||
beforeEach(function () {
|
||||
filter = buildRangeFilter(
|
||||
field, { gte: -Infinity, lt: Infinity }, indexPattern);
|
||||
});
|
||||
|
||||
describe('returned filter', function () {
|
||||
it('is a match_all filter', function () {
|
||||
expect(filter).not.to.have.property('script');
|
||||
expect(filter).to.have.property('match_all');
|
||||
});
|
||||
|
||||
it('does not contain params', function () {
|
||||
expect(filter).not.to.have.property('params');
|
||||
});
|
||||
|
||||
it('meta field is set to field name', function () {
|
||||
expect(filter.meta.field).to.equal('script number');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getField(indexPattern, name) {
|
||||
return indexPattern.fields.find(field => field.name === name);
|
||||
}
|
|
@ -1,30 +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.
|
||||
*/
|
||||
|
||||
// Creates a filter where the given field exists
|
||||
export function buildExistsFilter(field, indexPattern) {
|
||||
return {
|
||||
meta: {
|
||||
index: indexPattern.id
|
||||
},
|
||||
exists: {
|
||||
field: field.name
|
||||
}
|
||||
};
|
||||
}
|
51
packages/kbn-es-query/src/filters/index.d.ts
vendored
51
packages/kbn-es-query/src/filters/index.d.ts
vendored
|
@ -1,51 +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 { CustomFilter, ExistsFilter, PhraseFilter, PhrasesFilter, RangeFilter } from './lib';
|
||||
import { RangeFilterParams } from './lib/range_filter';
|
||||
|
||||
export * from './lib';
|
||||
|
||||
// We can't import the real types from the data plugin, so need to either duplicate
|
||||
// them here or figure out another solution, perhaps housing them in this package
|
||||
type Field = any;
|
||||
type IndexPattern = any;
|
||||
|
||||
export function buildExistsFilter(field: Field, indexPattern: IndexPattern): ExistsFilter;
|
||||
|
||||
export function buildPhraseFilter(
|
||||
field: Field,
|
||||
value: string,
|
||||
indexPattern: IndexPattern
|
||||
): PhraseFilter;
|
||||
|
||||
export function buildPhrasesFilter(
|
||||
field: Field,
|
||||
values: string[],
|
||||
indexPattern: IndexPattern
|
||||
): PhrasesFilter;
|
||||
|
||||
export function buildQueryFilter(query: any, index: string, alias?: string): CustomFilter;
|
||||
|
||||
export function buildRangeFilter(
|
||||
field: Field,
|
||||
params: RangeFilterParams,
|
||||
indexPattern: IndexPattern,
|
||||
formattedValue?: string
|
||||
): RangeFilter;
|
|
@ -1,95 +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.
|
||||
*/
|
||||
|
||||
// The interface the other filters extend
|
||||
export * from './meta_filter';
|
||||
|
||||
// The actual filter types
|
||||
import { CustomFilter } from './custom_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,
|
||||
getPhraseFilterField,
|
||||
getPhraseFilterValue,
|
||||
} from './phrase_filter';
|
||||
import { PhrasesFilter, isPhrasesFilter } from './phrases_filter';
|
||||
import { QueryStringFilter, isQueryStringFilter } from './query_string_filter';
|
||||
import {
|
||||
RangeFilter,
|
||||
isRangeFilter,
|
||||
isScriptedRangeFilter,
|
||||
RangeFilterParams,
|
||||
} 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,
|
||||
getPhraseFilterField,
|
||||
getPhraseFilterValue,
|
||||
PhrasesFilter,
|
||||
isPhrasesFilter,
|
||||
QueryStringFilter,
|
||||
isQueryStringFilter,
|
||||
RangeFilter,
|
||||
isRangeFilter,
|
||||
isScriptedRangeFilter,
|
||||
RangeFilterParams,
|
||||
MatchAllFilter,
|
||||
isMatchAllFilter,
|
||||
MissingFilter,
|
||||
isMissingFilter,
|
||||
};
|
||||
|
||||
// Any filter associated with a field (used in the filter bar/editor)
|
||||
export type FieldFilter =
|
||||
| ExistsFilter
|
||||
| GeoBoundingBoxFilter
|
||||
| GeoPolygonFilter
|
||||
| PhraseFilter
|
||||
| PhrasesFilter
|
||||
| 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',
|
||||
}
|
|
@ -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 { get, isPlainObject } 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;
|
||||
};
|
||||
|
||||
type PhraseFilterValue = string | number | boolean;
|
||||
|
||||
export const isPhraseFilter = (filter: any): filter is PhraseFilter => {
|
||||
const isMatchPhraseQuery = filter && filter.query && filter.query.match_phrase;
|
||||
|
||||
const isDeprecatedMatchPhraseQuery =
|
||||
filter &&
|
||||
filter.query &&
|
||||
filter.query.match &&
|
||||
Object.values(filter.query.match).find((params: any) => params.type === 'phrase');
|
||||
|
||||
return !!(isMatchPhraseQuery || isDeprecatedMatchPhraseQuery);
|
||||
};
|
||||
|
||||
export const isScriptedPhraseFilter = (filter: any): filter is PhraseFilter =>
|
||||
Boolean(get(filter, 'script.script.params.value'));
|
||||
|
||||
export const getPhraseFilterField = (filter: PhraseFilter) => {
|
||||
const queryConfig = filter.query.match_phrase || filter.query.match;
|
||||
return Object.keys(queryConfig)[0];
|
||||
};
|
||||
|
||||
export const getPhraseFilterValue = (filter: PhraseFilter): PhraseFilterValue => {
|
||||
const queryConfig = filter.query.match_phrase || filter.query.match;
|
||||
const queryValue = Object.values(queryConfig)[0] as any;
|
||||
return isPlainObject(queryValue) ? queryValue.query : queryValue;
|
||||
};
|
|
@ -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 { get, keys } from 'lodash';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
|
||||
export interface RangeFilterParams {
|
||||
from?: number | string;
|
||||
to?: number | string;
|
||||
gt?: number | string;
|
||||
lt?: number | string;
|
||||
gte?: number | string;
|
||||
lte?: number | string;
|
||||
format?: string;
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
|
@ -1,85 +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.
|
||||
*/
|
||||
|
||||
// Creates an filter where the given field matches the given value
|
||||
export function buildPhraseFilter(field, value, indexPattern) {
|
||||
const filter = { meta: { index: indexPattern.id } };
|
||||
const convertedValue = getConvertedValueForField(field, value);
|
||||
|
||||
if (field.scripted) {
|
||||
filter.script = getPhraseScript(field, value);
|
||||
filter.meta.field = field.name;
|
||||
} else {
|
||||
filter.query = { match_phrase: {} };
|
||||
filter.query.match_phrase[field.name] = convertedValue;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
export function getPhraseScript(field, value) {
|
||||
const convertedValue = getConvertedValueForField(field, value);
|
||||
const script = buildInlineScriptForPhraseFilter(field);
|
||||
|
||||
return {
|
||||
script: {
|
||||
source: script,
|
||||
lang: field.lang,
|
||||
params: {
|
||||
value: convertedValue
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// See https://github.com/elastic/elasticsearch/issues/20941 and https://github.com/elastic/kibana/issues/8677
|
||||
// and https://github.com/elastic/elasticsearch/pull/22201
|
||||
// for the reason behind this change. Aggs now return boolean buckets with a key of 1 or 0.
|
||||
export function getConvertedValueForField(field, value) {
|
||||
if (typeof value !== 'boolean' && field.type === 'boolean') {
|
||||
if ([1, 'true'].includes(value)) {
|
||||
return true;
|
||||
}
|
||||
else if ([0, 'false'].includes(value)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
throw new Error(`${value} is not a valid boolean value for boolean field ${field.name}`);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a scripted field and returns an inline script appropriate for use in a script query.
|
||||
* Handles lucene expression and Painless scripts. Other langs aren't guaranteed to generate valid
|
||||
* scripts.
|
||||
*
|
||||
* @param {object} scriptedField A Field object representing a scripted field
|
||||
* @returns {string} The inline script string
|
||||
*/
|
||||
export function buildInlineScriptForPhraseFilter(scriptedField) {
|
||||
// We must wrap painless scripts in a lambda in case they're more than a simple expression
|
||||
if (scriptedField.lang === 'painless') {
|
||||
return `boolean compare(Supplier s, def v) {return s.get() == v;}` +
|
||||
`compare(() -> { ${scriptedField.script} }, params.value);`;
|
||||
}
|
||||
else {
|
||||
return `(${scriptedField.script}) == value`;
|
||||
}
|
||||
}
|
1
packages/kbn-es-query/src/index.d.ts
vendored
1
packages/kbn-es-query/src/index.d.ts
vendored
|
@ -19,4 +19,3 @@
|
|||
|
||||
export * from './es_query';
|
||||
export * from './kuery';
|
||||
export * from './filters';
|
||||
|
|
|
@ -18,5 +18,4 @@
|
|||
*/
|
||||
|
||||
export * from './kuery';
|
||||
export * from './filters';
|
||||
export * from './es_query';
|
||||
|
|
|
@ -21,7 +21,7 @@ import _ from 'lodash';
|
|||
import * as ast from '../ast';
|
||||
import * as literal from '../node_types/literal';
|
||||
import * as wildcard from '../node_types/wildcard';
|
||||
import { getPhraseScript } from '../../filters';
|
||||
import { getPhraseScript } from '../../utils/filters';
|
||||
import { getFields } from './utils/get_fields';
|
||||
import { getTimeZoneFromSettings } from '../../utils/get_time_zone_from_settings';
|
||||
import { getFullFieldNameNode } from './utils/get_full_field_name_node';
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import _ from 'lodash';
|
||||
import { nodeTypes } from '../node_types';
|
||||
import * as ast from '../ast';
|
||||
import { getRangeScript } from '../../filters';
|
||||
import { getRangeScript } from '../../utils/filters';
|
||||
import { getFields } from './utils/get_fields';
|
||||
import { getTimeZoneFromSettings } from '../../utils/get_time_zone_from_settings';
|
||||
import { getFullFieldNameNode } from './utils/get_full_field_name_node';
|
||||
|
|
133
packages/kbn-es-query/src/utils/filters.js
Normal file
133
packages/kbn-es-query/src/utils/filters.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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 { pick, get, reduce, map } from 'lodash';
|
||||
|
||||
/** @deprecated
|
||||
* @see src/plugins/data/public/es_query/filters/phrase_filter.ts
|
||||
* Code was already moved into src/plugins/data/public.
|
||||
* This method will be removed after moving 'es_query' into new platform
|
||||
* */
|
||||
export const getConvertedValueForField = (field, value) => {
|
||||
if (typeof value !== 'boolean' && field.type === 'boolean') {
|
||||
if ([1, 'true'].includes(value)) {
|
||||
return true;
|
||||
} else if ([0, 'false'].includes(value)) {
|
||||
return false;
|
||||
} else {
|
||||
throw new Error(`${value} is not a valid boolean value for boolean field ${field.name}`);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/** @deprecated
|
||||
* @see src/plugins/data/public/es_query/filters/phrase_filter.ts
|
||||
* Code was already moved into src/plugins/data/public.
|
||||
* This method will be removed after moving 'es_query' into new platform
|
||||
* */
|
||||
export const buildInlineScriptForPhraseFilter = (scriptedField) => {
|
||||
// We must wrap painless scripts in a lambda in case they're more than a simple expression
|
||||
if (scriptedField.lang === 'painless') {
|
||||
return (
|
||||
`boolean compare(Supplier s, def v) {return s.get() == v;}` +
|
||||
`compare(() -> { ${scriptedField.script} }, params.value);`
|
||||
);
|
||||
} else {
|
||||
return `(${scriptedField.script}) == value`;
|
||||
}
|
||||
};
|
||||
|
||||
/** @deprecated
|
||||
* @see src/plugins/data/public/es_query/filters/phrase_filter.ts
|
||||
* Code was already moved into src/plugins/data/public.
|
||||
* This method will be removed after moving 'es_query' into new platform
|
||||
* */
|
||||
export function getPhraseScript(field, value) {
|
||||
const convertedValue = getConvertedValueForField(field, value);
|
||||
const script = buildInlineScriptForPhraseFilter(field);
|
||||
|
||||
return {
|
||||
script: {
|
||||
source: script,
|
||||
lang: field.lang,
|
||||
params: {
|
||||
value: convertedValue,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** @deprecated
|
||||
* @see src/plugins/data/public/es_query/filters/range_filter.ts
|
||||
* Code was already moved into src/plugins/data/public.
|
||||
* This method will be removed after moving 'kuery' into new platform
|
||||
* */
|
||||
export function getRangeScript(field, params) {
|
||||
const operators = {
|
||||
gt: '>',
|
||||
gte: '>=',
|
||||
lte: '<=',
|
||||
lt: '<',
|
||||
};
|
||||
const comparators = {
|
||||
gt: 'boolean gt(Supplier s, def v) {return s.get() > v}',
|
||||
gte: 'boolean gte(Supplier s, def v) {return s.get() >= v}',
|
||||
lte: 'boolean lte(Supplier s, def v) {return s.get() <= v}',
|
||||
lt: 'boolean lt(Supplier s, def v) {return s.get() < v}',
|
||||
};
|
||||
|
||||
const dateComparators = {
|
||||
gt: 'boolean gt(Supplier s, def v) {return s.get().toInstant().isAfter(Instant.parse(v))}',
|
||||
gte: 'boolean gte(Supplier s, def v) {return !s.get().toInstant().isBefore(Instant.parse(v))}',
|
||||
lte: 'boolean lte(Supplier s, def v) {return !s.get().toInstant().isAfter(Instant.parse(v))}',
|
||||
lt: 'boolean lt(Supplier s, def v) {return s.get().toInstant().isBefore(Instant.parse(v))}',
|
||||
};
|
||||
|
||||
const knownParams = pick(params, (val, key) => {
|
||||
return key in operators;
|
||||
});
|
||||
let script = map(knownParams, (val, key) => {
|
||||
return '(' + field.script + ')' + get(operators, key) + key;
|
||||
}).join(' && ');
|
||||
|
||||
// We must wrap painless scripts in a lambda in case they're more than a simple expression
|
||||
if (field.lang === 'painless') {
|
||||
const comp = field.type === 'date' ? dateComparators : comparators;
|
||||
const currentComparators = reduce(
|
||||
knownParams,
|
||||
(acc, val, key) => acc.concat(get(comp, key)),
|
||||
[]
|
||||
).join(' ');
|
||||
|
||||
const comparisons = map(knownParams, (val, key) => {
|
||||
return `${key}(() -> { ${field.script} }, params.${key})`;
|
||||
}).join(' && ');
|
||||
|
||||
script = `${currentComparators}${comparisons}`;
|
||||
}
|
||||
|
||||
return {
|
||||
script: {
|
||||
source: script,
|
||||
params: knownParams,
|
||||
lang: field.lang,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -18,21 +18,20 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { CoreStart } from 'src/core/public';
|
||||
import {
|
||||
IAction,
|
||||
createAction,
|
||||
IncompatibleActionError,
|
||||
} from '../../../../../../plugins/ui_actions/public';
|
||||
import { FilterManager } from '../../../../../../plugins/data/public';
|
||||
import { FilterManager, esFilters } from '../../../../../../plugins/data/public';
|
||||
import { TimefilterContract, changeTimeFilter, extractTimeFilter } from '../../timefilter';
|
||||
import { applyFiltersPopover } from '../apply_filters/apply_filters_popover';
|
||||
import { IndexPatternsStart } from '../../index_patterns';
|
||||
export const GLOBAL_APPLY_FILTER_ACTION = 'GLOBAL_APPLY_FILTER_ACTION';
|
||||
|
||||
interface ActionContext {
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
timeFieldName?: string;
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,7 @@ export function createFilterAction(
|
|||
throw new IncompatibleActionError();
|
||||
}
|
||||
|
||||
let selectedFilters: Filter[] = filters;
|
||||
let selectedFilters: esFilters.Filter[] = filters;
|
||||
|
||||
if (selectedFilters.length > 1) {
|
||||
const indexPatterns = await Promise.all(
|
||||
|
@ -73,7 +72,7 @@ export function createFilterAction(
|
|||
})
|
||||
);
|
||||
|
||||
const filterSelectionPromise: Promise<Filter[]> = new Promise(resolve => {
|
||||
const filterSelectionPromise: Promise<esFilters.Filter[]> = new Promise(resolve => {
|
||||
const overlay = overlays.openModal(
|
||||
applyFiltersPopover(
|
||||
filters,
|
||||
|
@ -82,7 +81,7 @@ export function createFilterAction(
|
|||
overlay.close();
|
||||
resolve([]);
|
||||
},
|
||||
(filterSelection: Filter[]) => {
|
||||
(filterSelection: esFilters.Filter[]) => {
|
||||
overlay.close();
|
||||
resolve(filterSelection);
|
||||
}
|
||||
|
|
|
@ -28,19 +28,18 @@ import {
|
|||
EuiModalHeaderTitle,
|
||||
EuiSwitch,
|
||||
} from '@elastic/eui';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { Component } from 'react';
|
||||
import { IndexPattern } from '../../index_patterns';
|
||||
import { getFilterDisplayText } from '../filter_bar/filter_editor/lib/get_filter_display_text';
|
||||
import { mapAndFlattenFilters } from '../../../../../../plugins/data/public';
|
||||
import { mapAndFlattenFilters, esFilters } from '../../../../../../plugins/data/public';
|
||||
import { getDisplayValueFromFilter } from '../filter_bar/filter_editor/lib/get_display_value';
|
||||
|
||||
interface Props {
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
indexPatterns: IndexPattern[];
|
||||
onCancel: () => void;
|
||||
onSubmit: (filters: Filter[]) => void;
|
||||
onSubmit: (filters: esFilters.Filter[]) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -58,7 +57,7 @@ export class ApplyFiltersPopoverContent extends Component<Props, State> {
|
|||
isFilterSelected: props.filters.map(() => true),
|
||||
};
|
||||
}
|
||||
private getLabel(filter: Filter) {
|
||||
private getLabel(filter: esFilters.Filter) {
|
||||
const filterDisplayValue = getDisplayValueFromFilter(filter, this.props.indexPatterns);
|
||||
return getFilterDisplayText(filter, filterDisplayValue);
|
||||
}
|
||||
|
|
|
@ -18,15 +18,15 @@
|
|||
*/
|
||||
|
||||
import { EuiModal, EuiOverlayMask } from '@elastic/eui';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import React, { Component } from 'react';
|
||||
import { ApplyFiltersPopoverContent } from './apply_filter_popover_content';
|
||||
import { IndexPattern } from '../../index_patterns/index_patterns';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
interface Props {
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
onCancel: () => void;
|
||||
onSubmit: (filters: Filter[]) => void;
|
||||
onSubmit: (filters: esFilters.Filter[]) => void;
|
||||
indexPatterns: IndexPattern[];
|
||||
}
|
||||
|
||||
|
@ -56,9 +56,9 @@ export class ApplyFiltersPopover extends Component<Props, State> {
|
|||
}
|
||||
|
||||
type cancelFunction = () => void;
|
||||
type submitFunction = (filters: Filter[]) => void;
|
||||
type submitFunction = (filters: esFilters.Filter[]) => void;
|
||||
export const applyFiltersPopover = (
|
||||
filters: Filter[],
|
||||
filters: esFilters.Filter[],
|
||||
indexPatterns: IndexPattern[],
|
||||
onCancel: cancelFunction,
|
||||
onSubmit: submitFunction
|
||||
|
|
|
@ -18,16 +18,6 @@
|
|||
*/
|
||||
|
||||
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui';
|
||||
import {
|
||||
buildEmptyFilter,
|
||||
disableFilter,
|
||||
enableFilter,
|
||||
Filter,
|
||||
pinFilter,
|
||||
toggleFilterDisabled,
|
||||
toggleFilterNegated,
|
||||
unpinFilter,
|
||||
} from '@kbn/es-query';
|
||||
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import classNames from 'classnames';
|
||||
import React, { useState } from 'react';
|
||||
|
@ -38,10 +28,11 @@ import { FilterEditor } from './filter_editor';
|
|||
import { FilterItem } from './filter_item';
|
||||
import { FilterOptions } from './filter_options';
|
||||
import { useKibana, KibanaContextProvider } from '../../../../../../plugins/kibana_react/public';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
interface Props {
|
||||
filters: Filter[];
|
||||
onFiltersUpdated?: (filters: Filter[]) => void;
|
||||
filters: esFilters.Filter[];
|
||||
onFiltersUpdated?: (filters: esFilters.Filter[]) => void;
|
||||
className: string;
|
||||
indexPatterns: IndexPattern[];
|
||||
intl: InjectedIntl;
|
||||
|
@ -87,7 +78,7 @@ function FilterBarUI(props: Props) {
|
|||
return content;
|
||||
}
|
||||
|
||||
function onFiltersUpdated(filters: Filter[]) {
|
||||
function onFiltersUpdated(filters: esFilters.Filter[]) {
|
||||
if (props.onFiltersUpdated) {
|
||||
props.onFiltersUpdated(filters);
|
||||
}
|
||||
|
@ -112,7 +103,7 @@ function FilterBarUI(props: Props) {
|
|||
const isPinned = uiSettings!.get('filters:pinnedByDefault');
|
||||
const [indexPattern] = props.indexPatterns;
|
||||
const index = indexPattern && indexPattern.id;
|
||||
const newFilter = buildEmptyFilter(isPinned, index);
|
||||
const newFilter = esFilters.buildEmptyFilter(isPinned, index);
|
||||
|
||||
const button = (
|
||||
<EuiButtonEmpty
|
||||
|
@ -157,7 +148,7 @@ function FilterBarUI(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
function onAdd(filter: Filter) {
|
||||
function onAdd(filter: esFilters.Filter) {
|
||||
setIsAddFilterPopoverOpen(false);
|
||||
const filters = [...props.filters, filter];
|
||||
onFiltersUpdated(filters);
|
||||
|
@ -169,39 +160,39 @@ function FilterBarUI(props: Props) {
|
|||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onUpdate(i: number, filter: Filter) {
|
||||
function onUpdate(i: number, filter: esFilters.Filter) {
|
||||
const filters = [...props.filters];
|
||||
filters[i] = filter;
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onEnableAll() {
|
||||
const filters = props.filters.map(enableFilter);
|
||||
const filters = props.filters.map(esFilters.enableFilter);
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onDisableAll() {
|
||||
const filters = props.filters.map(disableFilter);
|
||||
const filters = props.filters.map(esFilters.disableFilter);
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onPinAll() {
|
||||
const filters = props.filters.map(pinFilter);
|
||||
const filters = props.filters.map(esFilters.pinFilter);
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onUnpinAll() {
|
||||
const filters = props.filters.map(unpinFilter);
|
||||
const filters = props.filters.map(esFilters.unpinFilter);
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onToggleAllNegated() {
|
||||
const filters = props.filters.map(toggleFilterNegated);
|
||||
const filters = props.filters.map(esFilters.toggleFilterNegated);
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
function onToggleAllDisabled() {
|
||||
const filters = props.filters.map(toggleFilterDisabled);
|
||||
const filters = props.filters.map(esFilters.toggleFilterDisabled);
|
||||
onFiltersUpdated(filters);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import {
|
|||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
} from '@elastic/eui';
|
||||
import { FieldFilter, Filter } from '@kbn/es-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import { get } from 'lodash';
|
||||
|
@ -54,11 +53,12 @@ import { Operator } from './lib/filter_operators';
|
|||
import { PhraseValueInput } from './phrase_value_input';
|
||||
import { PhrasesValuesInput } from './phrases_values_input';
|
||||
import { RangeValueInput } from './range_value_input';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
interface Props {
|
||||
filter: Filter;
|
||||
filter: esFilters.Filter;
|
||||
indexPatterns: IndexPattern[];
|
||||
onSubmit: (filter: Filter) => void;
|
||||
onSubmit: (filter: esFilters.Filter) => void;
|
||||
onCancel: () => void;
|
||||
intl: InjectedIntl;
|
||||
}
|
||||
|
@ -379,7 +379,9 @@ class FilterEditorUI extends Component<Props, State> {
|
|||
|
||||
private getFieldFromFilter() {
|
||||
const indexPattern = this.getIndexPatternFromFilter();
|
||||
return indexPattern && getFieldFromFilter(this.props.filter as FieldFilter, indexPattern);
|
||||
return (
|
||||
indexPattern && getFieldFromFilter(this.props.filter as esFilters.FieldFilter, indexPattern)
|
||||
);
|
||||
}
|
||||
|
||||
private getSelectedOperator() {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { FilterStateStore, toggleFilterNegated } from '@kbn/es-query';
|
||||
import { mockFields, mockIndexPattern } from '../../../../index_patterns';
|
||||
import { IndexPattern, Field } from '../../../../index';
|
||||
import {
|
||||
|
@ -42,6 +41,7 @@ import { existsFilter } from './fixtures/exists_filter';
|
|||
import { phraseFilter } from './fixtures/phrase_filter';
|
||||
import { phrasesFilter } from './fixtures/phrases_filter';
|
||||
import { rangeFilter } from './fixtures/range_filter';
|
||||
import { esFilters } from '../../../../../../../../plugins/data/public';
|
||||
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
|
@ -81,7 +81,7 @@ describe('Filter editor utils', () => {
|
|||
});
|
||||
|
||||
it('should return "is not" for phrase filter', () => {
|
||||
const negatedPhraseFilter = toggleFilterNegated(phraseFilter);
|
||||
const negatedPhraseFilter = esFilters.toggleFilterNegated(phraseFilter);
|
||||
const operator = getOperatorFromFilter(negatedPhraseFilter);
|
||||
expect(operator).not.toBeUndefined();
|
||||
expect(operator && operator.type).toBe('phrase');
|
||||
|
@ -96,7 +96,7 @@ describe('Filter editor utils', () => {
|
|||
});
|
||||
|
||||
it('should return "is not one of" for negated phrases filter', () => {
|
||||
const negatedPhrasesFilter = toggleFilterNegated(phrasesFilter);
|
||||
const negatedPhrasesFilter = esFilters.toggleFilterNegated(phrasesFilter);
|
||||
const operator = getOperatorFromFilter(negatedPhrasesFilter);
|
||||
expect(operator).not.toBeUndefined();
|
||||
expect(operator && operator.type).toBe('phrases');
|
||||
|
@ -111,7 +111,7 @@ describe('Filter editor utils', () => {
|
|||
});
|
||||
|
||||
it('should return "is not between" for negated range filter', () => {
|
||||
const negatedRangeFilter = toggleFilterNegated(rangeFilter);
|
||||
const negatedRangeFilter = esFilters.toggleFilterNegated(rangeFilter);
|
||||
const operator = getOperatorFromFilter(negatedRangeFilter);
|
||||
expect(operator).not.toBeUndefined();
|
||||
expect(operator && operator.type).toBe('range');
|
||||
|
@ -126,7 +126,7 @@ describe('Filter editor utils', () => {
|
|||
});
|
||||
|
||||
it('should return "does not exists" for negated exists filter', () => {
|
||||
const negatedExistsFilter = toggleFilterNegated(existsFilter);
|
||||
const negatedExistsFilter = esFilters.toggleFilterNegated(existsFilter);
|
||||
const operator = getOperatorFromFilter(negatedExistsFilter);
|
||||
expect(operator).not.toBeUndefined();
|
||||
expect(operator && operator.type).toBe('exists');
|
||||
|
@ -246,7 +246,7 @@ describe('Filter editor utils', () => {
|
|||
it('should build phrase filters', () => {
|
||||
const params = 'foo';
|
||||
const alias = 'bar';
|
||||
const state = FilterStateStore.APP_STATE;
|
||||
const state = esFilters.FilterStateStore.APP_STATE;
|
||||
const filter = buildFilter(
|
||||
mockedIndexPattern,
|
||||
mockedFields[0],
|
||||
|
@ -268,7 +268,7 @@ describe('Filter editor utils', () => {
|
|||
it('should build phrases filters', () => {
|
||||
const params = ['foo', 'bar'];
|
||||
const alias = 'bar';
|
||||
const state = FilterStateStore.APP_STATE;
|
||||
const state = esFilters.FilterStateStore.APP_STATE;
|
||||
const filter = buildFilter(
|
||||
mockedIndexPattern,
|
||||
mockedFields[0],
|
||||
|
@ -290,7 +290,7 @@ describe('Filter editor utils', () => {
|
|||
it('should build range filters', () => {
|
||||
const params = { from: 'foo', to: 'qux' };
|
||||
const alias = 'bar';
|
||||
const state = FilterStateStore.APP_STATE;
|
||||
const state = esFilters.FilterStateStore.APP_STATE;
|
||||
const filter = buildFilter(
|
||||
mockedIndexPattern,
|
||||
mockedFields[0],
|
||||
|
@ -311,7 +311,7 @@ describe('Filter editor utils', () => {
|
|||
it('should build exists filters', () => {
|
||||
const params = undefined;
|
||||
const alias = 'bar';
|
||||
const state = FilterStateStore.APP_STATE;
|
||||
const state = esFilters.FilterStateStore.APP_STATE;
|
||||
const filter = buildFilter(
|
||||
mockedIndexPattern,
|
||||
mockedFields[0],
|
||||
|
@ -332,7 +332,7 @@ describe('Filter editor utils', () => {
|
|||
it('should include disabled state', () => {
|
||||
const params = undefined;
|
||||
const alias = 'bar';
|
||||
const state = FilterStateStore.APP_STATE;
|
||||
const state = esFilters.FilterStateStore.APP_STATE;
|
||||
const filter = buildFilter(
|
||||
mockedIndexPattern,
|
||||
mockedFields[0],
|
||||
|
@ -348,7 +348,7 @@ describe('Filter editor utils', () => {
|
|||
it('should negate based on operator', () => {
|
||||
const params = undefined;
|
||||
const alias = 'bar';
|
||||
const state = FilterStateStore.APP_STATE;
|
||||
const state = esFilters.FilterStateStore.APP_STATE;
|
||||
const filter = buildFilter(
|
||||
mockedIndexPattern,
|
||||
mockedFields[0],
|
||||
|
|
|
@ -18,42 +18,30 @@
|
|||
*/
|
||||
|
||||
import dateMath from '@elastic/datemath';
|
||||
import {
|
||||
buildExistsFilter,
|
||||
buildPhraseFilter,
|
||||
buildPhrasesFilter,
|
||||
buildRangeFilter,
|
||||
FieldFilter,
|
||||
Filter,
|
||||
FilterMeta,
|
||||
FilterStateStore,
|
||||
PhraseFilter,
|
||||
PhrasesFilter,
|
||||
RangeFilter,
|
||||
} from '@kbn/es-query';
|
||||
import { omit } from 'lodash';
|
||||
import { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public';
|
||||
import { Field, IndexPattern, isFilterable } from '../../../../index_patterns';
|
||||
import { FILTER_OPERATORS, Operator } from './filter_operators';
|
||||
import { esFilters } from '../../../../../../../../plugins/data/public';
|
||||
|
||||
export function getIndexPatternFromFilter(
|
||||
filter: Filter,
|
||||
filter: esFilters.Filter,
|
||||
indexPatterns: IndexPattern[]
|
||||
): IndexPattern | undefined {
|
||||
return indexPatterns.find(indexPattern => indexPattern.id === filter.meta.index);
|
||||
}
|
||||
|
||||
export function getFieldFromFilter(filter: FieldFilter, indexPattern: IndexPattern) {
|
||||
export function getFieldFromFilter(filter: esFilters.FieldFilter, indexPattern: IndexPattern) {
|
||||
return indexPattern.fields.find(field => field.name === filter.meta.key);
|
||||
}
|
||||
|
||||
export function getOperatorFromFilter(filter: Filter) {
|
||||
export function getOperatorFromFilter(filter: esFilters.Filter) {
|
||||
return FILTER_OPERATORS.find(operator => {
|
||||
return filter.meta.type === operator.type && filter.meta.negate === operator.negate;
|
||||
});
|
||||
}
|
||||
|
||||
export function getQueryDslFromFilter(filter: Filter) {
|
||||
export function getQueryDslFromFilter(filter: esFilters.Filter) {
|
||||
return omit(filter, ['$state', 'meta']);
|
||||
}
|
||||
|
||||
|
@ -67,16 +55,16 @@ export function getOperatorOptions(field: Field) {
|
|||
});
|
||||
}
|
||||
|
||||
export function getFilterParams(filter: Filter) {
|
||||
export function getFilterParams(filter: esFilters.Filter) {
|
||||
switch (filter.meta.type) {
|
||||
case 'phrase':
|
||||
return (filter as PhraseFilter).meta.params.query;
|
||||
return (filter as esFilters.PhraseFilter).meta.params.query;
|
||||
case 'phrases':
|
||||
return (filter as PhrasesFilter).meta.params;
|
||||
return (filter as esFilters.PhrasesFilter).meta.params;
|
||||
case 'range':
|
||||
return {
|
||||
from: (filter as RangeFilter).meta.params.gte,
|
||||
to: (filter as RangeFilter).meta.params.lt,
|
||||
from: (filter as esFilters.RangeFilter).meta.params.gte,
|
||||
to: (filter as esFilters.RangeFilter).meta.params.lt,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -133,8 +121,8 @@ export function buildFilter(
|
|||
disabled: boolean,
|
||||
params: any,
|
||||
alias: string | null,
|
||||
store: FilterStateStore
|
||||
): Filter {
|
||||
store: esFilters.FilterStateStore
|
||||
): esFilters.Filter {
|
||||
const filter = buildBaseFilter(indexPattern, field, operator, params);
|
||||
filter.meta.alias = alias;
|
||||
filter.meta.negate = operator.negate;
|
||||
|
@ -148,17 +136,17 @@ function buildBaseFilter(
|
|||
field: Field,
|
||||
operator: Operator,
|
||||
params: any
|
||||
): Filter {
|
||||
): esFilters.Filter {
|
||||
switch (operator.type) {
|
||||
case 'phrase':
|
||||
return buildPhraseFilter(field, params, indexPattern);
|
||||
return esFilters.buildPhraseFilter(field, params, indexPattern);
|
||||
case 'phrases':
|
||||
return buildPhrasesFilter(field, params, indexPattern);
|
||||
return esFilters.buildPhrasesFilter(field, params, indexPattern);
|
||||
case 'range':
|
||||
const newParams = { gte: params.from, lt: params.to };
|
||||
return buildRangeFilter(field, newParams, indexPattern);
|
||||
return esFilters.buildRangeFilter(field, newParams, indexPattern);
|
||||
case 'exists':
|
||||
return buildExistsFilter(field, indexPattern);
|
||||
return esFilters.buildExistsFilter(field, indexPattern);
|
||||
default:
|
||||
throw new Error(`Unknown operator type: ${operator.type}`);
|
||||
}
|
||||
|
@ -170,10 +158,10 @@ export function buildCustomFilter(
|
|||
disabled: boolean,
|
||||
negate: boolean,
|
||||
alias: string | null,
|
||||
store: FilterStateStore
|
||||
): Filter {
|
||||
const meta: FilterMeta = { index, type: 'custom', disabled, negate, alias };
|
||||
const filter: Filter = { ...queryDsl, meta };
|
||||
store: esFilters.FilterStateStore
|
||||
): esFilters.Filter {
|
||||
const meta: esFilters.FilterMeta = { index, type: 'custom', disabled, negate, alias };
|
||||
const filter: esFilters.Filter = { ...queryDsl, meta };
|
||||
filter.$state = { store };
|
||||
return filter;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExistsFilter, FilterStateStore } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../../../plugins/data/public';
|
||||
|
||||
export const existsFilter: ExistsFilter = {
|
||||
export const existsFilter: esFilters.ExistsFilter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
negate: false,
|
||||
|
@ -29,6 +29,6 @@ export const existsFilter: ExistsFilter = {
|
|||
alias: null,
|
||||
},
|
||||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
store: esFilters.FilterStateStore.APP_STATE,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { FilterStateStore, PhraseFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../../../plugins/data/public';
|
||||
|
||||
export const phraseFilter: PhraseFilter = {
|
||||
export const phraseFilter: esFilters.PhraseFilter = {
|
||||
meta: {
|
||||
negate: false,
|
||||
index: 'logstash-*',
|
||||
|
@ -33,6 +33,6 @@ export const phraseFilter: PhraseFilter = {
|
|||
},
|
||||
},
|
||||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
store: esFilters.FilterStateStore.APP_STATE,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { FilterStateStore, PhrasesFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../../../plugins/data/public';
|
||||
|
||||
export const phrasesFilter: PhrasesFilter = {
|
||||
export const phrasesFilter: esFilters.PhrasesFilter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
type: 'phrases',
|
||||
|
@ -31,6 +31,6 @@ export const phrasesFilter: PhrasesFilter = {
|
|||
alias: null,
|
||||
},
|
||||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
store: esFilters.FilterStateStore.APP_STATE,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { FilterStateStore, RangeFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../../../plugins/data/public';
|
||||
|
||||
export const rangeFilter: RangeFilter = {
|
||||
export const rangeFilter: esFilters.RangeFilter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
negate: false,
|
||||
|
@ -34,7 +34,7 @@ export const rangeFilter: RangeFilter = {
|
|||
},
|
||||
},
|
||||
$state: {
|
||||
store: FilterStateStore.APP_STATE,
|
||||
store: esFilters.FilterStateStore.APP_STATE,
|
||||
},
|
||||
range: {},
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../../plugins/data/public';
|
||||
import { IndexPattern } from '../../../../index_patterns/index_patterns';
|
||||
import { Field } from '../../../../index_patterns/fields';
|
||||
import { getIndexPatternFromFilter } from './filter_editor_utils';
|
||||
|
@ -33,7 +33,10 @@ function getValueFormatter(indexPattern?: IndexPattern, key?: string) {
|
|||
return format;
|
||||
}
|
||||
|
||||
export function getDisplayValueFromFilter(filter: Filter, indexPatterns: IndexPattern[]): string {
|
||||
export function getDisplayValueFromFilter(
|
||||
filter: esFilters.Filter,
|
||||
indexPatterns: IndexPattern[]
|
||||
): string {
|
||||
const indexPattern = getIndexPatternFromFilter(filter, indexPatterns);
|
||||
|
||||
if (typeof filter.meta.value === 'function') {
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
import React, { Fragment } from 'react';
|
||||
import { EuiTextColor } from '@elastic/eui';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { existsOperator, isOneOfOperator } from './filter_operators';
|
||||
import { esFilters } from '../../../../../../../../plugins/data/public';
|
||||
|
||||
export function getFilterDisplayText(filter: Filter, filterDisplayName: string) {
|
||||
export function getFilterDisplayText(filter: esFilters.Filter, filterDisplayName: string) {
|
||||
const prefixText = filter.meta.negate
|
||||
? ` ${i18n.translate('data.filter.filterBar.negatedFilterPrefix', {
|
||||
defaultMessage: 'NOT ',
|
||||
|
|
|
@ -18,13 +18,6 @@
|
|||
*/
|
||||
|
||||
import { EuiContextMenu, EuiPopover } from '@elastic/eui';
|
||||
import {
|
||||
Filter,
|
||||
isFilterPinned,
|
||||
toggleFilterDisabled,
|
||||
toggleFilterNegated,
|
||||
toggleFilterPinned,
|
||||
} from '@kbn/es-query';
|
||||
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import classNames from 'classnames';
|
||||
import React, { Component } from 'react';
|
||||
|
@ -33,13 +26,14 @@ import { IndexPattern } from '../../index_patterns';
|
|||
import { FilterEditor } from './filter_editor';
|
||||
import { FilterView } from './filter_view';
|
||||
import { getDisplayValueFromFilter } from './filter_editor/lib/get_display_value';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
filter: Filter;
|
||||
filter: esFilters.Filter;
|
||||
indexPatterns: IndexPattern[];
|
||||
className?: string;
|
||||
onUpdate: (filter: Filter) => void;
|
||||
onUpdate: (filter: esFilters.Filter) => void;
|
||||
onRemove: () => void;
|
||||
intl: InjectedIntl;
|
||||
uiSettings: UiSettingsClientContract;
|
||||
|
@ -62,7 +56,7 @@ class FilterItemUI extends Component<Props, State> {
|
|||
'globalFilterItem',
|
||||
{
|
||||
'globalFilterItem-isDisabled': disabled,
|
||||
'globalFilterItem-isPinned': isFilterPinned(filter),
|
||||
'globalFilterItem-isPinned': esFilters.isFilterPinned(filter),
|
||||
'globalFilterItem-isExcluded': negate,
|
||||
},
|
||||
this.props.className
|
||||
|
@ -91,7 +85,7 @@ class FilterItemUI extends Component<Props, State> {
|
|||
id: 0,
|
||||
items: [
|
||||
{
|
||||
name: isFilterPinned(filter)
|
||||
name: esFilters.isFilterPinned(filter)
|
||||
? this.props.intl.formatMessage({
|
||||
id: 'data.filter.filterBar.unpinFilterButtonLabel',
|
||||
defaultMessage: 'Unpin',
|
||||
|
@ -209,23 +203,23 @@ class FilterItemUI extends Component<Props, State> {
|
|||
});
|
||||
};
|
||||
|
||||
private onSubmit = (filter: Filter) => {
|
||||
private onSubmit = (filter: esFilters.Filter) => {
|
||||
this.closePopover();
|
||||
this.props.onUpdate(filter);
|
||||
};
|
||||
|
||||
private onTogglePinned = () => {
|
||||
const filter = toggleFilterPinned(this.props.filter);
|
||||
const filter = esFilters.toggleFilterPinned(this.props.filter);
|
||||
this.props.onUpdate(filter);
|
||||
};
|
||||
|
||||
private onToggleNegated = () => {
|
||||
const filter = toggleFilterNegated(this.props.filter);
|
||||
const filter = esFilters.toggleFilterNegated(this.props.filter);
|
||||
this.props.onUpdate(filter);
|
||||
};
|
||||
|
||||
private onToggleDisabled = () => {
|
||||
const filter = toggleFilterDisabled(this.props.filter);
|
||||
const filter = esFilters.toggleFilterDisabled(this.props.filter);
|
||||
this.props.onUpdate(filter);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
*/
|
||||
|
||||
import { EuiBadge, useInnerText } from '@elastic/eui';
|
||||
import { Filter, isFilterPinned } from '@kbn/es-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { SFC } from 'react';
|
||||
import { getFilterDisplayText } from '../filter_editor/lib/get_filter_display_text';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
interface Props {
|
||||
filter: Filter;
|
||||
filter: esFilters.Filter;
|
||||
displayName: string;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ export const FilterView: SFC<Props> = ({
|
|||
values: { innerText },
|
||||
});
|
||||
|
||||
if (isFilterPinned(filter)) {
|
||||
if (esFilters.isFilterPinned(filter)) {
|
||||
title = `${i18n.translate('data.filter.filterBar.pinnedFilterPrefix', {
|
||||
defaultMessage: 'Pinned',
|
||||
})} ${title}`;
|
||||
|
|
|
@ -19,12 +19,11 @@
|
|||
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { FilterStateStore } from '@kbn/es-query';
|
||||
import { FilterStateManager } from './filter_state_manager';
|
||||
|
||||
import { StubState } from './test_helpers/stub_state';
|
||||
import { getFilter } from './test_helpers/get_stub_filter';
|
||||
import { FilterManager } from '../../../../../../plugins/data/public';
|
||||
import { FilterManager, esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
import { coreMock } from '../../../../../../core/public/mocks';
|
||||
const setupMock = coreMock.createSetup();
|
||||
|
@ -59,7 +58,7 @@ describe('filter_state_manager', () => {
|
|||
});
|
||||
|
||||
test('should NOT watch state until both app and global state are defined', done => {
|
||||
const f1 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
globalStateStub.filters.push(f1);
|
||||
|
||||
setTimeout(() => {
|
||||
|
@ -72,8 +71,8 @@ describe('filter_state_manager', () => {
|
|||
appStateStub.save = sinon.stub();
|
||||
globalStateStub.save = sinon.stub();
|
||||
|
||||
const f1 = getFilter(FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f2 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f2 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
|
||||
filterManager.setFilters([f1, f2]);
|
||||
|
||||
|
@ -109,7 +108,7 @@ describe('filter_state_manager', () => {
|
|||
done();
|
||||
});
|
||||
|
||||
const f1 = getFilter(FilterStateStore.GLOBAL_STATE, true, true, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, true, true, 'age', 34);
|
||||
globalStateStub.filters.push(f1);
|
||||
});
|
||||
|
||||
|
@ -122,7 +121,7 @@ describe('filter_state_manager', () => {
|
|||
done();
|
||||
});
|
||||
|
||||
const f1 = getFilter(FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
appStateStub.filters.push(f1);
|
||||
});
|
||||
|
||||
|
@ -130,8 +129,8 @@ describe('filter_state_manager', () => {
|
|||
appStateStub.save = sinon.stub();
|
||||
globalStateStub.save = sinon.stub();
|
||||
|
||||
const f1 = getFilter(FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f2 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f2 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
|
||||
filterManager.setFilters([f1, f2]);
|
||||
|
||||
|
@ -143,8 +142,8 @@ describe('filter_state_manager', () => {
|
|||
appStateStub.save = sinon.stub();
|
||||
globalStateStub.save = sinon.stub();
|
||||
|
||||
const f1 = getFilter(FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f2 = getFilter(FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f2 = getFilter(esFilters.FilterStateStore.GLOBAL_STATE, false, false, 'age', 34);
|
||||
|
||||
filterManager.addFilters([f1, f2]);
|
||||
|
||||
|
@ -160,7 +159,7 @@ describe('filter_state_manager', () => {
|
|||
** And triggers *another* filter manager update.
|
||||
*/
|
||||
test('should NOT re-trigger filter manager', done => {
|
||||
const f1 = getFilter(FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
|
||||
filterManager.setFilters([f1]);
|
||||
const setFiltersSpy = sinon.spy(filterManager, 'setFilters');
|
||||
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { FilterStateStore } from '@kbn/es-query';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { State } from 'ui/state_management/state';
|
||||
import { FilterManager } from '../../../../../../plugins/data/public';
|
||||
import { FilterManager, esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
type GetAppStateFunc = () => State | undefined | null;
|
||||
|
||||
|
@ -73,8 +71,8 @@ export class FilterStateManager {
|
|||
|
||||
const newGlobalFilters = _.cloneDeep(globalFilters);
|
||||
const newAppFilters = _.cloneDeep(appFilters);
|
||||
FilterManager.setFiltersStore(newAppFilters, FilterStateStore.APP_STATE);
|
||||
FilterManager.setFiltersStore(newGlobalFilters, FilterStateStore.GLOBAL_STATE);
|
||||
FilterManager.setFiltersStore(newAppFilters, esFilters.FilterStateStore.APP_STATE);
|
||||
FilterManager.setFiltersStore(newGlobalFilters, esFilters.FilterStateStore.GLOBAL_STATE);
|
||||
|
||||
this.filterManager.setFilters(newGlobalFilters.concat(newAppFilters));
|
||||
}, 10);
|
||||
|
|
|
@ -17,15 +17,15 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter, FilterStateStore } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
export function getFilter(
|
||||
store: FilterStateStore,
|
||||
store: esFilters.FilterStateStore,
|
||||
disabled: boolean,
|
||||
negated: boolean,
|
||||
queryKey: string,
|
||||
queryValue: any
|
||||
): Filter {
|
||||
): esFilters.Filter {
|
||||
return {
|
||||
$state: {
|
||||
store,
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { State } from 'ui/state_management/state';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
export class StubState implements State {
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
save: sinon.SinonSpy<any[], any>;
|
||||
|
||||
constructor() {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { CoreStart } from 'src/core/public';
|
||||
import { DataPublicPluginStart } from 'src/plugins/data/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
|
@ -27,6 +26,7 @@ import { KibanaContextProvider } from '../../../../../../../../src/plugins/kiban
|
|||
import { TimefilterSetup } from '../../../timefilter';
|
||||
import { SearchBar } from '../../../';
|
||||
import { SearchBarOwnProps } from '.';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
interface StatefulSearchBarDeps {
|
||||
core: CoreStart;
|
||||
|
@ -40,7 +40,7 @@ export type StatetfulSearchBarProps = SearchBarOwnProps & {
|
|||
};
|
||||
|
||||
const defaultFiltersUpdated = (data: DataPublicPluginStart) => {
|
||||
return (filters: Filter[]) => {
|
||||
return (filters: esFilters.Filter[]) => {
|
||||
data.query.filterManager.setFilters(filters);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
import { compact } from 'lodash';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import classNames from 'classnames';
|
||||
import React, { Component } from 'react';
|
||||
|
@ -39,14 +38,15 @@ import {
|
|||
KibanaReactContextValue,
|
||||
} from '../../../../../../../plugins/kibana_react/public';
|
||||
import { IDataPluginServices } from '../../../types';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
interface SearchBarInjectedDeps {
|
||||
kibana: KibanaReactContextValue<IDataPluginServices>;
|
||||
intl: InjectedIntl;
|
||||
timeHistory: TimeHistoryContract;
|
||||
// Filter bar
|
||||
onFiltersUpdated?: (filters: Filter[]) => void;
|
||||
filters?: Filter[];
|
||||
onFiltersUpdated?: (filters: esFilters.Filter[]) => void;
|
||||
filters?: esFilters.Filter[];
|
||||
// Date picker
|
||||
dateRangeFrom?: string;
|
||||
dateRangeTo?: string;
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { RefreshInterval, TimeRange } from 'src/plugins/data/public';
|
||||
import { Query } from '../../query/query_bar';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export * from './components';
|
||||
|
||||
|
@ -36,6 +36,6 @@ export interface SavedQueryAttributes {
|
|||
title: string;
|
||||
description: string;
|
||||
query: Query;
|
||||
filters?: Filter[];
|
||||
filters?: esFilters.Filter[];
|
||||
timefilter?: SavedQueryTimeFilter;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import { SavedQueryAttributes } from '../index';
|
||||
import { createSavedQueryService } from './saved_query_service';
|
||||
import { FilterStateStore } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../../plugins/data/public';
|
||||
|
||||
const savedQueryAttributes: SavedQueryAttributes = {
|
||||
title: 'foo',
|
||||
|
@ -43,7 +43,7 @@ const savedQueryAttributesWithFilters: SavedQueryAttributes = {
|
|||
filters: [
|
||||
{
|
||||
query: { match_all: {} },
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
$state: { store: esFilters.FilterStateStore.APP_STATE },
|
||||
meta: {
|
||||
disabled: false,
|
||||
negate: false,
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { RangeFilter } from '@kbn/es-query';
|
||||
import { changeTimeFilter } from './change_time_filter';
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { timefilterServiceMock } from '../timefilter_service.mock';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
const timefilterMock = timefilterServiceMock.createSetupContract();
|
||||
const timefilter = timefilterMock.timefilter;
|
||||
|
@ -42,7 +42,7 @@ describe('changeTimeFilter()', () => {
|
|||
|
||||
test('should change the timefilter to match the range gt/lt', () => {
|
||||
const filter: any = { range: { '@timestamp': { gt, lt } } };
|
||||
changeTimeFilter(timefilter, filter as RangeFilter);
|
||||
changeTimeFilter(timefilter, filter as esFilters.RangeFilter);
|
||||
|
||||
const { to, from } = timefilter.getTime();
|
||||
|
||||
|
@ -52,7 +52,7 @@ describe('changeTimeFilter()', () => {
|
|||
|
||||
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);
|
||||
changeTimeFilter(timefilter, filter as esFilters.RangeFilter);
|
||||
|
||||
const { to, from } = timefilter.getTime();
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
|
||||
import moment from 'moment';
|
||||
import { keys } from 'lodash';
|
||||
import { RangeFilter } from '@kbn/es-query';
|
||||
import { TimefilterContract } from '../timefilter';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export function convertRangeFilterToTimeRange(filter: RangeFilter) {
|
||||
export function convertRangeFilterToTimeRange(filter: esFilters.RangeFilter) {
|
||||
const key = keys(filter.range)[0];
|
||||
const values = filter.range[key];
|
||||
|
||||
|
@ -32,6 +32,6 @@ export function convertRangeFilterToTimeRange(filter: RangeFilter) {
|
|||
};
|
||||
}
|
||||
|
||||
export function changeTimeFilter(timeFilter: TimefilterContract, filter: RangeFilter) {
|
||||
export function changeTimeFilter(timeFilter: TimefilterContract, filter: esFilters.RangeFilter) {
|
||||
timeFilter.setTime(convertRangeFilterToTimeRange(filter));
|
||||
}
|
||||
|
|
|
@ -17,15 +17,23 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter, buildRangeFilter, buildQueryFilter, buildPhraseFilter } from '@kbn/es-query';
|
||||
import { extractTimeFilter } from './extract_time_filter';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
describe('filter manager utilities', () => {
|
||||
describe('extractTimeFilter()', () => {
|
||||
test('should detect timeFilter', async () => {
|
||||
const filters: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'),
|
||||
buildRangeFilter({ name: 'time' }, { gt: 1388559600000, lt: 1388646000000 }, 'logstash-*'),
|
||||
const filters: esFilters.Filter[] = [
|
||||
esFilters.buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'logstash-*',
|
||||
''
|
||||
),
|
||||
esFilters.buildRangeFilter(
|
||||
{ name: 'time' },
|
||||
{ gt: 1388559600000, lt: 1388646000000 },
|
||||
'logstash-*'
|
||||
),
|
||||
];
|
||||
const result = await extractTimeFilter('time', filters);
|
||||
|
||||
|
@ -34,9 +42,13 @@ describe('filter manager utilities', () => {
|
|||
});
|
||||
|
||||
test("should not return timeFilter when name doesn't match", async () => {
|
||||
const filters: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'),
|
||||
buildRangeFilter({ name: '@timestamp' }, { from: 1, to: 2 }, 'logstash-*'),
|
||||
const filters: esFilters.Filter[] = [
|
||||
esFilters.buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'logstash-*',
|
||||
''
|
||||
),
|
||||
esFilters.buildRangeFilter({ name: '@timestamp' }, { from: 1, to: 2 }, 'logstash-*', ''),
|
||||
];
|
||||
const result = await extractTimeFilter('time', filters);
|
||||
|
||||
|
@ -45,9 +57,13 @@ describe('filter manager utilities', () => {
|
|||
});
|
||||
|
||||
test('should not return a non range filter, even when names match', async () => {
|
||||
const filters: Filter[] = [
|
||||
buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'logstash-*'),
|
||||
buildPhraseFilter({ name: 'time' }, 'banana', 'logstash-*'),
|
||||
const filters: esFilters.Filter[] = [
|
||||
esFilters.buildQueryFilter(
|
||||
{ _type: { match: { query: 'apache', type: 'phrase' } } },
|
||||
'logstash-*',
|
||||
''
|
||||
),
|
||||
esFilters.buildPhraseFilter({ name: 'time' }, 'banana', 'logstash-*'),
|
||||
];
|
||||
const result = await extractTimeFilter('time', filters);
|
||||
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
*/
|
||||
|
||||
import { keys, partition } from 'lodash';
|
||||
import { Filter, isRangeFilter, RangeFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export function extractTimeFilter(timeFieldName: string, filters: Filter[]) {
|
||||
const [timeRangeFilter, restOfFilters] = partition(filters, (obj: Filter) => {
|
||||
export function extractTimeFilter(timeFieldName: string, filters: esFilters.Filter[]) {
|
||||
const [timeRangeFilter, restOfFilters] = partition(filters, (obj: esFilters.Filter) => {
|
||||
let key;
|
||||
|
||||
if (isRangeFilter(obj)) {
|
||||
if (esFilters.isRangeFilter(obj)) {
|
||||
key = keys(obj.range)[0];
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,6 @@ export function extractTimeFilter(timeFieldName: string, filters: Filter[]) {
|
|||
|
||||
return {
|
||||
restOfFilters,
|
||||
timeRangeFilter: timeRangeFilter[0] as RangeFilter | undefined,
|
||||
timeRangeFilter: timeRangeFilter[0] as esFilters.RangeFilter | undefined,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { TimeRange } from '../../../../../../plugins/data/public';
|
||||
import { Adapters } from '../../../../../../plugins/inspector/public';
|
||||
import { Query } from '../../../../../../plugins/data/public';
|
||||
|
||||
export { TimeRange, Adapters, Filter, Query };
|
||||
export { TimeRange, Adapters, Query };
|
||||
export * from '../../../../../../plugins/expressions/public';
|
||||
|
|
|
@ -20,12 +20,8 @@
|
|||
import _ from 'lodash';
|
||||
import { FilterManager } from './filter_manager.js';
|
||||
import {
|
||||
buildPhraseFilter,
|
||||
buildPhrasesFilter,
|
||||
getPhraseFilterField,
|
||||
getPhraseFilterValue,
|
||||
isPhraseFilter,
|
||||
} from '@kbn/es-query';
|
||||
esFilters,
|
||||
} from '../../../../../../plugins/data/public';
|
||||
|
||||
export class PhraseFilterManager extends FilterManager {
|
||||
constructor(controlId, fieldName, indexPattern, queryFilter) {
|
||||
|
@ -43,12 +39,12 @@ export class PhraseFilterManager extends FilterManager {
|
|||
createFilter(phrases) {
|
||||
let newFilter;
|
||||
if (phrases.length === 1) {
|
||||
newFilter = buildPhraseFilter(
|
||||
newFilter = esFilters.buildPhraseFilter(
|
||||
this.indexPattern.fields.getByName(this.fieldName),
|
||||
phrases[0],
|
||||
this.indexPattern);
|
||||
} else {
|
||||
newFilter = buildPhrasesFilter(
|
||||
newFilter = esFilters.buildPhrasesFilter(
|
||||
this.indexPattern.fields.getByName(this.fieldName),
|
||||
phrases,
|
||||
this.indexPattern);
|
||||
|
@ -107,12 +103,12 @@ export class PhraseFilterManager extends FilterManager {
|
|||
}
|
||||
|
||||
// single phrase filter
|
||||
if (isPhraseFilter(kbnFilter)) {
|
||||
if (getPhraseFilterField(kbnFilter) !== this.fieldName) {
|
||||
if (esFilters.isPhraseFilter(kbnFilter)) {
|
||||
if (esFilters.getPhraseFilterField(kbnFilter) !== this.fieldName) {
|
||||
return;
|
||||
}
|
||||
|
||||
return getPhraseFilterValue(kbnFilter);
|
||||
return esFilters.getPhraseFilterValue(kbnFilter);
|
||||
}
|
||||
|
||||
// single phrase filter from bool filter
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import { FilterManager } from './filter_manager.js';
|
||||
import { buildRangeFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
// Convert slider value into ES range filter
|
||||
function toRange(sliderValue) {
|
||||
|
@ -55,7 +55,7 @@ export class RangeFilterManager extends FilterManager {
|
|||
* @return {object} range filter
|
||||
*/
|
||||
createFilter(value) {
|
||||
const newFilter = buildRangeFilter(
|
||||
const newFilter = esFilters.buildRangeFilter(
|
||||
this.indexPattern.fields.getByName(this.fieldName),
|
||||
toRange(value),
|
||||
this.indexPattern);
|
||||
|
|
|
@ -35,7 +35,6 @@ import {
|
|||
} from 'ui/state_management/app_state';
|
||||
|
||||
import { KbnUrl } from 'ui/url/kbn_url';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { IPrivate } from 'ui/private';
|
||||
|
@ -46,6 +45,7 @@ import { Subscription } from 'rxjs';
|
|||
import { ViewMode } from '../../../embeddable_api/public/np_ready/public';
|
||||
import { SavedObjectDashboard } from './saved_dashboard/saved_dashboard';
|
||||
import { DashboardAppState, SavedDashboardPanel, ConfirmModalFn } from './types';
|
||||
import { esFilters } from '../../../../../../src/plugins/data/public';
|
||||
|
||||
import { DashboardAppController } from './dashboard_app_controller';
|
||||
|
||||
|
@ -55,7 +55,7 @@ export interface DashboardAppScope extends ng.IScope {
|
|||
screenTitle: string;
|
||||
model: {
|
||||
query: Query;
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
timeRestore: boolean;
|
||||
title: string;
|
||||
description: string;
|
||||
|
@ -81,9 +81,9 @@ export interface DashboardAppScope extends ng.IScope {
|
|||
isPaused: boolean;
|
||||
refreshInterval: any;
|
||||
}) => void;
|
||||
onFiltersUpdated: (filters: Filter[]) => void;
|
||||
onFiltersUpdated: (filters: esFilters.Filter[]) => void;
|
||||
onCancelApplyFilters: () => void;
|
||||
onApplyFilters: (filters: Filter[]) => void;
|
||||
onApplyFilters: (filters: esFilters.Filter[]) => void;
|
||||
onQuerySaved: (savedQuery: SavedQuery) => void;
|
||||
onSavedQueryUpdated: (savedQuery: SavedQuery) => void;
|
||||
onClearSavedQuery: () => void;
|
||||
|
|
|
@ -48,7 +48,6 @@ import {
|
|||
} from 'ui/state_management/app_state';
|
||||
|
||||
import { KbnUrl } from 'ui/url/kbn_url';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { IPrivate } from 'ui/private';
|
||||
import { Query, SavedQuery } from 'src/legacy/core_plugins/data/public';
|
||||
|
@ -59,6 +58,7 @@ import { npStart } from 'ui/new_platform';
|
|||
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
|
||||
import { extractTimeFilter, changeTimeFilter } from '../../../data/public';
|
||||
import { start as data } from '../../../data/public/legacy';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
import {
|
||||
DashboardContainer,
|
||||
|
@ -514,7 +514,7 @@ export class DashboardAppController {
|
|||
}
|
||||
);
|
||||
|
||||
$scope.$watch('appState.$newFilters', (filters: Filter[] = []) => {
|
||||
$scope.$watch('appState.$newFilters', (filters: esFilters.Filter[] = []) => {
|
||||
if (filters.length === 1) {
|
||||
$scope.onApplyFilters(filters);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { stateMonitorFactory, StateMonitor } from 'ui/state_management/state_monitor_factory';
|
||||
import { Timefilter } from 'ui/timefilter';
|
||||
import { AppStateClass as TAppStateClass } from 'ui/state_management/app_state';
|
||||
|
@ -29,6 +28,7 @@ import { Moment } from 'moment';
|
|||
|
||||
import { DashboardContainer } from 'src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public';
|
||||
import { ViewMode } from '../../../../../../src/plugins/embeddable/public';
|
||||
import { esFilters } from '../../../../../../src/plugins/data/public';
|
||||
import { Query } from '../../../data/public';
|
||||
|
||||
import { getAppStateDefaults, migrateAppState } from './lib';
|
||||
|
@ -50,7 +50,7 @@ export class DashboardStateManager {
|
|||
public lastSavedDashboardFilters: {
|
||||
timeTo?: string | Moment;
|
||||
timeFrom?: string | Moment;
|
||||
filterBars: Filter[];
|
||||
filterBars: esFilters.Filter[];
|
||||
query: Query;
|
||||
};
|
||||
private stateDefaults: DashboardAppStateDefaults;
|
||||
|
@ -303,7 +303,7 @@ export class DashboardStateManager {
|
|||
return this.savedDashboard.timeRestore;
|
||||
}
|
||||
|
||||
public getLastSavedFilterBars(): Filter[] {
|
||||
public getLastSavedFilterBars(): esFilters.Filter[] {
|
||||
return this.lastSavedDashboardFilters.filterBars;
|
||||
}
|
||||
|
||||
|
@ -461,7 +461,7 @@ export class DashboardStateManager {
|
|||
* Applies the current filter state to the dashboard.
|
||||
* @param filter An array of filter bar filters.
|
||||
*/
|
||||
public applyFilters(query: Query, filters: Filter[]) {
|
||||
public applyFilters(query: Query, filters: esFilters.Filter[]) {
|
||||
this.appState.query = query;
|
||||
this.savedDashboard.searchSource.setField('query', query);
|
||||
this.savedDashboard.searchSource.setField('filter', filters);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import moment, { Moment } from 'moment';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
/**
|
||||
* @typedef {Object} QueryFilter
|
||||
|
@ -65,9 +65,9 @@ export class FilterUtils {
|
|||
* @param filters {Array.<Object>}
|
||||
* @returns {Array.<Object>}
|
||||
*/
|
||||
public static cleanFiltersForComparison(filters: Filter[]) {
|
||||
public static cleanFiltersForComparison(filters: esFilters.Filter[]) {
|
||||
return _.map(filters, filter => {
|
||||
const f: Partial<Filter> = _.omit(filter, ['$$hashKey', '$state']);
|
||||
const f: Partial<esFilters.Filter> = _.omit(filter, ['$$hashKey', '$state']);
|
||||
if (f.meta) {
|
||||
// f.meta.value is the value displayed in the filter bar.
|
||||
// It may also be loaded differently and shouldn't be used in this comparison.
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
|
||||
import { moveFiltersToQuery, Pre600FilterQuery } from './move_filters_to_query';
|
||||
import { Filter, FilterStateStore } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
const filter: Filter = {
|
||||
const filter: esFilters.Filter = {
|
||||
meta: { disabled: false, negate: false, alias: '' },
|
||||
query: {},
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
$state: { store: esFilters.FilterStateStore.APP_STATE },
|
||||
};
|
||||
|
||||
const queryFilter: Pre600FilterQuery = {
|
||||
|
@ -38,7 +38,7 @@ test('Migrates an old filter query into the query field', () => {
|
|||
expect(newSearchSource).toEqual({
|
||||
filter: [
|
||||
{
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
$state: { store: esFilters.FilterStateStore.APP_STATE },
|
||||
meta: {
|
||||
alias: '',
|
||||
disabled: false,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export interface Pre600FilterQuery {
|
||||
// pre 6.0.0 global query:queryString:options were stored per dashboard and would
|
||||
|
@ -30,18 +30,18 @@ export interface Pre600FilterQuery {
|
|||
export interface SearchSourcePre600 {
|
||||
// I encountered at least one export from 7.0.0-alpha that was missing the filter property in here.
|
||||
// The maps data in esarchives actually has it, but I don't know how/when they created it.
|
||||
filter?: Array<Filter | Pre600FilterQuery>;
|
||||
filter?: Array<esFilters.Filter | Pre600FilterQuery>;
|
||||
}
|
||||
|
||||
export interface SearchSource730 {
|
||||
filter: Filter[];
|
||||
filter: esFilters.Filter[];
|
||||
query: Query;
|
||||
highlightAll?: boolean;
|
||||
version?: boolean;
|
||||
}
|
||||
|
||||
function isQueryFilter(filter: Filter | { query: unknown }): filter is Pre600FilterQuery {
|
||||
return filter.query && !(filter as Filter).meta;
|
||||
function isQueryFilter(filter: esFilters.Filter | { query: unknown }): filter is Pre600FilterQuery {
|
||||
return filter.query && !(filter as esFilters.Filter).meta;
|
||||
}
|
||||
|
||||
export function moveFiltersToQuery(
|
||||
|
|
|
@ -19,10 +19,9 @@
|
|||
|
||||
import { SearchSource } from 'ui/courier';
|
||||
import { SavedObject } from 'ui/saved_objects/saved_object';
|
||||
import moment from 'moment';
|
||||
import { RefreshInterval } from 'src/plugins/data/public';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export interface SavedObjectDashboard extends SavedObject {
|
||||
id?: string;
|
||||
|
@ -41,5 +40,5 @@ export interface SavedObjectDashboard extends SavedObject {
|
|||
destroy: () => void;
|
||||
refreshInterval?: RefreshInterval;
|
||||
getQuery(): Query;
|
||||
getFilters(): Filter[];
|
||||
getFilters(): esFilters.Filter[];
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
import { AppState } from 'ui/state_management/app_state';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { AppState as TAppState } from 'ui/state_management/app_state';
|
||||
import { ViewMode } from 'src/plugins/embeddable/public';
|
||||
|
@ -30,6 +29,7 @@ import {
|
|||
RawSavedDashboardPanel640To720,
|
||||
RawSavedDashboardPanel730ToLatest,
|
||||
} from './migrations/types';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
export type NavAction = (anchorElement?: any) => void;
|
||||
|
||||
|
@ -110,7 +110,7 @@ export interface DashboardAppStateParameters {
|
|||
useMargins: boolean;
|
||||
};
|
||||
query: Query | string;
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
viewMode: ViewMode;
|
||||
savedQuery?: string;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { IndexPatterns, IndexPattern, getServices } from '../../../kibana_services';
|
||||
import { reverseSortDir, SortDirection } from './utils/sorting';
|
||||
import { extractNanos, convertIsoToMillis } from './utils/date_conversion';
|
||||
|
@ -25,6 +24,7 @@ import { fetchHitsInInterval } from './utils/fetch_hits_in_interval';
|
|||
import { generateIntervals } from './utils/generate_intervals';
|
||||
import { getEsQuerySearchAfter } from './utils/get_es_query_search_after';
|
||||
import { getEsQuerySort } from './utils/get_es_query_sort';
|
||||
import { esFilters } from '../../../../../../../../plugins/data/public';
|
||||
|
||||
export type SurrDocType = 'successors' | 'predecessors';
|
||||
export interface EsHitRecord {
|
||||
|
@ -67,7 +67,7 @@ function fetchContextProvider(indexPatterns: IndexPatterns) {
|
|||
tieBreakerField: string,
|
||||
sortDir: SortDirection,
|
||||
size: number,
|
||||
filters: Filter[]
|
||||
filters: esFilters.Filter[]
|
||||
) {
|
||||
if (typeof anchor !== 'object' || anchor === null) {
|
||||
return [];
|
||||
|
@ -112,7 +112,7 @@ function fetchContextProvider(indexPatterns: IndexPatterns) {
|
|||
return documents;
|
||||
}
|
||||
|
||||
async function createSearchSource(indexPattern: IndexPattern, filters: Filter[]) {
|
||||
async function createSearchSource(indexPattern: IndexPattern, filters: esFilters.Filter[]) {
|
||||
return new SearchSource()
|
||||
.setParent(false)
|
||||
.setField('index', indexPattern)
|
||||
|
|
|
@ -26,10 +26,10 @@ import { noWhiteSpace } from '../../../../../common/utils/no_white_space';
|
|||
import openRowHtml from './table_row/open.html';
|
||||
import detailsHtml from './table_row/details.html';
|
||||
import { getServices } from '../../../kibana_services';
|
||||
import { disableFilter } from '@kbn/es-query';
|
||||
import { dispatchRenderComplete } from '../../../../../../../../plugins/kibana_utils/public';
|
||||
import cellTemplateHtml from '../components/table_row/cell.html';
|
||||
import truncateByHeightTemplateHtml from '../components/table_row/truncate_by_height.html';
|
||||
import { esFilters } from '../../../../../../../../plugins/data/public';
|
||||
|
||||
const module = getServices().uiModules.get('app/discover');
|
||||
|
||||
|
@ -117,7 +117,7 @@ module.directive('kbnTableRow', function ($compile, $httpParamSerializer, kbnUrl
|
|||
const hash = $httpParamSerializer({
|
||||
_a: rison.encode({
|
||||
columns: $scope.columns,
|
||||
filters: ($scope.filters || []).map(disableFilter),
|
||||
filters: ($scope.filters || []).map(esFilters.disableFilter),
|
||||
}),
|
||||
});
|
||||
return `${path}?${hash}`;
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
import _ from 'lodash';
|
||||
import * as Rx from 'rxjs';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Filter, FilterStateStore } from '@kbn/es-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { TExecuteTriggerActions } from 'src/plugins/ui_actions/public';
|
||||
import { TimeRange, onlyDisabledFiltersChanged } from '../../../../../../plugins/data/public';
|
||||
import { setup as data } from '../../../../data/public/legacy';
|
||||
import { Query, getTime } from '../../../../data/public';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
import {
|
||||
APPLY_FILTER_TRIGGER,
|
||||
Container,
|
||||
|
@ -75,7 +75,7 @@ export interface FilterManager {
|
|||
values: string | string[],
|
||||
operation: string,
|
||||
index: number
|
||||
) => Filter[];
|
||||
) => esFilters.Filter[];
|
||||
}
|
||||
|
||||
interface SearchEmbeddableConfig {
|
||||
|
@ -105,7 +105,7 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
private abortController?: AbortController;
|
||||
|
||||
private prevTimeRange?: TimeRange;
|
||||
private prevFilters?: Filter[];
|
||||
private prevFilters?: esFilters.Filter[];
|
||||
private prevQuery?: Query;
|
||||
|
||||
constructor(
|
||||
|
@ -248,7 +248,7 @@ export class SearchEmbeddable extends Embeddable<SearchInput, SearchOutput>
|
|||
let filters = this.filterGen.generate(field, value, operator, indexPattern.id);
|
||||
filters = filters.map(filter => ({
|
||||
...filter,
|
||||
$state: { store: FilterStateStore.APP_STATE },
|
||||
$state: { store: esFilters.FilterStateStore.APP_STATE },
|
||||
}));
|
||||
|
||||
await this.executeTriggerActions(APPLY_FILTER_TRIGGER, {
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { EmbeddableInput, EmbeddableOutput, IEmbeddable } from 'src/plugins/embeddable/public';
|
||||
import { StaticIndexPattern } from '../kibana_services';
|
||||
import { SavedSearch } from '../types';
|
||||
import { SortOrder } from '../angular/doc_table/components/table_header/helpers';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export interface SearchInput extends EmbeddableInput {
|
||||
timeRange: TimeRange;
|
||||
query?: Query;
|
||||
filters?: Filter[];
|
||||
filters?: esFilters.Filter[];
|
||||
hidePanelTitles?: boolean;
|
||||
columns?: string[];
|
||||
sort?: SortOrder[];
|
||||
|
|
|
@ -21,8 +21,11 @@ import _ from 'lodash';
|
|||
import { EmbeddedVisualizeHandler } from 'ui/visualize/loader/embedded_visualize_handler';
|
||||
import { Subscription } from 'rxjs';
|
||||
import * as Rx from 'rxjs';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { TimeRange, onlyDisabledFiltersChanged } from '../../../../../../plugins/data/public';
|
||||
import {
|
||||
TimeRange,
|
||||
onlyDisabledFiltersChanged,
|
||||
esFilters,
|
||||
} from '../../../../../../plugins/data/public';
|
||||
import { Query } from '../../../../data/public';
|
||||
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
|
||||
|
||||
|
@ -55,7 +58,7 @@ export interface VisualizeEmbeddableConfiguration {
|
|||
export interface VisualizeInput extends EmbeddableInput {
|
||||
timeRange?: TimeRange;
|
||||
query?: Query;
|
||||
filters?: Filter[];
|
||||
filters?: esFilters.Filter[];
|
||||
vis?: {
|
||||
colors?: { [key: string]: string };
|
||||
};
|
||||
|
@ -79,7 +82,7 @@ export class VisualizeEmbeddable extends Embeddable<VisualizeInput, VisualizeOut
|
|||
private timeRange?: TimeRange;
|
||||
private query?: Query;
|
||||
private title?: string;
|
||||
private filters?: Filter[];
|
||||
private filters?: esFilters.Filter[];
|
||||
private visCustomizations: VisualizeInput['vis'];
|
||||
private subscription: Subscription;
|
||||
public readonly type = VISUALIZE_EMBEDDABLE_TYPE;
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import { buildEsQuery, getEsQueryConfig, Filter } from '@kbn/es-query';
|
||||
import { buildEsQuery, getEsQueryConfig } from '@kbn/es-query';
|
||||
// @ts-ignore
|
||||
import { timezoneProvider } from 'ui/vis/lib/timezone';
|
||||
import { KIBANA_CONTEXT_NAME } from 'src/plugins/expressions/public';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { TimeRange, esFilters } from 'src/plugins/data/public';
|
||||
import { VisParams } from 'ui/vis';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { TimelionVisualizationDependencies } from '../plugin';
|
||||
|
@ -60,7 +60,7 @@ export function getTimelionRequestHandler(dependencies: TimelionVisualizationDep
|
|||
visParams,
|
||||
}: {
|
||||
timeRange: TimeRange;
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
query: Query;
|
||||
visParams: VisParams;
|
||||
forceFetch?: boolean;
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Filter } from '@kbn/es-query';
|
||||
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
|
||||
// @ts-ignore
|
||||
import { buildEsQuery, getEsQueryConfig } from '@kbn/es-query';
|
||||
|
||||
import { esFilters } from '../../../../plugins/data/public';
|
||||
|
||||
// @ts-ignore
|
||||
import { VegaParser } from './data_model/vega_parser';
|
||||
// @ts-ignore
|
||||
|
@ -35,7 +36,7 @@ import { VisParams } from './vega_fn';
|
|||
|
||||
interface VegaRequestHandlerParams {
|
||||
query: Query;
|
||||
filters: Filter;
|
||||
filters: esFilters.Filter;
|
||||
timeRange: TimeRange;
|
||||
visParams: VisParams;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import { Utils } from '../data_model/utils';
|
|||
import { VISUALIZATION_COLORS } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { TooltipHandler } from './vega_tooltip';
|
||||
import { buildQueryFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
import { getEnableExternalUrls } from '../helpers/vega_config_provider';
|
||||
|
||||
|
@ -263,7 +263,7 @@ export class VegaBaseView {
|
|||
*/
|
||||
async addFilterHandler(query, index) {
|
||||
const indexId = await this._findIndex(index);
|
||||
const filter = buildQueryFilter(query, indexId);
|
||||
const filter = esFilters.buildQueryFilter(query, indexId);
|
||||
this._queryfilter.addFilters(filter);
|
||||
}
|
||||
|
||||
|
@ -274,7 +274,7 @@ export class VegaBaseView {
|
|||
async removeFilterHandler(query, index) {
|
||||
const $injector = await chrome.dangerouslyGetActiveInjector();
|
||||
const indexId = await this._findIndex(index);
|
||||
const filter = buildQueryFilter(query, indexId);
|
||||
const filter = esFilters.buildQueryFilter(query, indexId);
|
||||
|
||||
// This is a workaround for the https://github.com/elastic/kibana/issues/18863
|
||||
// Once fixed, replace with a direct call (no await is needed because its not async)
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { buildExistsFilter, buildPhrasesFilter, buildQueryFromFilters } from '@kbn/es-query';
|
||||
import { buildQueryFromFilters } from '@kbn/es-query';
|
||||
import { AggGroupNames } from '../../vis/editors/default/agg_groups';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
/**
|
||||
* walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId
|
||||
|
@ -180,7 +181,7 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
|||
agg.buckets.some(bucket => bucket.key === '__missing__')
|
||||
) {
|
||||
filters.push(
|
||||
buildExistsFilter(
|
||||
esFilters.buildExistsFilter(
|
||||
aggWithOtherBucket.params.field,
|
||||
aggWithOtherBucket.params.field.indexPattern
|
||||
)
|
||||
|
@ -232,7 +233,7 @@ export const mergeOtherBucketAggResponse = (
|
|||
);
|
||||
const requestFilterTerms = getOtherAggTerms(requestAgg, key, otherAgg);
|
||||
|
||||
const phraseFilter = buildPhrasesFilter(
|
||||
const phraseFilter = esFilters.buildPhrasesFilter(
|
||||
otherAgg.params.field,
|
||||
requestFilterTerms,
|
||||
otherAgg.params.field.indexPattern
|
||||
|
@ -243,7 +244,7 @@ export const mergeOtherBucketAggResponse = (
|
|||
|
||||
if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) {
|
||||
bucket.filters.push(
|
||||
buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern)
|
||||
esFilters.buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern)
|
||||
);
|
||||
}
|
||||
aggResultBuckets.push(bucket);
|
||||
|
|
|
@ -18,19 +18,19 @@
|
|||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { RangeFilter } from '@kbn/es-query';
|
||||
import { createFilterDateHistogram } from './date_histogram';
|
||||
import { intervalOptions } from '../_interval_options';
|
||||
import { AggConfigs } from '../../agg_configs';
|
||||
import { IBucketDateHistogramAggConfig } from '../date_histogram';
|
||||
import { BUCKET_TYPES } from '../bucket_agg_types';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
describe('AggConfig Filters', () => {
|
||||
describe('date_histogram', () => {
|
||||
let agg: IBucketDateHistogramAggConfig;
|
||||
let filter: RangeFilter;
|
||||
let filter: esFilters.RangeFilter;
|
||||
let bucketStart: any;
|
||||
let field: any;
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { buildRangeFilter } from '@kbn/es-query';
|
||||
import { IBucketDateHistogramAggConfig } from '../date_histogram';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterDateHistogram = (
|
||||
agg: IBucketDateHistogramAggConfig,
|
||||
|
@ -28,7 +28,7 @@ export const createFilterDateHistogram = (
|
|||
const start = moment(key);
|
||||
const interval = agg.buckets.getInterval();
|
||||
|
||||
return buildRangeFilter(
|
||||
return esFilters.buildRangeFilter(
|
||||
agg.params.field,
|
||||
{
|
||||
gte: start.toISOString(),
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||
import moment from 'moment';
|
||||
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
import { DateRangeKey } from '../date_range';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => {
|
||||
const filter: RangeFilterParams = {};
|
||||
const filter: esFilters.RangeFilterParams = {};
|
||||
if (from) filter.gte = moment(from).toISOString();
|
||||
if (to) filter.lt = moment(to).toISOString();
|
||||
if (to && from) filter.format = 'strict_date_optional_time';
|
||||
|
||||
return buildRangeFilter(agg.params.field, filter, agg.getIndexPattern());
|
||||
return esFilters.buildRangeFilter(agg.params.field, filter, agg.getIndexPattern());
|
||||
};
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { buildQueryFilter } from '@kbn/es-query';
|
||||
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => {
|
||||
// have the aggConfig write agg dsl params
|
||||
|
@ -28,6 +28,6 @@ export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) =>
|
|||
const indexPattern = aggConfig.getIndexPattern();
|
||||
|
||||
if (filter && indexPattern && indexPattern.id) {
|
||||
return buildQueryFilter(filter.query, indexPattern.id, key);
|
||||
return esFilters.buildQueryFilter(filter.query, indexPattern.id, key);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => {
|
||||
const value = parseInt(key, 10);
|
||||
const params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval };
|
||||
const params: esFilters.RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval };
|
||||
|
||||
return buildRangeFilter(
|
||||
return esFilters.buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
params,
|
||||
aggConfig.getIndexPattern(),
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||
import { CidrMask } from '../../../utils/cidr_mask';
|
||||
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
import { IpRangeKey } from '../ip_range';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => {
|
||||
let range: RangeFilterParams;
|
||||
let range: esFilters.RangeFilterParams;
|
||||
|
||||
if (key.type === 'mask') {
|
||||
range = new CidrMask(key.mask).getRange();
|
||||
|
@ -34,7 +34,7 @@ export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey
|
|||
};
|
||||
}
|
||||
|
||||
return buildRangeFilter(
|
||||
return esFilters.buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
{ gte: range.from, lte: range.to },
|
||||
aggConfig.getIndexPattern()
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { buildRangeFilter } from '@kbn/es-query';
|
||||
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => {
|
||||
return buildRangeFilter(
|
||||
return esFilters.buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
params,
|
||||
aggConfig.getIndexPattern(),
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ExistsFilter, Filter } from '@kbn/es-query';
|
||||
|
||||
import { createFilterTerms } from './terms';
|
||||
import { AggConfigs } from '../../agg_configs';
|
||||
import { BUCKET_TYPES } from '../bucket_agg_types';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
|
@ -48,7 +49,7 @@ describe('AggConfig Filters', () => {
|
|||
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
|
||||
]);
|
||||
|
||||
const filter = createFilterTerms(aggConfigs.aggs[0], 'apache', {}) as Filter;
|
||||
const filter = createFilterTerms(aggConfigs.aggs[0], 'apache', {}) as esFilters.Filter;
|
||||
|
||||
expect(filter).toHaveProperty('query');
|
||||
expect(filter.query).toHaveProperty('match_phrase');
|
||||
|
@ -63,14 +64,14 @@ describe('AggConfig Filters', () => {
|
|||
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
|
||||
]);
|
||||
|
||||
const filterFalse = createFilterTerms(aggConfigs.aggs[0], '', {}) as Filter;
|
||||
const filterFalse = createFilterTerms(aggConfigs.aggs[0], '', {}) as esFilters.Filter;
|
||||
|
||||
expect(filterFalse).toHaveProperty('query');
|
||||
expect(filterFalse.query).toHaveProperty('match_phrase');
|
||||
expect(filterFalse.query.match_phrase).toHaveProperty('field');
|
||||
expect(filterFalse.query.match_phrase.field).toBeFalsy();
|
||||
|
||||
const filterTrue = createFilterTerms(aggConfigs.aggs[0], '1', {}) as Filter;
|
||||
const filterTrue = createFilterTerms(aggConfigs.aggs[0], '1', {}) as esFilters.Filter;
|
||||
|
||||
expect(filterTrue).toHaveProperty('query');
|
||||
expect(filterTrue.query).toHaveProperty('match_phrase');
|
||||
|
@ -82,7 +83,11 @@ describe('AggConfig Filters', () => {
|
|||
const aggConfigs = getAggConfigs([
|
||||
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
|
||||
]);
|
||||
const filter = createFilterTerms(aggConfigs.aggs[0], '__missing__', {}) as ExistsFilter;
|
||||
const filter = createFilterTerms(
|
||||
aggConfigs.aggs[0],
|
||||
'__missing__',
|
||||
{}
|
||||
) as esFilters.ExistsFilter;
|
||||
|
||||
expect(filter).toHaveProperty('exists');
|
||||
expect(filter.exists).toHaveProperty('field', 'field');
|
||||
|
@ -98,7 +103,7 @@ describe('AggConfig Filters', () => {
|
|||
|
||||
const [filter] = createFilterTerms(aggConfigs.aggs[0], '__other__', {
|
||||
terms: ['apache'],
|
||||
}) as Filter[];
|
||||
}) as esFilters.Filter[];
|
||||
|
||||
expect(filter).toHaveProperty('query');
|
||||
expect(filter.query).toHaveProperty('bool');
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter, buildPhraseFilter, buildPhrasesFilter, buildExistsFilter } from '@kbn/es-query';
|
||||
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => {
|
||||
const field = aggConfig.params.field;
|
||||
|
@ -27,20 +27,20 @@ export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, para
|
|||
if (key === '__other__') {
|
||||
const terms = params.terms;
|
||||
|
||||
const phraseFilter = buildPhrasesFilter(field, terms, indexPattern);
|
||||
const phraseFilter = esFilters.buildPhrasesFilter(field, terms, indexPattern);
|
||||
phraseFilter.meta.negate = true;
|
||||
|
||||
const filters: Filter[] = [phraseFilter];
|
||||
const filters: esFilters.Filter[] = [phraseFilter];
|
||||
|
||||
if (terms.some((term: string) => term === '__missing__')) {
|
||||
filters.push(buildExistsFilter(field, indexPattern));
|
||||
filters.push(esFilters.buildExistsFilter(field, indexPattern));
|
||||
}
|
||||
|
||||
return filters;
|
||||
} else if (key === '__missing__') {
|
||||
const existsFilter = buildExistsFilter(field, indexPattern);
|
||||
const existsFilter = esFilters.buildExistsFilter(field, indexPattern);
|
||||
existsFilter.meta.negate = true;
|
||||
return existsFilter;
|
||||
}
|
||||
return buildPhraseFilter(field, key, indexPattern);
|
||||
return esFilters.buildPhraseFilter(field, key, indexPattern);
|
||||
};
|
||||
|
|
|
@ -32,7 +32,6 @@ import { ScaleMetricsParamEditor } from '../../vis/editors/default/controls/scal
|
|||
import { dateHistogramInterval } from '../../../../core_plugins/data/public';
|
||||
import { writeParams } from '../agg_params';
|
||||
import { AggConfigs } from '../agg_configs';
|
||||
import { AggConfig } from '../agg_config';
|
||||
import { isMetricAggType } from '../metrics/metric_agg_type';
|
||||
|
||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
|
@ -189,7 +188,7 @@ export const dateHistogramBucketAgg = new BucketAggType<IBucketDateHistogramAggC
|
|||
const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1;
|
||||
if (scaleMetrics && aggs) {
|
||||
const metrics = aggs.aggs.filter(a => isMetricAggType(a.type));
|
||||
const all = _.every(metrics, (a: AggConfig) => {
|
||||
const all = _.every(metrics, (a: IBucketAggConfig) => {
|
||||
const { type } = a;
|
||||
|
||||
if (isMetricAggType(type)) {
|
||||
|
|
|
@ -21,9 +21,8 @@ import moment from 'moment-timezone';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||
import { BucketAggType } from './_bucket_agg_type';
|
||||
import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
|
||||
import { createFilterDateRange } from './create_filter/date_range';
|
||||
import { AggConfig } from '../agg_config';
|
||||
import { FieldFormat } from '../../../../../plugins/data/common/field_formats';
|
||||
import { DateRangesParamEditor } from '../../vis/editors/default/controls/date_ranges';
|
||||
|
||||
|
@ -64,7 +63,7 @@ export const dateRangeBucketAgg = new BucketAggType({
|
|||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: KBN_FIELD_TYPES.DATE,
|
||||
default(agg: AggConfig) {
|
||||
default(agg: IBucketAggConfig) {
|
||||
return agg.getIndexPattern().timeFieldName;
|
||||
},
|
||||
},
|
||||
|
@ -83,7 +82,7 @@ export const dateRangeBucketAgg = new BucketAggType({
|
|||
default: undefined,
|
||||
// Implimentation method is the same as that of date_histogram
|
||||
serialize: () => undefined,
|
||||
write: (agg: AggConfig, output: Record<string, any>) => {
|
||||
write: (agg: IBucketAggConfig, output: Record<string, any>) => {
|
||||
const field = agg.getParam('field');
|
||||
let tz = agg.getParam('time_zone');
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import { IsFilteredByCollarParamEditor } from '../../vis/editors/default/control
|
|||
import { PrecisionParamEditor } from '../../vis/editors/default/controls/precision';
|
||||
import { geohashColumns } from '../../utils/decode_geo_hash';
|
||||
import { AggGroupNames } from '../../vis/editors/default/agg_groups';
|
||||
import { AggConfig } from '../agg_config';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
|
||||
// @ts-ignore
|
||||
|
@ -143,7 +142,7 @@ export const geoHashBucketAgg = new BucketAggType<IBucketGeoHashGridAggConfig>({
|
|||
},
|
||||
],
|
||||
getRequestAggs(agg) {
|
||||
const aggs: AggConfig[] = [];
|
||||
const aggs: IBucketAggConfig[] = [];
|
||||
const params = agg.params;
|
||||
|
||||
if (params.isFilteredByCollar && agg.getField()) {
|
||||
|
|
|
@ -28,7 +28,6 @@ import { NumberIntervalParamEditor } from '../../vis/editors/default/controls/nu
|
|||
import { MinDocCountParamEditor } from '../../vis/editors/default/controls/min_doc_count';
|
||||
import { HasExtendedBoundsParamEditor } from '../../vis/editors/default/controls/has_extended_bounds';
|
||||
import { ExtendedBoundsParamEditor } from '../../vis/editors/default/controls/extended_bounds';
|
||||
import { AggConfig } from '../agg_config';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||
|
||||
|
@ -177,7 +176,7 @@ export const histogramBucketAgg = new BucketAggType<IBucketHistogramAggConfig>({
|
|||
name: 'min_doc_count',
|
||||
default: false,
|
||||
editorComponent: MinDocCountParamEditor,
|
||||
write(aggConfig: AggConfig, output: Record<string, any>) {
|
||||
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||
if (aggConfig.params.min_doc_count) {
|
||||
output.params.min_doc_count = 0;
|
||||
} else {
|
||||
|
@ -198,14 +197,14 @@ export const histogramBucketAgg = new BucketAggType<IBucketHistogramAggConfig>({
|
|||
max: '',
|
||||
},
|
||||
editorComponent: ExtendedBoundsParamEditor,
|
||||
write(aggConfig: AggConfig, output: Record<string, any>) {
|
||||
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||
const { min, max } = aggConfig.params.extended_bounds;
|
||||
|
||||
if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) {
|
||||
output.params.extended_bounds = { min, max };
|
||||
}
|
||||
},
|
||||
shouldShow: (aggConfig: AggConfig) => aggConfig.params.has_extended_bounds,
|
||||
shouldShow: (aggConfig: IBucketAggConfig) => aggConfig.params.has_extended_bounds,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
import { isString, isObject } from 'lodash';
|
||||
import { AggConfig } from 'ui/agg_types';
|
||||
import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type';
|
||||
|
||||
export const isType = (type: string) => {
|
||||
|
@ -32,12 +31,16 @@ export const isType = (type: string) => {
|
|||
export const isStringType = isType('string');
|
||||
|
||||
export const migrateIncludeExcludeFormat = {
|
||||
serialize(this: BucketAggParam, value: any, agg: AggConfig) {
|
||||
serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) {
|
||||
if (this.shouldShow && !this.shouldShow(agg)) return;
|
||||
if (!value || isString(value)) return value;
|
||||
else return value.pattern;
|
||||
},
|
||||
write(this: BucketAggType<IBucketAggConfig>, aggConfig: AggConfig, output: Record<string, any>) {
|
||||
write(
|
||||
this: BucketAggType<IBucketAggConfig>,
|
||||
aggConfig: IBucketAggConfig,
|
||||
output: Record<string, any>
|
||||
) {
|
||||
const value = aggConfig.getParam(this.name);
|
||||
|
||||
if (isObject(value)) {
|
||||
|
|
|
@ -71,13 +71,13 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import { buildEsQuery, getEsQueryConfig } from '@kbn/es-query';
|
||||
import { getEsQueryConfig, buildEsQuery } from '@kbn/es-query';
|
||||
|
||||
import { normalizeSortRequest } from './_normalize_sort_request';
|
||||
|
||||
import { fetchSoon } from '../fetch';
|
||||
import { fieldWildcardFilter } from '../../field_wildcard';
|
||||
import { getHighlightRequest } from '../../../../../plugins/data/common/field_formats';
|
||||
import { getHighlightRequest } from '../../../../../plugins/data/public';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import chrome from '../../chrome';
|
||||
import { RequestFailure } from '../fetch/errors';
|
||||
|
|
|
@ -24,8 +24,8 @@ import expect from '@kbn/expect';
|
|||
import ngMock from 'ng_mock';
|
||||
import { getFilterGenerator } from '..';
|
||||
import { FilterBarQueryFilterProvider } from '../../filter_manager/query_filter';
|
||||
import { uniqFilters } from '../../../../../plugins/data/public';
|
||||
import { getPhraseScript } from '@kbn/es-query';
|
||||
import { uniqFilters, esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
let queryFilter;
|
||||
let filterGen;
|
||||
let appState;
|
||||
|
@ -137,14 +137,14 @@ describe('Filter Manager', function () {
|
|||
filterGen.add(scriptedField, 1, '+', 'myIndex');
|
||||
checkAddFilters(1, [{
|
||||
meta: { index: 'myIndex', negate: false, field: 'scriptedField' },
|
||||
script: getPhraseScript(scriptedField, 1)
|
||||
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: getPhraseScript(scriptedField, 1)
|
||||
script: esFilters.getPhraseScript(scriptedField, 1)
|
||||
}], 5);
|
||||
expect(appState.filters).to.have.length(3);
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getPhraseFilterField, getPhraseFilterValue, getPhraseScript, isPhraseFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../plugins/data/public';
|
||||
|
||||
// Adds a filter to a passed state
|
||||
export function getFilterGenerator(queryFilter) {
|
||||
|
@ -42,8 +42,8 @@ export function getFilterGenerator(queryFilter) {
|
|||
return filter.exists.field === value;
|
||||
}
|
||||
|
||||
if (isPhraseFilter(filter)) {
|
||||
return getPhraseFilterField(filter) === fieldName && getPhraseFilterValue(filter) === value;
|
||||
if (esFilters.isPhraseFilter(filter)) {
|
||||
return esFilters.getPhraseFilterField(filter) === fieldName && esFilters.getPhraseFilterValue(filter) === value;
|
||||
}
|
||||
|
||||
if (filter.script) {
|
||||
|
@ -73,7 +73,7 @@ export function getFilterGenerator(queryFilter) {
|
|||
if (field.scripted) {
|
||||
filter = {
|
||||
meta: { negate, index, field: fieldName },
|
||||
script: getPhraseScript(field, value)
|
||||
script: esFilters.getPhraseScript(field, value)
|
||||
};
|
||||
} else {
|
||||
filter = { meta: { negate, index }, query: { match_phrase: {} } };
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { buildRangeFilter } from '@kbn/es-query';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
export function onBrushEvent(event) {
|
||||
const isNumber = event.data.ordered;
|
||||
|
@ -56,7 +56,7 @@ export function onBrushEvent(event) {
|
|||
};
|
||||
}
|
||||
|
||||
const newFilter = buildRangeFilter(
|
||||
const newFilter = esFilters.buildRangeFilter(
|
||||
field,
|
||||
range,
|
||||
indexPattern,
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
import _ from 'lodash';
|
||||
import { pushFilterBarFilters } from '../push_filters';
|
||||
import { onBrushEvent } from './brush_event';
|
||||
import { uniqFilters } from '../../../../../plugins/data/public';
|
||||
import { toggleFilterNegated } from '@kbn/es-query';
|
||||
import { uniqFilters, esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
/**
|
||||
* For terms aggregations on `__other__` buckets, this assembles a list of applicable filter
|
||||
* terms based on a specific cell in the tabified data.
|
||||
|
@ -94,7 +94,7 @@ const createFiltersFromEvent = (event) => {
|
|||
if (filter) {
|
||||
filter.forEach(f => {
|
||||
if (event.negate) {
|
||||
f = toggleFilterNegated(f);
|
||||
f = esFilters.toggleFilterNegated(f);
|
||||
}
|
||||
filters.push(f);
|
||||
});
|
||||
|
|
|
@ -22,7 +22,6 @@ import { debounce, forEach, get, isEqual } from 'lodash';
|
|||
import * as Rx from 'rxjs';
|
||||
import { share } from 'rxjs/operators';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
// @ts-ignore untyped dependency
|
||||
import { AggConfigs } from 'ui/agg_types/agg_configs';
|
||||
|
@ -44,6 +43,7 @@ import { VisFiltersProvider } from '../../vis/vis_filters';
|
|||
import { PipelineDataLoader } from './pipeline_data_loader';
|
||||
import { visualizationLoader } from './visualization_loader';
|
||||
import { Query } from '../../../../core_plugins/data/public';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
import { DataAdapter, RequestAdapter } from '../../inspector/adapters';
|
||||
|
||||
|
@ -67,7 +67,7 @@ export interface RequestHandlerParams {
|
|||
aggs: AggConfigs;
|
||||
timeRange?: TimeRange;
|
||||
query?: Query;
|
||||
filters?: Filter[];
|
||||
filters?: esFilters.Filter[];
|
||||
forceFetch: boolean;
|
||||
queryFilter: QueryFilter;
|
||||
uiState?: PersistedState;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { TimeRange } from 'src/plugins/data/public';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { SavedObject } from 'ui/saved_objects/saved_object';
|
||||
|
@ -26,6 +25,7 @@ import { SearchSource } from '../../courier';
|
|||
import { PersistedState } from '../../persisted_state';
|
||||
import { AppState } from '../../state_management/app_state';
|
||||
import { Vis } from '../../vis';
|
||||
import { esFilters } from '../../../../../plugins/data/public';
|
||||
|
||||
export interface VisSavedObject extends SavedObject {
|
||||
vis: Vis;
|
||||
|
@ -68,7 +68,7 @@ export interface VisualizeLoaderParams {
|
|||
/**
|
||||
* Specifies the filters that should be applied to that visualization.
|
||||
*/
|
||||
filters?: Filter[];
|
||||
filters?: esFilters.Filter[];
|
||||
/**
|
||||
* The query that should apply to that visualization.
|
||||
*/
|
||||
|
|
|
@ -22,13 +22,13 @@ import { get } from 'lodash';
|
|||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
import { AggConfig } from 'ui/vis';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { Query } from 'src/legacy/core_plugins/data/public';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { Vis } from '../../../vis';
|
||||
import { esFilters } from '../../../../../../plugins/data/public';
|
||||
|
||||
interface QueryGeohashBoundsParams {
|
||||
filters?: Filter[];
|
||||
filters?: esFilters.Filter[];
|
||||
query?: Query;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ export async function queryGeohashBounds(vis: Vis, params: QueryGeohashBoundsPar
|
|||
const useTimeFilter = !!indexPattern.timeFieldName;
|
||||
if (useTimeFilter) {
|
||||
const filter = timefilter.createFilter(indexPattern);
|
||||
if (filter) activeFilters.push((filter as any) as Filter);
|
||||
if (filter) activeFilters.push((filter as any) as esFilters.Filter);
|
||||
}
|
||||
return activeFilters;
|
||||
});
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { RefreshInterval, TimeRange, Query } from '../../../data/public';
|
||||
import { CoreStart } from '../../../../core/public';
|
||||
import { IUiActionsStart } from '../ui_actions_plugin';
|
||||
|
@ -38,6 +37,7 @@ import { createPanelState } from './panel';
|
|||
import { DashboardPanelState } from './types';
|
||||
import { DashboardViewport } from './viewport/dashboard_viewport';
|
||||
import { Start as InspectorStartContract } from '../../../inspector/public';
|
||||
import { esFilters } from '../../../../plugins/data/public';
|
||||
import {
|
||||
KibanaContextProvider,
|
||||
KibanaReactContext,
|
||||
|
@ -46,7 +46,7 @@ import {
|
|||
|
||||
export interface DashboardContainerInput extends ContainerInput {
|
||||
viewMode: ViewMode;
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
query: Query;
|
||||
timeRange: TimeRange;
|
||||
refreshConfig?: RefreshInterval;
|
||||
|
@ -65,7 +65,7 @@ interface IndexSignature {
|
|||
}
|
||||
|
||||
export interface InheritedChildInput extends IndexSignature {
|
||||
filters: Filter[];
|
||||
filters: esFilters.Filter[];
|
||||
query: Query;
|
||||
timeRange: TimeRange;
|
||||
refreshConfig?: RefreshInterval;
|
||||
|
|
320
src/plugins/data/common/es_query/__tests__/fields_mock.ts
Normal file
320
src/plugins/data/common/es_query/__tests__/fields_mock.ts
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* 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 const fields = [
|
||||
{
|
||||
name: 'bytes',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
count: 10,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'ssl',
|
||||
type: 'boolean',
|
||||
esTypes: ['boolean'],
|
||||
count: 20,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: '@timestamp',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
count: 30,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'time',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
count: 30,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: '@tags',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'utc_time',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'phpmemory',
|
||||
type: 'number',
|
||||
esTypes: ['integer'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'ip',
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'request_body',
|
||||
type: 'attachment',
|
||||
esTypes: ['attachment'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'point',
|
||||
type: 'geo_point',
|
||||
esTypes: ['geo_point'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'area',
|
||||
type: 'geo_shape',
|
||||
esTypes: ['geo_shape'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'hashed',
|
||||
type: 'murmur3',
|
||||
esTypes: ['murmur3'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'geo.coordinates',
|
||||
type: 'geo_point',
|
||||
esTypes: ['geo_point'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'extension',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'machine.os',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'machine.os.raw',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
subType: { multi: { parent: 'machine.os' } },
|
||||
},
|
||||
{
|
||||
name: 'geo.src',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: '_id',
|
||||
type: 'string',
|
||||
esTypes: ['_id'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: '_type',
|
||||
type: 'string',
|
||||
esTypes: ['_type'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: '_source',
|
||||
type: '_source',
|
||||
esTypes: ['_source'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'non-filterable',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: false,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'non-sortable',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: false,
|
||||
aggregatable: false,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'custom_user_field',
|
||||
type: 'conflict',
|
||||
esTypes: ['long', 'text'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
name: 'script string',
|
||||
type: 'string',
|
||||
count: 0,
|
||||
scripted: true,
|
||||
script: "'i am a string'",
|
||||
lang: 'expression',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'script number',
|
||||
type: 'number',
|
||||
count: 0,
|
||||
scripted: true,
|
||||
script: '1234',
|
||||
lang: 'expression',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'script date',
|
||||
type: 'date',
|
||||
count: 0,
|
||||
scripted: true,
|
||||
script: '1234',
|
||||
lang: 'painless',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'script murmur3',
|
||||
type: 'murmur3',
|
||||
count: 0,
|
||||
scripted: true,
|
||||
script: '1234',
|
||||
lang: 'expression',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
name: 'nestedField.child',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
readFromDocValues: false,
|
||||
subType: { nested: { path: 'nestedField' } },
|
||||
},
|
||||
{
|
||||
name: 'nestedField.nestedChild.doublyNestedChild',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
readFromDocValues: false,
|
||||
subType: { nested: { path: 'nestedField.nestedChild' } },
|
||||
},
|
||||
];
|
||||
|
||||
export const getField = (name: string) => fields.find(field => field.name === name);
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
import { IndexPattern, Field } from './types';
|
||||
|
||||
export type ExistsFilterMeta = FilterMeta;
|
||||
|
||||
|
@ -31,3 +32,14 @@ export type ExistsFilter = Filter & {
|
|||
};
|
||||
|
||||
export const isExistsFilter = (filter: any): filter is ExistsFilter => filter && filter.exists;
|
||||
|
||||
export const buildExistsFilter = (field: Field, indexPattern: IndexPattern) => {
|
||||
return {
|
||||
meta: {
|
||||
index: indexPattern.id,
|
||||
},
|
||||
exists: {
|
||||
field: field.name,
|
||||
},
|
||||
} as ExistsFilter;
|
||||
};
|
|
@ -17,16 +17,16 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
export * from './custom_filter';
|
||||
export * from './exists_filter';
|
||||
export * from './geo_bounding_box_filter';
|
||||
export * from './geo_polygon_filter';
|
||||
export * from './match_all_filter';
|
||||
export * from './meta_filter';
|
||||
export * from './missing_filter';
|
||||
export * from './phrase_filter';
|
||||
export * from './phrases_filter';
|
||||
export * from './query_string_filter';
|
||||
export * from './range_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';
|
||||
export * from './types';
|
|
@ -55,7 +55,7 @@ export interface LatLon {
|
|||
lon: number;
|
||||
}
|
||||
|
||||
export function buildEmptyFilter(isPinned: boolean, index?: string): Filter {
|
||||
export const buildEmptyFilter = (isPinned: boolean, index?: string): Filter => {
|
||||
const meta: FilterMeta = {
|
||||
disabled: false,
|
||||
negate: false,
|
||||
|
@ -65,43 +65,43 @@ export function buildEmptyFilter(isPinned: boolean, index?: string): Filter {
|
|||
const $state: FilterState = {
|
||||
store: isPinned ? FilterStateStore.GLOBAL_STATE : FilterStateStore.APP_STATE,
|
||||
};
|
||||
|
||||
return { meta, $state };
|
||||
}
|
||||
};
|
||||
|
||||
export function isFilterPinned(filter: Filter) {
|
||||
export const isFilterPinned = (filter: Filter) => {
|
||||
return filter.$state && filter.$state.store === FilterStateStore.GLOBAL_STATE;
|
||||
}
|
||||
};
|
||||
|
||||
export function toggleFilterDisabled(filter: Filter) {
|
||||
export const toggleFilterDisabled = (filter: Filter) => {
|
||||
const disabled = !filter.meta.disabled;
|
||||
const meta = { ...filter.meta, disabled };
|
||||
return { ...filter, meta };
|
||||
}
|
||||
|
||||
export function toggleFilterNegated(filter: Filter) {
|
||||
return { ...filter, meta };
|
||||
};
|
||||
|
||||
export const toggleFilterNegated = (filter: Filter) => {
|
||||
const negate = !filter.meta.negate;
|
||||
const meta = { ...filter.meta, negate };
|
||||
return { ...filter, meta };
|
||||
}
|
||||
|
||||
export function toggleFilterPinned(filter: Filter) {
|
||||
return { ...filter, meta };
|
||||
};
|
||||
|
||||
export const toggleFilterPinned = (filter: Filter) => {
|
||||
const store = isFilterPinned(filter) ? FilterStateStore.APP_STATE : FilterStateStore.GLOBAL_STATE;
|
||||
const $state = { ...filter.$state, store };
|
||||
|
||||
return { ...filter, $state };
|
||||
}
|
||||
};
|
||||
|
||||
export function enableFilter(filter: Filter) {
|
||||
return !filter.meta.disabled ? filter : toggleFilterDisabled(filter);
|
||||
}
|
||||
export const enableFilter = (filter: Filter) =>
|
||||
!filter.meta.disabled ? filter : toggleFilterDisabled(filter);
|
||||
|
||||
export function disableFilter(filter: Filter) {
|
||||
return filter.meta.disabled ? filter : toggleFilterDisabled(filter);
|
||||
}
|
||||
export const disableFilter = (filter: Filter) =>
|
||||
filter.meta.disabled ? filter : toggleFilterDisabled(filter);
|
||||
|
||||
export function pinFilter(filter: Filter) {
|
||||
return isFilterPinned(filter) ? filter : toggleFilterPinned(filter);
|
||||
}
|
||||
export const pinFilter = (filter: Filter) =>
|
||||
isFilterPinned(filter) ? filter : toggleFilterPinned(filter);
|
||||
|
||||
export function unpinFilter(filter: Filter) {
|
||||
return !isFilterPinned(filter) ? filter : toggleFilterPinned(filter);
|
||||
}
|
||||
export const unpinFilter = (filter: Filter) =>
|
||||
!isFilterPinned(filter) ? filter : toggleFilterPinned(filter);
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 { buildInlineScriptForPhraseFilter, buildPhraseFilter } from './phrase_filter';
|
||||
import { IndexPattern } from './types';
|
||||
import { getField } from '../__tests__/fields_mock';
|
||||
|
||||
describe('Phrase filter builder', () => {
|
||||
let indexPattern: IndexPattern;
|
||||
|
||||
beforeEach(() => {
|
||||
indexPattern = {
|
||||
id: 'id',
|
||||
};
|
||||
});
|
||||
|
||||
it('should be a function', () => {
|
||||
expect(typeof buildPhraseFilter).toBe('function');
|
||||
});
|
||||
|
||||
it('should return a match query filter when passed a standard field', () => {
|
||||
const field = getField('bytes');
|
||||
|
||||
expect(buildPhraseFilter(field, 5, indexPattern)).toEqual({
|
||||
meta: {
|
||||
index: 'id',
|
||||
},
|
||||
query: {
|
||||
match_phrase: {
|
||||
bytes: 5,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a script filter when passed a scripted field', () => {
|
||||
const field = getField('script number');
|
||||
|
||||
expect(buildPhraseFilter(field, 5, indexPattern)).toEqual({
|
||||
meta: {
|
||||
index: 'id',
|
||||
field: 'script number',
|
||||
},
|
||||
script: {
|
||||
script: {
|
||||
lang: 'expression',
|
||||
params: {
|
||||
value: 5,
|
||||
},
|
||||
source: '(1234) == value',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildInlineScriptForPhraseFilter', () => {
|
||||
it('should wrap painless scripts in a lambda', () => {
|
||||
const field = {
|
||||
lang: 'painless',
|
||||
script: 'return foo;',
|
||||
};
|
||||
|
||||
const expected =
|
||||
`boolean compare(Supplier s, def v) {return s.get() == v;}` +
|
||||
`compare(() -> { return foo; }, params.value);`;
|
||||
|
||||
expect(buildInlineScriptForPhraseFilter(field)).toBe(expected);
|
||||
});
|
||||
|
||||
it('should create a simple comparison for other langs', () => {
|
||||
const field = {
|
||||
lang: 'expression',
|
||||
script: 'doc[bytes].value',
|
||||
};
|
||||
|
||||
const expected = `(doc[bytes].value) == value`;
|
||||
|
||||
expect(buildInlineScriptForPhraseFilter(field)).toBe(expected);
|
||||
});
|
||||
});
|
144
src/plugins/data/common/es_query/filters/phrase_filter.ts
Normal file
144
src/plugins/data/common/es_query/filters/phrase_filter.ts
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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, isPlainObject } from 'lodash';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
import { IndexPattern, Field } from './types';
|
||||
|
||||
export type PhraseFilterMeta = FilterMeta & {
|
||||
params?: {
|
||||
query: string; // The unformatted value
|
||||
};
|
||||
script?: {
|
||||
script: {
|
||||
source?: any;
|
||||
lang?: string;
|
||||
params: any;
|
||||
};
|
||||
};
|
||||
field?: any;
|
||||
index?: any;
|
||||
};
|
||||
|
||||
export type PhraseFilter = Filter & {
|
||||
meta: PhraseFilterMeta;
|
||||
};
|
||||
|
||||
type PhraseFilterValue = string | number | boolean;
|
||||
|
||||
export const isPhraseFilter = (filter: any): filter is PhraseFilter => {
|
||||
const isMatchPhraseQuery = filter && filter.query && filter.query.match_phrase;
|
||||
|
||||
const isDeprecatedMatchPhraseQuery =
|
||||
filter &&
|
||||
filter.query &&
|
||||
filter.query.match &&
|
||||
Object.values(filter.query.match).find((params: any) => params.type === 'phrase');
|
||||
|
||||
return !!(isMatchPhraseQuery || isDeprecatedMatchPhraseQuery);
|
||||
};
|
||||
|
||||
export const isScriptedPhraseFilter = (filter: any): filter is PhraseFilter =>
|
||||
Boolean(get(filter, 'script.script.params.value'));
|
||||
|
||||
export const getPhraseFilterField = (filter: PhraseFilter) => {
|
||||
const queryConfig = filter.query.match_phrase || filter.query.match;
|
||||
return Object.keys(queryConfig)[0];
|
||||
};
|
||||
|
||||
export const getPhraseFilterValue = (filter: PhraseFilter): PhraseFilterValue => {
|
||||
const queryConfig = filter.query.match_phrase || filter.query.match;
|
||||
const queryValue = Object.values(queryConfig)[0] as any;
|
||||
return isPlainObject(queryValue) ? queryValue.query : queryValue;
|
||||
};
|
||||
|
||||
export const buildPhraseFilter = (
|
||||
field: Field,
|
||||
value: any,
|
||||
indexPattern: IndexPattern
|
||||
): PhraseFilter => {
|
||||
const convertedValue = getConvertedValueForField(field, value);
|
||||
|
||||
if (field.scripted) {
|
||||
return {
|
||||
meta: { index: indexPattern.id, field: field.name } as PhraseFilterMeta,
|
||||
script: getPhraseScript(field, value),
|
||||
} as PhraseFilter;
|
||||
} else {
|
||||
return {
|
||||
meta: { index: indexPattern.id },
|
||||
query: {
|
||||
match_phrase: {
|
||||
[field.name]: convertedValue,
|
||||
},
|
||||
},
|
||||
} as PhraseFilter;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPhraseScript = (field: Field, value: string) => {
|
||||
const convertedValue = getConvertedValueForField(field, value);
|
||||
const script = buildInlineScriptForPhraseFilter(field);
|
||||
|
||||
return {
|
||||
script: {
|
||||
source: script,
|
||||
lang: field.lang,
|
||||
params: {
|
||||
value: convertedValue,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// See https://github.com/elastic/elasticsearch/issues/20941 and https://github.com/elastic/kibana/issues/8677
|
||||
// and https://github.com/elastic/elasticsearch/pull/22201
|
||||
// for the reason behind this change. Aggs now return boolean buckets with a key of 1 or 0.
|
||||
export const getConvertedValueForField = (field: Field, value: any) => {
|
||||
if (typeof value !== 'boolean' && field.type === 'boolean') {
|
||||
if ([1, 'true'].includes(value)) {
|
||||
return true;
|
||||
} else if ([0, 'false'].includes(value)) {
|
||||
return false;
|
||||
} else {
|
||||
throw new Error(`${value} is not a valid boolean value for boolean field ${field.name}`);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a scripted field and returns an inline script appropriate for use in a script query.
|
||||
* Handles lucene expression and Painless scripts. Other langs aren't guaranteed to generate valid
|
||||
* scripts.
|
||||
*
|
||||
* @param {object} scriptedField A Field object representing a scripted field
|
||||
* @returns {string} The inline script string
|
||||
*/
|
||||
export const buildInlineScriptForPhraseFilter = (scriptedField: any) => {
|
||||
// We must wrap painless scripts in a lambda in case they're more than a simple expression
|
||||
if (scriptedField.lang === 'painless') {
|
||||
return (
|
||||
`boolean compare(Supplier s, def v) {return s.get() == v;}` +
|
||||
`compare(() -> { ${scriptedField.script} }, params.value);`
|
||||
);
|
||||
} else {
|
||||
return `(${scriptedField.script}) == value`;
|
||||
}
|
||||
};
|
|
@ -17,47 +17,54 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { getPhraseScript } from './phrase';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
import { Field, IndexPattern } from './types';
|
||||
import { getPhraseScript } from './phrase_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';
|
||||
|
||||
// Creates a filter where the given field matches one or more of the given values
|
||||
// params should be an array of values
|
||||
export function buildPhrasesFilter(field, params, indexPattern) {
|
||||
export const buildPhrasesFilter = (field: Field, params: any, indexPattern: IndexPattern) => {
|
||||
const index = indexPattern.id;
|
||||
const type = 'phrases';
|
||||
const key = field.name;
|
||||
const value = params
|
||||
.map(value => format(field, value))
|
||||
.join(', ');
|
||||
|
||||
const filter = {
|
||||
meta: { index, type, key, value, params }
|
||||
};
|
||||
const format = (f: Field, value: any) =>
|
||||
f && f.format && f.format.convert ? f.format.convert(value) : value;
|
||||
|
||||
const value = params.map((v: any) => format(field, v)).join(', ');
|
||||
|
||||
let should;
|
||||
if (field.scripted) {
|
||||
should = params.map((value) => ({
|
||||
script: getPhraseScript(field, value)
|
||||
should = params.map((v: any) => ({
|
||||
script: getPhraseScript(field, v),
|
||||
}));
|
||||
} else {
|
||||
should = params.map((value) => ({
|
||||
should = params.map((v: any) => ({
|
||||
match_phrase: {
|
||||
[field.name]: value
|
||||
}
|
||||
[field.name]: v,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
filter.query = {
|
||||
bool: {
|
||||
should,
|
||||
minimum_should_match: 1
|
||||
}
|
||||
};
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
function format(field, value) {
|
||||
return field && field.format && field.format.convert
|
||||
? field.format.convert(value)
|
||||
: value;
|
||||
}
|
||||
return {
|
||||
meta: { index, type, key, value, params },
|
||||
query: {
|
||||
bool: {
|
||||
should,
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
} as PhrasesFilter;
|
||||
};
|
|
@ -17,18 +17,31 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
// Creates a filter corresponding to a raw Elasticsearch query DSL object
|
||||
export function buildQueryFilter(query, index, alias) {
|
||||
const filter = {
|
||||
query: query,
|
||||
meta: {
|
||||
index,
|
||||
}
|
||||
};
|
||||
import { buildQueryFilter } from './query_string_filter';
|
||||
import { IndexPattern } from './types';
|
||||
|
||||
if (alias) {
|
||||
filter.meta.alias = alias;
|
||||
}
|
||||
describe('Phrase filter builder', () => {
|
||||
let indexPattern: IndexPattern;
|
||||
|
||||
return filter;
|
||||
}
|
||||
beforeEach(() => {
|
||||
indexPattern = {
|
||||
id: 'id',
|
||||
};
|
||||
});
|
||||
|
||||
it('should be a function', () => {
|
||||
expect(typeof buildQueryFilter).toBe('function');
|
||||
});
|
||||
|
||||
it('should return a query filter when passed a standard field', () => {
|
||||
expect(buildQueryFilter({ foo: 'bar' }, indexPattern.id, '')).toEqual({
|
||||
meta: {
|
||||
alias: '',
|
||||
index: 'id',
|
||||
},
|
||||
query: {
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
import { IndexPattern } from './types';
|
||||
|
||||
export type QueryStringFilterMeta = FilterMeta;
|
||||
|
||||
|
@ -32,3 +33,17 @@ export type QueryStringFilter = Filter & {
|
|||
|
||||
export const isQueryStringFilter = (filter: any): filter is QueryStringFilter =>
|
||||
filter && filter.query && filter.query.query_string;
|
||||
|
||||
// Creates a filter corresponding to a raw Elasticsearch query DSL object
|
||||
export const buildQueryFilter = (
|
||||
query: QueryStringFilter['query'],
|
||||
index: IndexPattern,
|
||||
alias: string
|
||||
) =>
|
||||
({
|
||||
query,
|
||||
meta: {
|
||||
index,
|
||||
alias,
|
||||
},
|
||||
} as QueryStringFilter);
|
174
src/plugins/data/common/es_query/filters/range_filter.test.ts
Normal file
174
src/plugins/data/common/es_query/filters/range_filter.test.ts
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 { each } from 'lodash';
|
||||
import { buildRangeFilter, RangeFilter } from './range_filter';
|
||||
import { IndexPattern, Field } from './types';
|
||||
import { getField } from '../__tests__/fields_mock';
|
||||
|
||||
describe('Range filter builder', () => {
|
||||
let indexPattern: IndexPattern;
|
||||
|
||||
beforeEach(() => {
|
||||
indexPattern = {
|
||||
id: 'id',
|
||||
};
|
||||
});
|
||||
|
||||
it('should be a function', () => {
|
||||
expect(typeof buildRangeFilter).toBe('function');
|
||||
});
|
||||
|
||||
it('should return a range filter when passed a standard field', () => {
|
||||
const field = getField('bytes');
|
||||
|
||||
expect(buildRangeFilter(field, { gte: 1, lte: 3 }, indexPattern)).toEqual({
|
||||
meta: {
|
||||
index: 'id',
|
||||
params: {},
|
||||
},
|
||||
range: {
|
||||
bytes: {
|
||||
gte: 1,
|
||||
lte: 3,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a script filter when passed a scripted field', () => {
|
||||
const field = getField('script number');
|
||||
|
||||
expect(buildRangeFilter(field, { gte: 1, lte: 3 }, indexPattern)).toEqual({
|
||||
meta: {
|
||||
field: 'script number',
|
||||
index: 'id',
|
||||
params: {},
|
||||
},
|
||||
script: {
|
||||
script: {
|
||||
lang: 'expression',
|
||||
source: '(' + field!.script + ')>=gte && (' + field!.script + ')<=lte',
|
||||
params: {
|
||||
value: '>=1 <=3',
|
||||
gte: 1,
|
||||
lte: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should wrap painless scripts in comparator lambdas', () => {
|
||||
const field = getField('script date');
|
||||
const expected =
|
||||
`boolean gte(Supplier s, def v) {return !s.get().toInstant().isBefore(Instant.parse(v))} ` +
|
||||
`boolean lte(Supplier s, def v) {return !s.get().toInstant().isAfter(Instant.parse(v))}` +
|
||||
`gte(() -> { ${field!.script} }, params.gte) && ` +
|
||||
`lte(() -> { ${field!.script} }, params.lte)`;
|
||||
|
||||
const rangeFilter = buildRangeFilter(field, { gte: 1, lte: 3 }, indexPattern);
|
||||
|
||||
expect(rangeFilter.script!.script.source).toBe(expected);
|
||||
});
|
||||
|
||||
it('should throw an error when gte and gt, or lte and lt are both passed', () => {
|
||||
const field = getField('script number');
|
||||
|
||||
expect(() => {
|
||||
buildRangeFilter(field, { gte: 1, gt: 3 }, indexPattern);
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
buildRangeFilter(field, { lte: 1, lt: 3 }, indexPattern);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it('to use the right operator for each of gte, gt, lt and lte', () => {
|
||||
const field = getField('script number');
|
||||
|
||||
each({ gte: '>=', gt: '>', lte: '<=', lt: '<' }, (operator: string, key: any) => {
|
||||
const params = {
|
||||
[key]: 5,
|
||||
};
|
||||
|
||||
const filter = buildRangeFilter(field, params, indexPattern);
|
||||
const script = filter.script!.script;
|
||||
|
||||
expect(script.source).toBe('(' + field!.script + ')' + operator + key);
|
||||
expect(script.params[key]).toBe(5);
|
||||
expect(script.params.value).toBe(operator + 5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given params where one side is infinite', () => {
|
||||
let field: Field;
|
||||
let filter: RangeFilter;
|
||||
|
||||
beforeEach(() => {
|
||||
field = getField('script number');
|
||||
filter = buildRangeFilter(field, { gte: 0, lt: Infinity }, indexPattern);
|
||||
});
|
||||
|
||||
describe('returned filter', () => {
|
||||
it('is a script filter', () => {
|
||||
expect(filter).toHaveProperty('script');
|
||||
});
|
||||
|
||||
it('contain a param for the finite side', () => {
|
||||
expect(filter.script!.script.params).toHaveProperty('gte', 0);
|
||||
});
|
||||
|
||||
it('does not contain a param for the infinite side', () => {
|
||||
expect(filter.script!.script.params).not.toHaveProperty('lt');
|
||||
});
|
||||
|
||||
it('does not contain a script condition for the infinite side', () => {
|
||||
const script = field!.script;
|
||||
|
||||
expect(filter.script!.script.source).toEqual(`(${script})>=gte`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given params where both sides are infinite', () => {
|
||||
let field: Field;
|
||||
let filter: RangeFilter;
|
||||
|
||||
beforeEach(() => {
|
||||
field = getField('script number');
|
||||
filter = buildRangeFilter(field, { gte: -Infinity, lt: Infinity }, indexPattern);
|
||||
});
|
||||
|
||||
describe('returned filter', () => {
|
||||
it('is a match_all filter', () => {
|
||||
expect(filter).not.toHaveProperty('script');
|
||||
expect(filter).toHaveProperty('match_all');
|
||||
});
|
||||
|
||||
it('does not contain params', () => {
|
||||
expect(filter).not.toHaveProperty('params');
|
||||
});
|
||||
|
||||
it('meta field is set to field name', () => {
|
||||
expect(filter.meta.field).toEqual('script number');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue