/
result.go
178 lines (157 loc) · 3.49 KB
/
result.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package graphite
import (
"strings"
)
type Result struct {
results []*Series
cursor int
curr *Series
}
type Series struct {
cursor int
curr *DataPoint
Name string
DataPoints []DataPoint
}
type DataPoint struct {
X, Y *float64
}
// NextItem can be called inside `for` and will populate the response to Current()
// Responds with true if a new Current() was found (hence you can call Current() to get it)
func (r *Result) Next() bool {
if r.cursor < len(r.results) {
r.curr = r.results[r.cursor]
} else {
r.curr = nil
}
r.cursor++
return r.curr != nil
}
// Current returns the current item within the iterator
func (r *Result) Current() *Series {
return r.curr
}
// Rewind takes the result set iterator back to the start
func (r *Result) Rewind() {
r.curr = nil
r.cursor = 0
}
// Count returns how many series we have within this results set
func (r *Result) Count() int {
return len(r.results)
}
// Target attempts to find the result for a particular target, returning nil if not found
func (r *Result) Target(s string) *Series {
for _, tr := range r.results {
if tr.Name == s {
return tr
}
}
return nil
}
// TargetLike attempts to find the result for a particular target, matching where the supplied
// string is _anywhere_ within the target name - eg: partial match. Returns nil if not found
// This will always return the _first_ thing found that matches, where multiple matches exist
func (r *Result) TargetLike(s string) *Series {
for _, tr := range r.results {
if strings.Contains(tr.Name, s) {
return tr
}
}
return nil
}
// TargetN returns the Nth results series, 0 indexed, or nil if out of bounds
func (r *Result) TargetN(i int) *Series {
if i < 0 || i >= len(r.results) {
return nil
}
return r.results[i]
}
// Len returns how many data points in a series
func (tr *Series) Len() int {
if tr == nil {
return 0
}
return len(tr.DataPoints)
}
// Sum will aggregate all Y values from data points within the series
func (tr *Series) Sum() float64 {
if tr == nil {
return 0.0
}
var r float64
for _, dp := range tr.DataPoints {
if dp.Y == nil {
continue
}
r += *dp.Y
}
return r
}
// Max finds the maximum Y value from the data points within the series
// Will return 0 if no datapoints
func (tr *Series) Max() float64 {
if tr == nil {
return 0.0
}
var r float64
for _, dp := range tr.DataPoints {
if dp.Y == nil {
continue
}
if *dp.Y > r {
r = *dp.Y
}
}
return r
}
// Min finds the minimunm Y value from the data points within the series
// Will return 0 if no datapoints
func (tr *Series) Min() float64 {
if tr == nil {
return 0.0
}
var (
r float64
first bool = true
)
for _, dp := range tr.DataPoints {
if dp.Y == nil {
continue
}
if first || *dp.Y < r {
r = *dp.Y
first = false
}
}
return r
}
// NextItem can be called inside `for` and will populate the response to Current()
// Responds with true if a new Current() was found (hence you can call Current() to get it)
func (tr *Series) Next() bool {
if tr == nil {
return false
}
if tr.cursor < len(tr.DataPoints) {
tr.curr = &tr.DataPoints[tr.cursor]
} else {
tr.curr = nil
}
tr.cursor++
return tr.curr != nil
}
// Current returns the current data point within the iterator
func (tr *Series) Current() DataPoint {
if tr == nil || tr.curr == nil {
return DataPoint{}
}
return *tr.curr
}
// Rewind takes the result set iterator back to the start
func (tr *Series) Rewind() {
if tr == nil {
return
}
tr.curr = nil
tr.cursor = 0
}