1package query 2 3import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 8 "github.com/influxdata/influxdb/models" 9 "github.com/influxdata/influxql" 10) 11 12const ( 13 // WarningLevel is the message level for a warning. 14 WarningLevel = "warning" 15) 16 17// TagSet is a fundamental concept within the query system. It represents a composite series, 18// composed of multiple individual series that share a set of tag attributes. 19type TagSet struct { 20 Tags map[string]string 21 Filters []influxql.Expr 22 SeriesKeys []string 23 Key []byte 24} 25 26// AddFilter adds a series-level filter to the Tagset. 27func (t *TagSet) AddFilter(key string, filter influxql.Expr) { 28 t.SeriesKeys = append(t.SeriesKeys, key) 29 t.Filters = append(t.Filters, filter) 30} 31 32func (t *TagSet) Len() int { return len(t.SeriesKeys) } 33func (t *TagSet) Less(i, j int) bool { return t.SeriesKeys[i] < t.SeriesKeys[j] } 34func (t *TagSet) Swap(i, j int) { 35 t.SeriesKeys[i], t.SeriesKeys[j] = t.SeriesKeys[j], t.SeriesKeys[i] 36 t.Filters[i], t.Filters[j] = t.Filters[j], t.Filters[i] 37} 38 39// Reverse reverses the order of series keys and filters in the TagSet. 40func (t *TagSet) Reverse() { 41 for i, j := 0, len(t.Filters)-1; i < j; i, j = i+1, j-1 { 42 t.Filters[i], t.Filters[j] = t.Filters[j], t.Filters[i] 43 t.SeriesKeys[i], t.SeriesKeys[j] = t.SeriesKeys[j], t.SeriesKeys[i] 44 } 45} 46 47// LimitTagSets returns a tag set list with SLIMIT and SOFFSET applied. 48func LimitTagSets(a []*TagSet, slimit, soffset int) []*TagSet { 49 // Ignore if no limit or offset is specified. 50 if slimit == 0 && soffset == 0 { 51 return a 52 } 53 54 // If offset is beyond the number of tag sets then return nil. 55 if soffset > len(a) { 56 return nil 57 } 58 59 // Clamp limit to the max number of tag sets. 60 if soffset+slimit > len(a) { 61 slimit = len(a) - soffset 62 } 63 return a[soffset : soffset+slimit] 64} 65 66// Message represents a user-facing message to be included with the result. 67type Message struct { 68 Level string `json:"level"` 69 Text string `json:"text"` 70} 71 72// ReadOnlyWarning generates a warning message that tells the user the command 73// they are using is being used for writing in a read only context. 74// 75// This is a temporary method while to be used while transitioning to read only 76// operations for issue #6290. 77func ReadOnlyWarning(stmt string) *Message { 78 return &Message{ 79 Level: WarningLevel, 80 Text: fmt.Sprintf("deprecated use of '%s' in a read only context, please use a POST request instead", stmt), 81 } 82} 83 84// Result represents a resultset returned from a single statement. 85// Rows represents a list of rows that can be sorted consistently by name/tag. 86type Result struct { 87 // StatementID is just the statement's position in the query. It's used 88 // to combine statement results if they're being buffered in memory. 89 StatementID int 90 Series models.Rows 91 Messages []*Message 92 Partial bool 93 Err error 94} 95 96// MarshalJSON encodes the result into JSON. 97func (r *Result) MarshalJSON() ([]byte, error) { 98 // Define a struct that outputs "error" as a string. 99 var o struct { 100 StatementID int `json:"statement_id"` 101 Series []*models.Row `json:"series,omitempty"` 102 Messages []*Message `json:"messages,omitempty"` 103 Partial bool `json:"partial,omitempty"` 104 Err string `json:"error,omitempty"` 105 } 106 107 // Copy fields to output struct. 108 o.StatementID = r.StatementID 109 o.Series = r.Series 110 o.Messages = r.Messages 111 o.Partial = r.Partial 112 if r.Err != nil { 113 o.Err = r.Err.Error() 114 } 115 116 return json.Marshal(&o) 117} 118 119// UnmarshalJSON decodes the data into the Result struct 120func (r *Result) UnmarshalJSON(b []byte) error { 121 var o struct { 122 StatementID int `json:"statement_id"` 123 Series []*models.Row `json:"series,omitempty"` 124 Messages []*Message `json:"messages,omitempty"` 125 Partial bool `json:"partial,omitempty"` 126 Err string `json:"error,omitempty"` 127 } 128 129 err := json.Unmarshal(b, &o) 130 if err != nil { 131 return err 132 } 133 r.StatementID = o.StatementID 134 r.Series = o.Series 135 r.Messages = o.Messages 136 r.Partial = o.Partial 137 if o.Err != "" { 138 r.Err = errors.New(o.Err) 139 } 140 return nil 141} 142