1// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
2// Use of this source code is governed by a MIT-license.
3// See http://olivere.mit-license.org/license.txt for details.
4
5package elastic
6
7// DateHistogramAggregation is a multi-bucket aggregation similar to the
8// histogram except it can only be applied on date values.
9// See: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html
10type DateHistogramAggregation struct {
11	field           string
12	script          string
13	scriptFile      string
14	lang            string
15	params          map[string]interface{}
16	subAggregations map[string]Aggregation
17
18	interval                   string
19	order                      string
20	orderAsc                   bool
21	minDocCount                *int64
22	extendedBoundsMin          interface{}
23	extendedBoundsMax          interface{}
24	preZone                    string
25	postZone                   string
26	preZoneAdjustLargeInterval *bool
27	format                     string
28	preOffset                  int64
29	postOffset                 int64
30	factor                     *float32
31}
32
33func NewDateHistogramAggregation() DateHistogramAggregation {
34	a := DateHistogramAggregation{
35		params:          make(map[string]interface{}),
36		subAggregations: make(map[string]Aggregation),
37	}
38	return a
39}
40
41func (a DateHistogramAggregation) Field(field string) DateHistogramAggregation {
42	a.field = field
43	return a
44}
45
46func (a DateHistogramAggregation) Script(script string) DateHistogramAggregation {
47	a.script = script
48	return a
49}
50
51func (a DateHistogramAggregation) ScriptFile(scriptFile string) DateHistogramAggregation {
52	a.scriptFile = scriptFile
53	return a
54}
55
56func (a DateHistogramAggregation) Lang(lang string) DateHistogramAggregation {
57	a.lang = lang
58	return a
59}
60
61func (a DateHistogramAggregation) Param(name string, value interface{}) DateHistogramAggregation {
62	a.params[name] = value
63	return a
64}
65
66func (a DateHistogramAggregation) SubAggregation(name string, subAggregation Aggregation) DateHistogramAggregation {
67	a.subAggregations[name] = subAggregation
68	return a
69}
70
71// Allowed values are: "year", "quarter", "month", "week", "day",
72// "hour", "minute". It also supports time settings like "1.5h"
73// (up to "w" for weeks).
74func (a DateHistogramAggregation) Interval(interval string) DateHistogramAggregation {
75	a.interval = interval
76	return a
77}
78
79// Order specifies the sort order. Valid values for order are:
80// "_key", "_count", a sub-aggregation name, or a sub-aggregation name
81// with a metric.
82func (a DateHistogramAggregation) Order(order string, asc bool) DateHistogramAggregation {
83	a.order = order
84	a.orderAsc = asc
85	return a
86}
87
88func (a DateHistogramAggregation) OrderByCount(asc bool) DateHistogramAggregation {
89	// "order" : { "_count" : "asc" }
90	a.order = "_count"
91	a.orderAsc = asc
92	return a
93}
94
95func (a DateHistogramAggregation) OrderByCountAsc() DateHistogramAggregation {
96	return a.OrderByCount(true)
97}
98
99func (a DateHistogramAggregation) OrderByCountDesc() DateHistogramAggregation {
100	return a.OrderByCount(false)
101}
102
103func (a DateHistogramAggregation) OrderByKey(asc bool) DateHistogramAggregation {
104	// "order" : { "_key" : "asc" }
105	a.order = "_key"
106	a.orderAsc = asc
107	return a
108}
109
110func (a DateHistogramAggregation) OrderByKeyAsc() DateHistogramAggregation {
111	return a.OrderByKey(true)
112}
113
114func (a DateHistogramAggregation) OrderByKeyDesc() DateHistogramAggregation {
115	return a.OrderByKey(false)
116}
117
118// OrderByAggregation creates a bucket ordering strategy which sorts buckets
119// based on a single-valued calc get.
120func (a DateHistogramAggregation) OrderByAggregation(aggName string, asc bool) DateHistogramAggregation {
121	// {
122	//     "aggs" : {
123	//         "genders" : {
124	//             "terms" : {
125	//                 "field" : "gender",
126	//                 "order" : { "avg_height" : "desc" }
127	//             },
128	//             "aggs" : {
129	//                 "avg_height" : { "avg" : { "field" : "height" } }
130	//             }
131	//         }
132	//     }
133	// }
134	a.order = aggName
135	a.orderAsc = asc
136	return a
137}
138
139// OrderByAggregationAndMetric creates a bucket ordering strategy which
140// sorts buckets based on a multi-valued calc get.
141func (a DateHistogramAggregation) OrderByAggregationAndMetric(aggName, metric string, asc bool) DateHistogramAggregation {
142	// {
143	//     "aggs" : {
144	//         "genders" : {
145	//             "terms" : {
146	//                 "field" : "gender",
147	//                 "order" : { "height_stats.avg" : "desc" }
148	//             },
149	//             "aggs" : {
150	//                 "height_stats" : { "stats" : { "field" : "height" } }
151	//             }
152	//         }
153	//     }
154	// }
155	a.order = aggName + "." + metric
156	a.orderAsc = asc
157	return a
158}
159
160func (a DateHistogramAggregation) MinDocCount(minDocCount int64) DateHistogramAggregation {
161	a.minDocCount = &minDocCount
162	return a
163}
164
165func (a DateHistogramAggregation) PreZone(preZone string) DateHistogramAggregation {
166	a.preZone = preZone
167	return a
168}
169
170func (a DateHistogramAggregation) PostZone(postZone string) DateHistogramAggregation {
171	a.postZone = postZone
172	return a
173}
174
175func (a DateHistogramAggregation) PreZoneAdjustLargeInterval(preZoneAdjustLargeInterval bool) DateHistogramAggregation {
176	a.preZoneAdjustLargeInterval = &preZoneAdjustLargeInterval
177	return a
178}
179
180func (a DateHistogramAggregation) PreOffset(preOffset int64) DateHistogramAggregation {
181	a.preOffset = preOffset
182	return a
183}
184
185func (a DateHistogramAggregation) PostOffset(postOffset int64) DateHistogramAggregation {
186	a.postOffset = postOffset
187	return a
188}
189
190func (a DateHistogramAggregation) Factor(factor float32) DateHistogramAggregation {
191	a.factor = &factor
192	return a
193}
194
195func (a DateHistogramAggregation) Format(format string) DateHistogramAggregation {
196	a.format = format
197	return a
198}
199
200// ExtendedBoundsMin accepts int, int64, string, or time.Time values.
201func (a DateHistogramAggregation) ExtendedBoundsMin(min interface{}) DateHistogramAggregation {
202	a.extendedBoundsMin = min
203	return a
204}
205
206// ExtendedBoundsMax accepts int, int64, string, or time.Time values.
207func (a DateHistogramAggregation) ExtendedBoundsMax(max interface{}) DateHistogramAggregation {
208	a.extendedBoundsMax = max
209	return a
210}
211
212func (a DateHistogramAggregation) Source() interface{} {
213	// Example:
214	// {
215	//     "aggs" : {
216	//         "articles_over_time" : {
217	//             "date_histogram" : {
218	//                 "field" : "date",
219	//                 "interval" : "month"
220	//             }
221	//         }
222	//     }
223	// }
224	//
225	// This method returns only the { "date_histogram" : { ... } } part.
226
227	source := make(map[string]interface{})
228	opts := make(map[string]interface{})
229	source["date_histogram"] = opts
230
231	// ValuesSourceAggregationBuilder
232	if a.field != "" {
233		opts["field"] = a.field
234	}
235	if a.script != "" {
236		opts["script"] = a.script
237	}
238	if a.scriptFile != "" {
239		opts["script_file"] = a.scriptFile
240	}
241	if a.lang != "" {
242		opts["lang"] = a.lang
243	}
244	if len(a.params) > 0 {
245		opts["params"] = a.params
246	}
247
248	opts["interval"] = a.interval
249	if a.minDocCount != nil {
250		opts["min_doc_count"] = *a.minDocCount
251	}
252	if a.order != "" {
253		o := make(map[string]interface{})
254		if a.orderAsc {
255			o[a.order] = "asc"
256		} else {
257			o[a.order] = "desc"
258		}
259		opts["order"] = o
260	}
261	if a.preZone != "" {
262		opts["pre_zone"] = a.preZone
263	}
264	if a.postZone != "" {
265		opts["post_zone"] = a.postZone
266	}
267	if a.preZoneAdjustLargeInterval != nil {
268		opts["pre_zone_adjust_large_interval"] = *a.preZoneAdjustLargeInterval
269	}
270	if a.preOffset != 0 {
271		opts["pre_offset"] = a.preOffset
272	}
273	if a.postOffset != 0 {
274		opts["post_offset"] = a.postOffset
275	}
276	if a.factor != nil {
277		opts["factor"] = *a.factor
278	}
279	if a.format != "" {
280		opts["format"] = a.format
281	}
282	if a.extendedBoundsMin != nil || a.extendedBoundsMax != nil {
283		bounds := make(map[string]interface{})
284		if a.extendedBoundsMin != nil {
285			bounds["min"] = a.extendedBoundsMin
286		}
287		if a.extendedBoundsMax != nil {
288			bounds["max"] = a.extendedBoundsMax
289		}
290		opts["extended_bounds"] = bounds
291	}
292
293	// AggregationBuilder (SubAggregations)
294	if len(a.subAggregations) > 0 {
295		aggsMap := make(map[string]interface{})
296		source["aggregations"] = aggsMap
297		for name, aggregate := range a.subAggregations {
298			aggsMap[name] = aggregate.Source()
299		}
300	}
301
302	return source
303}
304