mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Merge pull request #279 from spenceralger/fix_sorting_by_metric
Fix sorting by metric
This commit is contained in:
commit
ac58bee5bf
18 changed files with 634 additions and 22 deletions
|
@ -632,7 +632,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
$scope.searchSource.aggs(function () {
|
||||
return $scope.vis.aggs.toDSL();
|
||||
return $scope.vis.aggs.toDsl();
|
||||
});
|
||||
|
||||
// stash this promise so that other calls to setupVisualization will have to wait
|
||||
|
|
|
@ -89,7 +89,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
self.searchSource.aggs(function () {
|
||||
return self.vis.aggs.toDSL();
|
||||
return self.vis.aggs.toDsl();
|
||||
});
|
||||
|
||||
return self;
|
||||
|
|
|
@ -57,7 +57,7 @@ define(function (require) {
|
|||
* the quality of things like date_histogram's "auto" interval)
|
||||
* @return {object} output
|
||||
* output of the write calls, reduced into a single object. A `params: {}` property is exposed on the
|
||||
* output object which is used to create the agg DSL for the search request. All other properties
|
||||
* output object which is used to create the agg dsl for the search request. All other properties
|
||||
* are dependent on the AggParam#write methods which should be studied for each AggType.
|
||||
*/
|
||||
AggParams.prototype.write = function (aggConfig, locals) {
|
||||
|
|
|
@ -56,6 +56,15 @@ define(function (require) {
|
|||
*/
|
||||
this.ordered = config.ordered;
|
||||
|
||||
/**
|
||||
* Flag that prevents this aggregation from being included in the dsl. This is only
|
||||
* used by the count aggregation (currently) since it doesn't really exist and it's output
|
||||
* is available on every bucket.
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.hasNoDsl = !!config.hasNoDsl;
|
||||
|
||||
/**
|
||||
* An instance of {{#crossLink "AggParams"}}{{/crossLink}}.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
define(function (require) {
|
||||
return function BucketCountBetweenUtil() {
|
||||
|
||||
/**
|
||||
* Count the number of bucket aggs between two agg config objects owned
|
||||
* by the same vis.
|
||||
*
|
||||
* If one of the two aggs was not found in the agg list, returns null.
|
||||
* If a was found after b, the count will be negative
|
||||
* If a was found first, the count will be positive.
|
||||
*
|
||||
* @param {AggConfig} aggConfigA - the aggConfig that is expected first
|
||||
* @param {AggConfig} aggConfigB - the aggConfig that is expected second
|
||||
* @return {null|number}
|
||||
*/
|
||||
function bucketCountBetween(aggConfigA, aggConfigB) {
|
||||
var aggs = aggConfigA.vis.aggs.getSorted();
|
||||
|
||||
var aIndex = aggs.indexOf(aggConfigA);
|
||||
var bIndex = aggs.indexOf(aggConfigB);
|
||||
|
||||
if (aIndex === -1 || bIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// return a negative distance, if b is before a
|
||||
var negative = (aIndex > bIndex);
|
||||
|
||||
var count = aggs
|
||||
.slice(aIndex, bIndex - aIndex - 1)
|
||||
.reduce(function (count, cfg) {
|
||||
if (cfg.schema.group === 'buckets') {
|
||||
return count + 1;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
}, 0);
|
||||
|
||||
return (negative ? -1 : 1) * count;
|
||||
}
|
||||
|
||||
return bucketCountBetween;
|
||||
};
|
||||
});
|
|
@ -2,6 +2,7 @@ define(function (require) {
|
|||
return function TermsAggDefinition(Private) {
|
||||
var _ = require('lodash');
|
||||
var AggType = Private(require('components/agg_types/_agg_type'));
|
||||
var bucketCountBetween = Private(require('components/agg_types/buckets/_bucket_count_between'));
|
||||
|
||||
return new AggType({
|
||||
name: 'terms',
|
||||
|
@ -28,11 +29,23 @@ define(function (require) {
|
|||
editor: require('text!components/agg_types/controls/order_and_size.html'),
|
||||
default: 'desc',
|
||||
write: function (aggConfig, output) {
|
||||
var metricAggConfig = _.first(aggConfig.vis.aggs.bySchemaGroup.metrics);
|
||||
|
||||
var metricAgg = _.first(aggConfig.vis.aggs.bySchemaGroup.metrics);
|
||||
/**
|
||||
* In order to sort by a metric agg, the metric need to be an immediate
|
||||
* decendant, this checks if that is the case.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
var metricIsOwned = bucketCountBetween(aggConfig, metricAggConfig) === 0;
|
||||
|
||||
output.params.order = {};
|
||||
output.params.order[metricAgg.id] = aggConfig.params.order.val;
|
||||
output.params.order[metricAggConfig.id] = aggConfig.params.order.val;
|
||||
|
||||
if (!metricIsOwned) {
|
||||
output.subAggs = output.subAggs || [];
|
||||
output.subAggs.push(metricAggConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -6,6 +6,7 @@ define(function (require) {
|
|||
{
|
||||
name: 'count',
|
||||
title: 'Count',
|
||||
hasNoDsl: true,
|
||||
makeLabel: function (aggConfig) {
|
||||
return 'Count of documents';
|
||||
}
|
||||
|
|
|
@ -60,6 +60,38 @@ define(function (require) {
|
|||
});
|
||||
};
|
||||
|
||||
AggConfig.prototype.write = function () {
|
||||
return this.type.params.write(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert this aggConfig to it's dsl syntax.
|
||||
*
|
||||
* Adds params and adhoc subaggs to a pojo, then returns it
|
||||
*
|
||||
* @param {AggConfig} aggConfig - the config object to convert
|
||||
* @return {void|Object} - if the config has a dsl representation, it is
|
||||
* returned, else undefined is returned
|
||||
*/
|
||||
AggConfig.prototype.toDsl = function () {
|
||||
if (this.type.hasNoDsl) return;
|
||||
|
||||
var output = this.write();
|
||||
|
||||
var configDsl = {};
|
||||
configDsl[this.type.name] = output.params;
|
||||
|
||||
// if the config requires subAggs, write them to the dsl as well
|
||||
if (output.subAggs) {
|
||||
var subDslLvl = configDsl.aggs || (configDsl.aggs = {});
|
||||
output.subAggs.forEach(function nestAdhocSubAggs(subAggConfig) {
|
||||
subDslLvl[subAggConfig.id] = subAggConfig.toDsl();
|
||||
});
|
||||
}
|
||||
|
||||
return configDsl;
|
||||
};
|
||||
|
||||
AggConfig.prototype.toJSON = function () {
|
||||
var self = this;
|
||||
var params = self.params;
|
||||
|
|
|
@ -7,32 +7,41 @@ define(function (require) {
|
|||
_(AggConfigs).inherits(Registry);
|
||||
function AggConfigs(vis, configStates) {
|
||||
this.vis = vis;
|
||||
|
||||
AggConfigs.Super.call(this, {
|
||||
index: ['id'],
|
||||
group: ['schema.group'],
|
||||
group: ['schema.group', 'type.name'],
|
||||
initialSet: (configStates || []).map(function (aggConfigState) {
|
||||
if (aggConfigState instanceof AggConfig) return aggConfigState;
|
||||
return new AggConfig(vis, aggConfigState);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
AggConfigs.prototype.toDSL = function () {
|
||||
var dsl = {};
|
||||
var current = dsl;
|
||||
AggConfigs.prototype.toDsl = function () {
|
||||
var dslTopLvl = {};
|
||||
var dslLvlCursor;
|
||||
|
||||
this.getSorted().forEach(function (agg) {
|
||||
if (agg.type.name === 'count') return;
|
||||
this.getSorted()
|
||||
.filter(function (config) {
|
||||
return !config.type.hasNoDsl;
|
||||
})
|
||||
.forEach(function nestEachConfig(config, i, list) {
|
||||
var prevConfig = list[i - 1];
|
||||
var prevDsl = prevConfig && dslLvlCursor && dslLvlCursor[prevConfig.id];
|
||||
|
||||
current.aggs = {};
|
||||
// advance the cursor
|
||||
if (prevDsl && prevConfig.schema.group !== 'metrics') {
|
||||
dslLvlCursor = prevDsl.aggs || (prevDsl.aggs = {});
|
||||
}
|
||||
|
||||
var aggDsl = {};
|
||||
var output = agg.type.params.write(agg);
|
||||
aggDsl[agg.type.name] = output.params;
|
||||
current = current.aggs[agg.id] = aggDsl;
|
||||
// start at the top level
|
||||
if (!dslLvlCursor) dslLvlCursor = dslTopLvl;
|
||||
|
||||
dslLvlCursor[config.id] = config.toDsl();
|
||||
});
|
||||
|
||||
// set the dsl to the searchSource
|
||||
return dsl.aggs || {};
|
||||
return dslTopLvl;
|
||||
};
|
||||
|
||||
AggConfigs.prototype.getSorted = function () {
|
||||
|
|
|
@ -26,7 +26,7 @@ define(function (require) {
|
|||
},
|
||||
_.merge(
|
||||
aggConfig.schema.params.write(aggConfig),
|
||||
aggConfig.type.params.write(aggConfig)
|
||||
aggConfig.write()
|
||||
)
|
||||
);
|
||||
return chartDataConfig;
|
||||
|
|
|
@ -88,7 +88,8 @@
|
|||
'specs/index_patterns/_flatten_search_response',
|
||||
'specs/utils/registry/index',
|
||||
'specs/directives/filter_bar',
|
||||
'specs/components/agg_types/index'
|
||||
'specs/components/agg_types/index',
|
||||
'specs/components/vis/index'
|
||||
], function (kibana, sinon) {
|
||||
kibana.load(function () {
|
||||
var xhr = sinon.useFakeXMLHttpRequest();
|
||||
|
|
193
test/unit/specs/components/agg_types/_bucket_count_between.js
Normal file
193
test/unit/specs/components/agg_types/_bucket_count_between.js
Normal file
|
@ -0,0 +1,193 @@
|
|||
define(function (require) {
|
||||
return ['bucketCountBetween util', function () {
|
||||
var _ = require('lodash');
|
||||
var indexPattern;
|
||||
var Vis;
|
||||
var visTypes;
|
||||
var aggTypes;
|
||||
var AggConfig;
|
||||
var bucketCountBetween;
|
||||
|
||||
// http://cwestblog.com/2014/02/25/javascript-testing-for-negative-zero/
|
||||
// works for -0 and +0
|
||||
function isNegative(n) {
|
||||
return ((n = +n) || 1 / n) < 0;
|
||||
}
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private) {
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
Vis = Private(require('components/vis/vis'));
|
||||
visTypes = Private(require('components/vis_types/index'));
|
||||
aggTypes = Private(require('components/agg_types/index'));
|
||||
AggConfig = Private(require('components/vis/_agg_config'));
|
||||
bucketCountBetween = Private(require('components/agg_types/buckets/_bucket_count_between'));
|
||||
}));
|
||||
|
||||
it('returns a positive number when a is before b', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
},
|
||||
{
|
||||
type: 'terms',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var a = vis.aggs.byTypeName.date_histogram[0];
|
||||
var b = vis.aggs.byTypeName.terms[0];
|
||||
var count = bucketCountBetween(a, b);
|
||||
expect(isNegative(count)).to.be(false);
|
||||
});
|
||||
|
||||
it('returns a negative number when a is after b', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
},
|
||||
{
|
||||
type: 'terms',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var a = vis.aggs.byTypeName.terms[0];
|
||||
var b = vis.aggs.byTypeName.date_histogram[0];
|
||||
var count = bucketCountBetween(a, b);
|
||||
expect(isNegative(count)).to.be(true);
|
||||
});
|
||||
|
||||
it('returns 0 when there are no buckets between a and b', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
},
|
||||
{
|
||||
type: 'terms',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var a = vis.aggs.byTypeName.date_histogram[0];
|
||||
var b = vis.aggs.byTypeName.terms[0];
|
||||
expect(bucketCountBetween(a, b)).to.be(0);
|
||||
});
|
||||
|
||||
it('returns null when b is not in the aggs', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var a = vis.aggs.byTypeName.date_histogram[0];
|
||||
var b = new AggConfig(vis, {
|
||||
type: 'terms',
|
||||
schema: 'segment'
|
||||
});
|
||||
|
||||
expect(bucketCountBetween(a, b)).to.be(null);
|
||||
});
|
||||
|
||||
it('returns null when a is not in the aggs', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var a = new AggConfig(vis, {
|
||||
type: 'terms',
|
||||
schema: 'segment'
|
||||
});
|
||||
var b = vis.aggs.byTypeName.date_histogram[0];
|
||||
|
||||
expect(bucketCountBetween(a, b)).to.be(null);
|
||||
});
|
||||
|
||||
it('returns null when a and b are not in the aggs', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: []
|
||||
});
|
||||
|
||||
var a = new AggConfig(vis, {
|
||||
type: 'terms',
|
||||
schema: 'segment'
|
||||
});
|
||||
|
||||
var b = new AggConfig(vis, {
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
});
|
||||
|
||||
expect(bucketCountBetween(a, b)).to.be(null);
|
||||
});
|
||||
|
||||
it('can count', function () {
|
||||
var schemas = visTypes.byName.histogram.schemas.buckets;
|
||||
|
||||
// slow for this test is actually somewhere around 1/2 a sec
|
||||
this.slow(500);
|
||||
|
||||
function randBucketAggForVis(vis) {
|
||||
var schema = _.sample(schemas);
|
||||
var aggType = _.sample(aggTypes.byType.buckets);
|
||||
|
||||
return new AggConfig(vis, {
|
||||
schema: schema,
|
||||
type: aggType
|
||||
});
|
||||
}
|
||||
|
||||
_.times(50, function (n) {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: []
|
||||
});
|
||||
|
||||
var randBucketAgg = _.partial(randBucketAggForVis, vis);
|
||||
|
||||
var a = randBucketAgg();
|
||||
var b = randBucketAgg();
|
||||
|
||||
// create n aggs between a and b
|
||||
var aggs = [];
|
||||
for (var i = 0; i < n; i++) {
|
||||
aggs.push(randBucketAgg());
|
||||
}
|
||||
|
||||
aggs.unshift(a);
|
||||
aggs.push(b);
|
||||
|
||||
vis.setState({
|
||||
type: 'histogram',
|
||||
aggs: aggs
|
||||
});
|
||||
|
||||
expect(bucketCountBetween(a, b)).to.be(n);
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
|
@ -30,7 +30,7 @@ define(function (require) {
|
|||
}));
|
||||
|
||||
describe('interval', function () {
|
||||
// reads aggConfig.params.interval, writes to DSL.interval
|
||||
// reads aggConfig.params.interval, writes to dsl.interval
|
||||
|
||||
it('accepts a number', function () {
|
||||
var output = paramWriter.write({ interval: 100 });
|
||||
|
|
|
@ -30,7 +30,7 @@ define(function (require) {
|
|||
}));
|
||||
|
||||
describe('interval', function () {
|
||||
// reads aggConfig.params.interval, writes to DSL.interval
|
||||
// reads aggConfig.params.interval, writes to dsl.interval
|
||||
|
||||
it('accepts a number', function () {
|
||||
var output = paramWriter.write({ interval: 100 });
|
||||
|
|
|
@ -3,6 +3,7 @@ define(function (require) {
|
|||
var childSuites = [
|
||||
require('specs/components/agg_types/_agg_type'),
|
||||
require('specs/components/agg_types/_agg_params'),
|
||||
require('specs/components/agg_types/_bucket_count_between'),
|
||||
require('specs/components/agg_types/bucket_aggs/histogram'),
|
||||
require('specs/components/agg_types/bucket_aggs/date_histogram'),
|
||||
require('specs/components/agg_types/_metric_aggs')
|
||||
|
|
106
test/unit/specs/components/vis/_agg_config.js
Normal file
106
test/unit/specs/components/vis/_agg_config.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
define(function (require) {
|
||||
return ['AggConfig', function () {
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
|
||||
var Vis;
|
||||
var AggConfig;
|
||||
var indexPattern;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private) {
|
||||
Vis = Private(require('components/vis/vis'));
|
||||
AggConfig = Private(require('components/vis/_agg_config'));
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
}));
|
||||
|
||||
describe('#toDsl', function () {
|
||||
it('calls #write()', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var aggConfig = vis.aggs.byTypeName.date_histogram[0];
|
||||
var stub = sinon.stub(aggConfig, 'write').returns({ params: {} });
|
||||
|
||||
aggConfig.toDsl();
|
||||
expect(stub.callCount).to.be(1);
|
||||
});
|
||||
|
||||
it('uses the type name as the agg name', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var aggConfig = vis.aggs.byTypeName.date_histogram[0];
|
||||
sinon.stub(aggConfig, 'write').returns({ params: {} });
|
||||
|
||||
var dsl = aggConfig.toDsl();
|
||||
expect(dsl).to.have.property('date_histogram');
|
||||
});
|
||||
|
||||
|
||||
it('uses the params from #write() output as the agg params', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var aggConfig = vis.aggs.byTypeName.date_histogram[0];
|
||||
var football = {};
|
||||
|
||||
sinon.stub(aggConfig, 'write').returns({ params: football });
|
||||
|
||||
var dsl = aggConfig.toDsl();
|
||||
expect(dsl.date_histogram).to.be(football);
|
||||
});
|
||||
|
||||
it('includes subAggs from #write() output', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'avg',
|
||||
schema: 'metric'
|
||||
},
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var histoConfig = vis.aggs.byTypeName.date_histogram[0];
|
||||
var avgConfig = vis.aggs.byTypeName.avg[0];
|
||||
var football = {};
|
||||
|
||||
sinon.stub(histoConfig, 'write').returns({ params: {}, subAggs: [avgConfig] });
|
||||
sinon.stub(avgConfig, 'write').returns({ params: football });
|
||||
|
||||
var dsl = histoConfig.toDsl();
|
||||
|
||||
// didn't use .eql() because of variable key names, and final check is strict
|
||||
expect(dsl).to.have.property('aggs');
|
||||
expect(dsl.aggs).to.have.property(avgConfig.id);
|
||||
expect(dsl.aggs[avgConfig.id]).to.have.property('avg');
|
||||
expect(dsl.aggs[avgConfig.id].avg).to.be(football);
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
193
test/unit/specs/components/vis/_agg_configs.js
Normal file
193
test/unit/specs/components/vis/_agg_configs.js
Normal file
|
@ -0,0 +1,193 @@
|
|||
define(function (require) {
|
||||
return ['AggConfigs', function () {
|
||||
var _ = require('lodash');
|
||||
var sinon = require('test_utils/auto_release_sinon');
|
||||
|
||||
var Vis;
|
||||
var Registry;
|
||||
var AggConfig;
|
||||
var AggConfigs;
|
||||
var SpiedAggConfig;
|
||||
var indexPattern;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private) {
|
||||
// replace the AggConfig module with a spy
|
||||
var RealAggConfigPM = require('components/vis/_agg_config');
|
||||
AggConfig = Private(RealAggConfigPM);
|
||||
Private.stub(RealAggConfigPM, sinon.spy(AggConfig));
|
||||
|
||||
// load main deps
|
||||
Vis = Private(require('components/vis/vis'));
|
||||
SpiedAggConfig = Private(require('components/vis/_agg_config'));
|
||||
AggConfigs = Private(require('components/vis/_agg_configs'));
|
||||
Registry = require('utils/registry/registry');
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
}));
|
||||
|
||||
it('extends Registry', function () {
|
||||
var ac = new AggConfigs();
|
||||
expect(ac).to.be.a(Registry);
|
||||
});
|
||||
|
||||
describe('constructor', function () {
|
||||
it('handles passing just a vis', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: []
|
||||
});
|
||||
|
||||
var ac = new AggConfigs(vis);
|
||||
expect(ac).to.have.length(0);
|
||||
});
|
||||
|
||||
it('converts configStates into AggConfig objects if they are not already', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: []
|
||||
});
|
||||
|
||||
var ac = new AggConfigs(vis, [
|
||||
{
|
||||
type: 'date_histogram',
|
||||
schema: 'segment'
|
||||
},
|
||||
new AggConfig({
|
||||
type: 'terms',
|
||||
schema: 'split'
|
||||
})
|
||||
]);
|
||||
|
||||
expect(ac).to.have.length(2);
|
||||
expect(SpiedAggConfig).to.have.property('callCount', 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getSorted', function () {
|
||||
it('performs a stable sort, but moves metrics to the bottom', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{ type: 'avg', schema: 'metric' },
|
||||
{ type: 'terms', schema: 'split' },
|
||||
{ type: 'histogram', schema: 'split' },
|
||||
{ type: 'sum', schema: 'metric' },
|
||||
{ type: 'date_histogram', schema: 'segment' },
|
||||
{ type: 'filters', schema: 'split' },
|
||||
{ type: 'count', schema: 'metric' }
|
||||
]
|
||||
});
|
||||
|
||||
var avg = vis.aggs.byTypeName.avg[0];
|
||||
var sum = vis.aggs.byTypeName.sum[0];
|
||||
var count = vis.aggs.byTypeName.count[0];
|
||||
var terms = vis.aggs.byTypeName.terms[0];
|
||||
var histo = vis.aggs.byTypeName.histogram[0];
|
||||
var dateHisto = vis.aggs.byTypeName.date_histogram[0];
|
||||
var filters = vis.aggs.byTypeName.filters[0];
|
||||
|
||||
var sorted = vis.aggs.getSorted();
|
||||
|
||||
expect(sorted.shift()).to.be(terms);
|
||||
expect(sorted.shift()).to.be(histo);
|
||||
expect(sorted.shift()).to.be(dateHisto);
|
||||
expect(sorted.shift()).to.be(filters);
|
||||
expect(sorted.shift()).to.be(avg);
|
||||
expect(sorted.shift()).to.be(sum);
|
||||
expect(sorted.shift()).to.be(count);
|
||||
expect(sorted).to.have.length(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toDsl', function () {
|
||||
it('uses the sorted aggs', function () {
|
||||
var vis = new Vis(indexPattern, { type: 'histogram' });
|
||||
sinon.spy(vis.aggs, 'getSorted');
|
||||
vis.aggs.toDsl();
|
||||
expect(vis.aggs.getSorted).to.have.property('callCount', 1);
|
||||
});
|
||||
|
||||
it('calls aggConfig#toDsl() on each aggConfig and compiles the nested output', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{ type: 'date_histogram', schema: 'segment' },
|
||||
{ type: 'filters', schema: 'split' }
|
||||
]
|
||||
});
|
||||
|
||||
var aggInfos = vis.aggs.map(function (aggConfig) {
|
||||
var football = {};
|
||||
|
||||
sinon.stub(aggConfig, 'toDsl', function () {
|
||||
return football;
|
||||
});
|
||||
|
||||
return {
|
||||
id: aggConfig.id,
|
||||
football: football
|
||||
};
|
||||
});
|
||||
|
||||
(function recurse(lvl) {
|
||||
var info = aggInfos.shift();
|
||||
|
||||
expect(lvl).to.have.property(info.id);
|
||||
expect(lvl[info.id]).to.be(info.football);
|
||||
|
||||
if (lvl[info.id].aggs) {
|
||||
return recurse(lvl[info.id].aggs);
|
||||
}
|
||||
}(vis.aggs.toDsl()));
|
||||
|
||||
expect(aggInfos).to.have.length(0);
|
||||
});
|
||||
|
||||
it('skips aggs that don\'t have a dsl representation', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{ type: 'date_histogram', schema: 'segment', params: { field: '@timestamp' } },
|
||||
{ type: 'count', schema: 'metric' }
|
||||
]
|
||||
});
|
||||
|
||||
var dsl = vis.aggs.toDsl();
|
||||
var histo = vis.aggs.byTypeName.date_histogram[0];
|
||||
var count = vis.aggs.byTypeName.count[0];
|
||||
|
||||
expect(dsl).to.have.property(histo.id);
|
||||
expect(dsl[histo.id]).to.be.an('object');
|
||||
expect(dsl[histo.id]).to.not.have.property('aggs');
|
||||
expect(dsl).to.not.have.property(count.id);
|
||||
});
|
||||
|
||||
it('writes multiple metric aggregations at the same level', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{ type: 'date_histogram', schema: 'segment', params: { field: '@timestamp' } },
|
||||
{ type: 'avg', schema: 'metric', params: { field: 'bytes' } },
|
||||
{ type: 'sum', schema: 'metric', params: { field: 'bytes' } },
|
||||
{ type: 'min', schema: 'metric', params: { field: 'bytes' } },
|
||||
{ type: 'max', schema: 'metric', params: { field: 'bytes' } }
|
||||
]
|
||||
});
|
||||
|
||||
var dsl = vis.aggs.toDsl();
|
||||
|
||||
var histo = vis.aggs.byTypeName.date_histogram[0];
|
||||
var metrics = vis.aggs.bySchemaGroup.metrics;
|
||||
|
||||
expect(dsl).to.have.property(histo.id);
|
||||
expect(dsl[histo.id]).to.be.an('object');
|
||||
expect(dsl[histo.id]).to.have.property('aggs');
|
||||
|
||||
metrics.forEach(function (metric) {
|
||||
expect(dsl[histo.id].aggs).to.have.property(metric.id);
|
||||
expect(dsl[histo.id].aggs[metric.id]).to.not.have.property('aggs');
|
||||
});
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
10
test/unit/specs/components/vis/index.js
Normal file
10
test/unit/specs/components/vis/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
define(function (require) {
|
||||
describe('Vis Component', function () {
|
||||
var childSuites = [
|
||||
require('specs/components/vis/_agg_config'),
|
||||
require('specs/components/vis/_agg_configs')
|
||||
].forEach(function (s) {
|
||||
describe(s[0], s[1]);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue