app/modules/entities/crud/aggregation.js
// @flow
const _ = require('lodash');
class Aggregation {
_name: string;
_object: Object;
_field: ?string;
constructor(name: string, object: Object = {}) {
this._name = name;
this._object = object;
this._field = 'field' in object ? object.field : null;
}
get name(): string {
return this._name;
}
field(f: string) {
this._field = f;
return this;
}
generate(): Object {
return this._object;
}
}
class TopHitsAggregation extends Aggregation {
_size: number;
_from: number;
_sort: Array<Object>;
_source: ?Object;
constructor(name: string, object: Object = {}) {
super(name, object);
this._name = name;
this._object = object;
this._size = 'size' in object ? object.size : 0;
this._from = 'from' in object ? object.from : 0;
this._sort = 'sort' in object ? object.sort : [];
this._source = '_source' in object ? object._source : null;
}
size(s: number): TopHitsAggregation {
this._size = s;
return this;
}
from(f: number): TopHitsAggregation {
this._from = f;
return this;
}
sort(s: Array): TopHitsAggregation {
this._sort = s;
return this;
}
source(s: ?Object): TopHitsAggregation {
this._source = source;
return this;
}
generate(): Object {
const obj = {
[this._name]: {},
};
obj[this._name] = {
top_hits: {
sort: this._sort,
size: this._size,
from: this._from,
},
};
if (this._source) {
obj[this._name].top_hits._source = this._source;
}
return obj;
}
}
class MetricAggregation extends Aggregation {
}
class SingleValueMetricAggregation extends MetricAggregation {
_missing: any;
constructor(name: string, object: Object = {}) {
super(name, object);
this._missing = 'missing' in object ? object.missing : null;
}
missing(v: any) {
if (v == null) {
return this;
}
this._missing = v;
return this;
}
generate() {
const obj = {
[this._name]: {},
};
const subobj = {
field: this._field,
};
if (this._missing != null) {
subobj.missing = this._missing;
}
const cname = this.constructor.name.toLowerCase().replace('aggregation', '');
if (cname === 'valuecount') {
obj[this._name].value_count = subobj;
} else {
obj[this._name][cname] = subobj;
}
return obj;
}
}
class AvgAggregation extends SingleValueMetricAggregation {}
class MinAggregation extends SingleValueMetricAggregation {}
class MaxAggregation extends SingleValueMetricAggregation {}
class SumAggregation extends SingleValueMetricAggregation {}
class ValueCountAggregation extends SingleValueMetricAggregation {
missing() {
// Not existent for this aggregation
return this;
}
}
class CardinalityAggregation extends SingleValueMetricAggregation {
_precision_threshold: number;
constructor(name: string, object: Object = {}) {
super(name, object);
this._precision_threshold = 'precision_threshold' in object ? object.precision_threshold : 3000; // Default in ES;
}
precision_threshold(n: number) {
if (typeof n !== 'number') {
return this;
}
this._precision_threshold = n;
return this;
}
generate(): Object {
const obj = super.generate();
obj[this._name].cardinality.precision_threshold = this._precision_threshold;
return obj;
}
}
class MultiValueMetricAggregation extends SingleValueMetricAggregation {
}
class ExtendedStatsAggregation extends MultiValueMetricAggregation {
_sigma: ?number;
constructor(name: string, object: Object = {}) {
super(name, object);
this._sigma = 'sigma' in object ? object.sigma : null;
}
sigma(v: number): Aggregation {
this._sigma = v;
return this;
}
generate(): Object {
return this;
}
}
class StatsAggregation extends MultiValueMetricAggregation {
generate(): Object {
return this;
}
}
class PercentilesAggregation extends MultiValueMetricAggregation {
_percents: Array<number>;
_keyed: boolean;
_hdr_significant_value_digits: number;
_hdr: boolean;
constructor(name: string, object: Object = {}) {
super(name, object);
this._percents = 'percents' in object ? object.percents : [];
this._keyed = 'keyed' in object ? object.keyed : true;
this._hdr = 'hdr' in object;
this._hdr_significant_value_digits = 'hdr' in object
&& 'number_of_significant_value_digits' in object.hdr ? object.hdr.number_of_significant_value_digits : 3;
}
percents(arr: Array<number>): Aggregation {
this._percents = arr;
return this;
}
keyed(b: boolean): Aggregation {
this._keyed = b;
return this;
}
hdr_significant_digits(d: number): Aggregation {
this._hdr = true;
this._hdr_significant_value_digits = d;
return this;
}
generate(): Object {
return this;
}
}
class PercentileRanksAggregation extends PercentilesAggregation {
_values: Array<number>;
constructor(name: string, object: Object = {}) {
super(name, object);
this._values = 'values' in object ? object.values : [];
}
values(arr: Array<number>): Aggregation {
this._values = arr;
return this;
}
generate(): Object {
return this;
}
}
class BucketAggregation extends Aggregation {
_sub_aggregations: Array<Aggregation>;
_keyed: boolean;
constructor(name: string, object: Object = {}) {
super(name, object);
this._sub_aggregations = [];
this._keyed = 'keyed' in object ? object.keyed : false;
}
aggregation(agg: Aggregation) {
this._sub_aggregations.push(agg);
return this;
}
}
class NestedAggregation extends BucketAggregation {
_path: ?string;
constructor(name: string, object: Object = {}) {
super(name, object);
this._path = 'path' in object ? object.path : null;
}
path(p: string) {
this._path = p;
return this;
}
generate() {
return {
[this._name]: {
nested: {
path: this._path,
},
aggs: this._sub_aggregations.reduce((obj, agg) => {
obj = _.merge(obj, agg.generate());
return obj;
}, {}),
},
};
}
}
class FilterAggregation extends BucketAggregation {
_query: ?Object;
constructor(name: string, object: Object = {}) {
super(name, object);
this._query = null;
}
query(q: Object) {
this._query = q;
return this;
}
generate() {
return {
[this._name]: {
filter: this._query == null ? {} : this._query,
aggs: this._sub_aggregations.reduce((obj, agg) => {
obj = _.merge(obj, agg.generate());
return obj;
}, {}),
},
};
}
}
class TermsAggregation extends BucketAggregation {
_include: ?string | ?Array<string>;
_exclude: ?string | ?Array<string>;
_missing: any;
_size: number;
_shard_size: number;
_min_doc_count: number;
_shard_min_doc_count: number;
_order: ?Object;
constructor(name: string, object: Object = {}) {
super(name, object);
this._include = 'include' in object ? object.include : null;
this._exclude = 'exclude' in object ? object.exclude : null;
this._missing = 'missing' in object ? object.missing : null;
this._size = 'size' in object ? object.size : 10;
this._shard_size = 'shard_size' in object ? object.shard_size : this._size;
this._min_doc_count = 'min_doc_count' in object ?
object.min_doc_count : 1;
this._shard_min_doc_count = 'shard_min_doc_count' in object ?
object.shard_min_doc_count : 1;
// Check with an enum TODO
this._collect_mode = 'collect_mode' in object ? object.collect_mode : null;
this._order = 'order' in object ? this._extract_order(object.order) : null;
}
_extract_order(order: Object): ?Object {
if (order && Object.keys(order).length === 1) {
const keys = Object.keys(order);
const key = keys[0];
if (order[key] === 'desc' || order[key] === 'asc') {
return order;
}
return null;
}
return null;
}
include(inc: string | Array<string>) {
this._include = inc;
return this;
}
exclude(exc: string | Array<string>) {
this._exclude = exc;
return this;
}
missing(m: any) {
this._missing = m;
return this;
}
size(s: number) {
this._size = s;
return this;
}
shard_size(s: number) {
this._shard_size = s;
return this;
}
min_doc_count(dc: number) {
this._min_doc_count = dc;
return this;
}
shard_min_doc_count(dc: number) {
this._shard_min_doc_count = dc;
return this;
}
generate() {
const obj = {
[this._name]: {
terms: {
field: this._field,
},
},
};
obj[this._name].terms.size = this._size;
obj[this._name].terms.shard_size = this._shard_size;
obj[this._name].terms.shard_size = this._shard_size;
obj[this._name].terms.min_doc_count = this._min_doc_count;
obj[this._name].terms.shard_min_doc_count = this._shard_min_doc_count;
if (this._missing != null) {
obj[this._name].terms.missing = this._missing;
}
if (this._include != null) {
obj[this._name].terms.include = this._include;
}
if (this._exclude != null) {
obj[this._name].terms.exclude = this._exclude;
}
if (this._order != null) {
obj[this._name].terms.order = this._order;
}
if (this._sub_aggregations.length > 0) {
obj[this._name].aggs = {};
obj[this._name].aggs = this._sub_aggregations.reduce((o, agg) => {
o = _.merge(o, agg.generate());
return o;
}, obj[this._name].aggs);
}
return obj;
}
}
class DateHistogramAggregation extends BucketAggregation {
_timezone: ?string;
_offset: ?string;
_format: ?string;
_interval: ?string;
_missing: any;
_shard_size: number;
_min_doc_count: number;
_order: ?Object;
constructor(name: string, object: Object = {}) {
super(name, object);
this._missing = 'missing' in object ? object.missing : null;
this._shard_size = 'shard_size' in object ? object.shard_size : this._size;
this._min_doc_count = 'min_doc_count' in object ?
object.min_doc_count : 1;
this._format = 'format' in object ? object.format : null;
this._timezone = 'timezone' in object ? object.timezone : null;
this._interval = 'interval' in object ? object.interval : null;
this._offset = 'offset' in object ? object.offset : null;
this._order = 'order' in object ? this._extract_order(object.order) : null;
}
_extract_order(order: Object): ?Object {
if (order && Object.keys(order).length === 1) {
const keys = Object.keys(order);
const key = keys[0];
if (order[key] === 'desc' || order[key] === 'asc') {
return order;
}
return null;
}
return null;
}
missing(m: any) {
this._missing = m;
return this;
}
shard_size(s: number) {
this._shard_size = s;
return this;
}
min_doc_count(dc: number) {
this._min_doc_count = dc;
return this;
}
format(f: string): DateHistogramAggregation {
this._format = f;
return this;
}
timezone(tz: string): DateHistogramAggregation {
this._timezone = tz;
return this;
}
interval(inter: string): DateHistogramAggregation {
this._interval = inter;
return this;
}
order(o: ?Object): DateHistogramAggregation {
this._order = this._extract_order(o);
return this;
}
generate() {
const obj = {
[this._name]: {
date_histogram: {
field: this._field,
},
},
};
obj[this._name].date_histogram.shard_size = this._shard_size;
obj[this._name].date_histogram.shard_size = this._shard_size;
obj[this._name].date_histogram.min_doc_count = this._min_doc_count;
if (this._format) {
obj[this._name].date_histogram.format = this._format;
}
if (this._timezone) {
obj[this._name].date_histogram.time_zone = this._timezone;
}
if (this._interval) {
obj[this._name].date_histogram.interval = this._interval;
}
if (this._offset) {
obj[this._name].date_histogram.offset = this._offset;
}
if (this._missing != null) {
obj[this._name].date_histogram.missing = this._missing;
}
if (this._order != null) {
obj[this._name].date_histogram.order = this._order;
}
if (this._sub_aggregations.length > 0) {
obj[this._name].aggs = {};
obj[this._name].aggs = this._sub_aggregations.reduce((o, agg) => {
o = _.merge(o, agg.generate());
return o;
}, obj[this._name].aggs);
}
return obj;
}
}
module.exports = {
Aggregation,
BucketAggregation,
SingleValueMetricAggregation,
MultiValueMetricAggregation,
AvgAggregation,
MinAggregation,
MaxAggregation,
SumAggregation,
ValueCountAggregation,
CardinalityAggregation,
ExtendedStatsAggregation,
StatsAggregation,
PercentilesAggregation,
PercentileRanksAggregation,
NestedAggregation,
FilterAggregation,
TermsAggregation,
DateHistogramAggregation,
TopHitsAggregation,
};