1// Copyright 2012-present 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.
4package elastic
5
6// ScriptedMetricAggregation is a a metric aggregation that executes using scripts to provide a metric output.
7//
8// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-scripted-metric-aggregation.html
9type ScriptedMetricAggregation struct {
10	initScript    *Script
11	mapScript     *Script
12	combineScript *Script
13	reduceScript  *Script
14
15	params map[string]interface{}
16	meta   map[string]interface{}
17}
18
19func NewScriptedMetricAggregation() *ScriptedMetricAggregation {
20	a := &ScriptedMetricAggregation{}
21	return a
22}
23
24func (a *ScriptedMetricAggregation) InitScript(script *Script) *ScriptedMetricAggregation {
25	a.initScript = script
26	return a
27}
28
29func (a *ScriptedMetricAggregation) MapScript(script *Script) *ScriptedMetricAggregation {
30	a.mapScript = script
31	return a
32}
33
34func (a *ScriptedMetricAggregation) CombineScript(script *Script) *ScriptedMetricAggregation {
35	a.combineScript = script
36	return a
37}
38
39func (a *ScriptedMetricAggregation) ReduceScript(script *Script) *ScriptedMetricAggregation {
40	a.reduceScript = script
41	return a
42}
43
44func (a *ScriptedMetricAggregation) Params(params map[string]interface{}) *ScriptedMetricAggregation {
45	a.params = params
46	return a
47}
48
49// Meta sets the meta data to be included in the aggregation response.
50func (a *ScriptedMetricAggregation) Meta(metaData map[string]interface{}) *ScriptedMetricAggregation {
51	a.meta = metaData
52	return a
53}
54
55func (a *ScriptedMetricAggregation) Source() (interface{}, error) {
56	// Example:
57	//	{
58	//    "aggs" : {
59	//      "magic_script" : { "scripted_metric" : {
60	//  		"init_script" : "state.transactions = []",
61	//		  	"map_script" : "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
62	//		  	"combine_script" : "double profit = 0; for (t in state.transactions) { profit += t } return profit",
63	//		  	"reduce_script" : "double profit = 0; for (a in states) { profit += a } return profit"
64	//      } }
65	//    }
66	//	}
67	// This method returns only the { "scripted_metric" : { ... } } part.
68
69	source := make(map[string]interface{})
70	opts := make(map[string]interface{})
71	source["scripted_metric"] = opts
72
73	if a.initScript != nil {
74		src, err := a.initScript.Source()
75		if err != nil {
76			return nil, err
77		}
78		opts["init_script"] = src
79	}
80	if a.mapScript != nil {
81		src, err := a.mapScript.Source()
82		if err != nil {
83			return nil, err
84		}
85		opts["map_script"] = src
86	}
87	if a.combineScript != nil {
88		src, err := a.combineScript.Source()
89		if err != nil {
90			return nil, err
91		}
92		opts["combine_script"] = src
93	}
94	if a.reduceScript != nil {
95		src, err := a.reduceScript.Source()
96		if err != nil {
97			return nil, err
98		}
99		opts["reduce_script"] = src
100	}
101
102	if a.params != nil && len(a.params) > 0 {
103		opts["params"] = a.params
104	}
105
106	// Add Meta data if available
107	if len(a.meta) > 0 {
108		source["meta"] = a.meta
109	}
110
111	return source, nil
112}
113