diff --git a/src/ui/public/filter_bar/lib/__tests__/mapMatchAll.js b/src/ui/public/filter_bar/lib/__tests__/mapMatchAll.js new file mode 100644 index 000000000000..b0c851b6774b --- /dev/null +++ b/src/ui/public/filter_bar/lib/__tests__/mapMatchAll.js @@ -0,0 +1,51 @@ + +describe('ui/filter_bar/lib', function () { + describe('mapMatchAll()', function () { + const expect = require('expect.js'); + const ngMock = require('ngMock'); + let resolvePromises; + let mapMatchAll; + let filter; + + + beforeEach(ngMock.module('kibana')); + beforeEach(ngMock.inject(function (Private, $rootScope) { + resolvePromises = () => $rootScope.$apply(); + mapMatchAll = Private(require('ui/filter_bar/lib/mapMatchAll')); + filter = { + match_all: {}, + meta: { + field: 'foo', + formattedValue: 'bar' + } + }; + })); + + context('when given a filter that is not match_all', function () { + it('filter is rejected', function (done) { + delete filter.match_all; + mapMatchAll(filter).catch(result => { + expect(result).to.be(filter); + done(); + }); + resolvePromises(); + }); + }); + + context('when given a match_all filter', function () { + let result; + beforeEach(function () { + mapMatchAll(filter).then(r => result = r); + resolvePromises(); + }); + + it('key is set to meta field', function () { + expect(result).to.have.property('key', filter.meta.field); + }); + + it('value is set to meta formattedValue', function () { + expect(result).to.have.property('value', filter.meta.formattedValue); + }); + }); + }); +}); diff --git a/src/ui/public/filter_bar/lib/mapFilter.js b/src/ui/public/filter_bar/lib/mapFilter.js index 8bf2a2d5cf43..ebf6bb31ae11 100644 --- a/src/ui/public/filter_bar/lib/mapFilter.js +++ b/src/ui/public/filter_bar/lib/mapFilter.js @@ -21,6 +21,7 @@ define(function (require) { // that either handles the mapping operation or not // and add it here. ProTip: These are executed in order listed var mappers = [ + Private(require('./mapMatchAll')), Private(require('./mapTerms')), Private(require('./mapRange')), Private(require('./mapExists')), diff --git a/src/ui/public/filter_bar/lib/mapMatchAll.js b/src/ui/public/filter_bar/lib/mapMatchAll.js new file mode 100644 index 000000000000..c062fa69e0dc --- /dev/null +++ b/src/ui/public/filter_bar/lib/mapMatchAll.js @@ -0,0 +1,12 @@ +define(function (require) { + return function mapMatchAllProvider(Promise) { + return function (filter) { + if (filter.match_all) { + const key = filter.meta.field; + const value = filter.meta.formattedValue || 'all'; + return Promise.resolve({ key, value }); + } + return Promise.reject(filter); + }; + }; +}); diff --git a/src/ui/public/filter_manager/__tests__/lib/range.js b/src/ui/public/filter_manager/__tests__/lib/range.js index 7de6608c22bb..fb3432a6cab2 100644 --- a/src/ui/public/filter_manager/__tests__/lib/range.js +++ b/src/ui/public/filter_manager/__tests__/lib/range.js @@ -63,5 +63,53 @@ describe('Filter Manager', function () { }); }); + + context('when given params where one side is infinite', function () { + let filter; + beforeEach(function () { + filter = fn(indexPattern.fields.byName['script number'], { 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.params).to.have.property('gte', 0); + }); + + it('does not contain a param for the infinite side', function () { + expect(filter.script.params).not.to.have.property('lt'); + }); + + it('does not contain a script condition for the infinite side', function () { + const script = indexPattern.fields.byName['script number'].script; + expect(filter.script.script).to.equal(`(${script})>=gte`); + }); + }); + }); + + context('when given params where both sides are infinite', function () { + let filter; + beforeEach(function () { + filter = fn(indexPattern.fields.byName['script number'], { 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'); + }); + }); + }); }); }); diff --git a/src/ui/public/filter_manager/lib/range.js b/src/ui/public/filter_manager/lib/range.js index 759518041e64..4d374a51d320 100644 --- a/src/ui/public/filter_manager/lib/range.js +++ b/src/ui/public/filter_manager/lib/range.js @@ -1,27 +1,44 @@ define(function (require) { - var _ = require('lodash'); + const _ = require('lodash'); + const OPERANDS_IN_RANGE = 2; + return function buildRangeFilter(field, params, indexPattern, formattedValue) { - var filter = { meta: { index: indexPattern.id } }; + const filter = { meta: { index: indexPattern.id } }; if (formattedValue) filter.meta.formattedValue = formattedValue; params = _.clone(params); - if (params.gte && params.gt) throw new Error('gte and gt are mutually exclusive'); - if (params.lte && params.lt) throw new Error('lte and lt are mutually exclusive'); + if ('gte' in params && 'gt' in params) throw new Error('gte and gt are mutually exclusive'); + if ('lte' in params && 'lt' in params) throw new Error('lte and lt are mutually exclusive'); - if (field.scripted) { - var operators = { + const totalInfinite = ['gt', 'lt'].reduce((totalInfinite, op) => { + const key = op in params ? op : `${op}e`; + const isInfinite = Math.abs(params[key]) === Infinity; + + if (isInfinite) { + totalInfinite++; + delete params[key]; + } + + return totalInfinite; + }, 0); + + if (totalInfinite === OPERANDS_IN_RANGE) { + filter.match_all = {}; + filter.meta.field = field.name; + } else if (field.scripted) { + const operators = { gt: '>', gte: '>=', lte: '<=', lt: '<', }; - var script = _.map(params, function (val, key) { + const script = _.map(params, function (val, key) { return '(' + field.script + ')' + operators[key] + key; }).join(' && '); - var value = _.map(params, function (val, key) { + const value = _.map(params, function (val, key) { return operators[key] + field.format.convert(val); }).join(' '); @@ -32,6 +49,7 @@ define(function (require) { filter.range = {}; filter.range[field.name] = params; } + return filter; }; });