1// Copyright 2020-2021 InfluxData, Inc. All rights reserved. 2// Use of this source code is governed by MIT 3// license that can be found in the LICENSE file. 4 5// Package query defined types for representing flux query result 6package query 7 8import ( 9 "fmt" 10 "strings" 11 "time" 12) 13 14// FluxTableMetadata holds flux query result table information represented by collection of columns. 15// Each new table is introduced by annotations 16type FluxTableMetadata struct { 17 position int 18 columns []*FluxColumn 19} 20 21// FluxColumn holds flux query table column properties 22type FluxColumn struct { 23 index int 24 name string 25 dataType string 26 group bool 27 defaultValue string 28} 29 30// FluxRecord represents row in the flux query result table 31type FluxRecord struct { 32 table int 33 values map[string]interface{} 34} 35 36// NewFluxTableMetadata creates FluxTableMetadata for the table on position 37func NewFluxTableMetadata(position int) *FluxTableMetadata { 38 return NewFluxTableMetadataFull(position, make([]*FluxColumn, 0, 10)) 39} 40 41// NewFluxTableMetadataFull creates FluxTableMetadata 42func NewFluxTableMetadataFull(position int, columns []*FluxColumn) *FluxTableMetadata { 43 return &FluxTableMetadata{position: position, columns: columns} 44} 45 46// Position returns position of the table in the flux query result 47func (f *FluxTableMetadata) Position() int { 48 return f.position 49} 50 51// Columns returns slice of flux query result table 52func (f *FluxTableMetadata) Columns() []*FluxColumn { 53 return f.columns 54} 55 56// AddColumn adds column definition to table metadata 57func (f *FluxTableMetadata) AddColumn(column *FluxColumn) *FluxTableMetadata { 58 f.columns = append(f.columns, column) 59 return f 60} 61 62// Column returns flux table column by index. 63// Returns nil if index is out of the bounds. 64func (f *FluxTableMetadata) Column(index int) *FluxColumn { 65 if len(f.columns) == 0 || index < 0 || index >= len(f.columns) { 66 return nil 67 } 68 return f.columns[index] 69} 70 71// String returns FluxTableMetadata string dump 72func (f *FluxTableMetadata) String() string { 73 var buffer strings.Builder 74 for i, c := range f.columns { 75 if i > 0 { 76 buffer.WriteString(",") 77 } 78 buffer.WriteString("col") 79 buffer.WriteString(c.String()) 80 } 81 return buffer.String() 82} 83 84// NewFluxColumn creates FluxColumn for position 85func NewFluxColumn(index int) *FluxColumn { 86 return &FluxColumn{index: index} 87} 88 89// NewFluxColumnFull creates FluxColumn 90func NewFluxColumnFull(dataType string, defaultValue string, name string, group bool, index int) *FluxColumn { 91 return &FluxColumn{index: index, name: name, dataType: dataType, group: group, defaultValue: defaultValue} 92} 93 94// SetDefaultValue sets default value for the column 95func (f *FluxColumn) SetDefaultValue(defaultValue string) { 96 f.defaultValue = defaultValue 97} 98 99// SetGroup set group flag for the column 100func (f *FluxColumn) SetGroup(group bool) { 101 f.group = group 102} 103 104// SetDataType sets data type for the column 105func (f *FluxColumn) SetDataType(dataType string) { 106 f.dataType = dataType 107} 108 109// SetName sets name of the column 110func (f *FluxColumn) SetName(name string) { 111 f.name = name 112} 113 114// DefaultValue returns default value of the column 115func (f *FluxColumn) DefaultValue() string { 116 return f.defaultValue 117} 118 119// IsGroup return true if the column is grouping column 120func (f *FluxColumn) IsGroup() bool { 121 return f.group 122} 123 124// DataType returns data type of the column 125func (f *FluxColumn) DataType() string { 126 return f.dataType 127} 128 129// Name returns name of the column 130func (f *FluxColumn) Name() string { 131 return f.name 132} 133 134// Index returns index of the column 135func (f *FluxColumn) Index() int { 136 return f.index 137} 138 139// String returns FluxColumn string dump 140func (f *FluxColumn) String() string { 141 return fmt.Sprintf("{%d: name: %s, datatype: %s, defaultValue: %s, group: %v}", f.index, f.name, f.dataType, f.defaultValue, f.group) 142} 143 144// NewFluxRecord returns new record for the table with values 145func NewFluxRecord(table int, values map[string]interface{}) *FluxRecord { 146 return &FluxRecord{table: table, values: values} 147} 148 149// Table returns index of the table record belongs to 150func (r *FluxRecord) Table() int { 151 return r.table 152} 153 154// Start returns the inclusive lower time bound of all records in the current table. 155// Returns empty time.Time if there is no column "_start". 156func (r *FluxRecord) Start() time.Time { 157 return timeValue(r.values, "_start") 158} 159 160// Stop returns the exclusive upper time bound of all records in the current table. 161// Returns empty time.Time if there is no column "_stop". 162func (r *FluxRecord) Stop() time.Time { 163 return timeValue(r.values, "_stop") 164} 165 166// Time returns the time of the record. 167// Returns empty time.Time if there is no column "_time". 168func (r *FluxRecord) Time() time.Time { 169 return timeValue(r.values, "_time") 170} 171 172// Value returns the default _value column value or nil if not present 173func (r *FluxRecord) Value() interface{} { 174 return r.ValueByKey("_value") 175} 176 177// Field returns the field name. 178// Returns empty string if there is no column "_field". 179func (r *FluxRecord) Field() string { 180 return stringValue(r.values, "_field") 181} 182 183// Result returns the value of the _result column, which represents result name. 184// Returns empty string if there is no column "result". 185func (r *FluxRecord) Result() string { 186 return stringValue(r.values, "result") 187} 188 189// Measurement returns the measurement name of the record 190// Returns empty string if there is no column "_measurement". 191func (r *FluxRecord) Measurement() string { 192 return stringValue(r.values, "_measurement") 193} 194 195// Values returns map of the values where key is the column name 196func (r *FluxRecord) Values() map[string]interface{} { 197 return r.values 198} 199 200// ValueByKey returns value for given column key for the record or nil of result has no value the column key 201func (r *FluxRecord) ValueByKey(key string) interface{} { 202 return r.values[key] 203} 204 205// String returns FluxRecord string dump 206func (r *FluxRecord) String() string { 207 var buffer strings.Builder 208 i := 0 209 for k, v := range r.values { 210 if i > 0 { 211 buffer.WriteString(",") 212 } 213 buffer.WriteString(fmt.Sprintf("%s:%v", k, v)) 214 i++ 215 } 216 return buffer.String() 217} 218 219// timeValue returns time.Time value from values map according to the key 220// Empty time.Time value is returned if key is not found 221func timeValue(values map[string]interface{}, key string) time.Time { 222 if val, ok := values[key]; ok { 223 if t, ok := val.(time.Time); ok { 224 return t 225 } 226 } 227 return time.Time{} 228} 229 230// timeValue returns string value from values map according to the key 231// Empty string is returned if key is not found 232func stringValue(values map[string]interface{}, key string) string { 233 if val, ok := values[key]; ok { 234 if s, ok := val.(string); ok { 235 return s 236 } 237 } 238 return "" 239} 240