-
Notifications
You must be signed in to change notification settings - Fork 0
/
aggregations.go
114 lines (99 loc) · 2.01 KB
/
aggregations.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package columns
import (
"fmt"
"math"
)
// Aggregation is the interface for describing a calculated value in a footer
type Aggregation interface {
AddValue(v interface{}) error
Name() string
Result() float64
}
// ErrInvalidType error for saying it's a value we can't "aggregate"
var ErrInvalidType = fmt.Errorf("not a numerical value")
func round(n float64, precision int) float64 {
decimals := math.Pow10(precision)
return math.Round(n*decimals) / decimals
}
func getNum(v interface{}) (float64, bool) {
switch n := v.(type) {
case float64:
return n, true
case float32:
return float64(n), true
case int64:
return float64(n), true
case int32:
return float64(n), true
case int16:
return float64(n), true
case int8:
return float64(n), true
case int:
return float64(n), true
case uint64:
return float64(n), true
case uint32:
return float64(n), true
case uint16:
return float64(n), true
case uint8:
return float64(n), true
case uint:
return float64(n), true
case bool:
if n {
return 1, true
}
return 0, true
}
return 0, false
}
// SUM
type aggSum struct {
precision int
value float64
}
// Sum creates an 'Aggregation' that 'sums' all valid values
func Sum(prec int) Aggregation {
return &aggSum{
precision: prec,
}
}
func (sum *aggSum) Name() string {
return "Sum"
}
func (sum *aggSum) Result() float64 {
return round(sum.value, sum.precision)
}
func (sum *aggSum) AddValue(v interface{}) error {
if n, ok := getNum(v); ok {
sum.value += n
}
return ErrInvalidType
}
// AVG
type aggAvg struct {
precision int
total float64
count int
}
// Avg creates an 'Aggregation' that 'averages' all valid values
func Avg(prec int) Aggregation {
return &aggAvg{
precision: prec,
}
}
func (avg *aggAvg) Name() string {
return "Average"
}
func (avg *aggAvg) Result() float64 {
return round(avg.total/float64(avg.count), avg.precision)
}
func (avg *aggAvg) AddValue(v interface{}) error {
if n, ok := getNum(v); ok {
avg.total += n
avg.count++
}
return ErrInvalidType
}