forked from influxdata/kapacitor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
query.go
143 lines (128 loc) · 3.01 KB
/
query.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
package kapacitor
import (
"fmt"
"time"
"github.com/influxdata/influxdb/influxql"
"github.com/influxdata/kapacitor/tick"
)
type Query struct {
startTL *influxql.TimeLiteral
stopTL *influxql.TimeLiteral
stmt *influxql.SelectStatement
}
func NewQuery(q string) (*Query, error) {
query := &Query{}
// Parse and validate query
stmt, err := influxql.ParseStatement(q)
if err != nil {
return nil, err
}
var ok bool
query.stmt, ok = stmt.(*influxql.SelectStatement)
if !ok {
return nil, fmt.Errorf("query is not a select statement %q", q)
}
// Add in time condition nodes
query.startTL = &influxql.TimeLiteral{}
startExpr := &influxql.BinaryExpr{
Op: influxql.GTE,
LHS: &influxql.VarRef{Val: "time"},
RHS: query.startTL,
}
query.stopTL = &influxql.TimeLiteral{}
stopExpr := &influxql.BinaryExpr{
Op: influxql.LT,
LHS: &influxql.VarRef{Val: "time"},
RHS: query.stopTL,
}
if query.stmt.Condition != nil {
query.stmt.Condition = &influxql.BinaryExpr{
Op: influxql.AND,
LHS: query.stmt.Condition,
RHS: &influxql.BinaryExpr{
Op: influxql.AND,
LHS: startExpr,
RHS: stopExpr,
},
}
} else {
query.stmt.Condition = &influxql.BinaryExpr{
Op: influxql.AND,
LHS: startExpr,
RHS: stopExpr,
}
}
return query, nil
}
// Return the db rp pairs of the query
func (q *Query) DBRPs() ([]DBRP, error) {
dbrps := make([]DBRP, len(q.stmt.Sources))
for i, s := range q.stmt.Sources {
m, ok := s.(*influxql.Measurement)
if !ok {
return nil, fmt.Errorf("unknown query source %T", s)
}
dbrps[i] = DBRP{
Database: m.Database,
RetentionPolicy: m.RetentionPolicy,
}
}
return dbrps, nil
}
// Set the start time of the query
func (q *Query) Start(s time.Time) {
q.startTL.Val = s
}
// Set the stop time of the query
func (q *Query) Stop(s time.Time) {
q.stopTL.Val = s
}
// Set the dimensions on the query
func (q *Query) Dimensions(dims []interface{}) error {
q.stmt.Dimensions = q.stmt.Dimensions[:0]
// Add in dimensions
hasTime := false
for _, d := range dims {
switch dim := d.(type) {
case time.Duration:
if hasTime {
return fmt.Errorf("groupBy cannot have more than one time dimension")
}
// Add time dimension
hasTime = true
q.stmt.Dimensions = append(q.stmt.Dimensions,
&influxql.Dimension{
Expr: &influxql.Call{
Name: "time",
Args: []influxql.Expr{
&influxql.DurationLiteral{
Val: dim,
},
},
},
})
case string:
q.stmt.Dimensions = append(q.stmt.Dimensions,
&influxql.Dimension{
Expr: &influxql.VarRef{
Val: dim,
},
})
case *tick.StarNode:
q.stmt.Dimensions = append(q.stmt.Dimensions,
&influxql.Dimension{
Expr: &influxql.Wildcard{},
})
default:
return fmt.Errorf("invalid dimension type:%T, must be string or time.Duration", d)
}
}
return nil
}
func (q *Query) Fill(option influxql.FillOption, value interface{}) {
q.stmt.Fill = option
q.stmt.FillValue = value
}
func (q *Query) String() string {
return q.stmt.String()
}