202 lines
5.4 KiB
Go
202 lines
5.4 KiB
Go
package cursors
|
|
|
|
import (
|
|
"github.com/influxdata/influxdb/v2/models"
|
|
"github.com/influxdata/influxql"
|
|
)
|
|
|
|
// FieldType represents the primitive field data types available in tsm.
|
|
type FieldType int
|
|
|
|
const (
|
|
Float FieldType = iota // means the data type is a float
|
|
Integer // means the data type is an integer
|
|
Unsigned // means the data type is an unsigned integer
|
|
String // means the data type is a string of text
|
|
Boolean // means the data type is a boolean
|
|
Undefined // means the data type in unknown or undefined
|
|
)
|
|
|
|
var (
|
|
fieldTypeToDataTypeMapping = [8]influxql.DataType{
|
|
Float: influxql.Float,
|
|
Integer: influxql.Integer,
|
|
Unsigned: influxql.Unsigned,
|
|
String: influxql.String,
|
|
Boolean: influxql.Boolean,
|
|
Undefined: influxql.Unknown,
|
|
6: influxql.Unknown,
|
|
7: influxql.Unknown,
|
|
}
|
|
)
|
|
|
|
// FieldTypeToDataType returns the equivalent influxql DataType for the field type ft.
|
|
// If ft is an invalid FieldType, the results are undefined.
|
|
func FieldTypeToDataType(ft FieldType) influxql.DataType {
|
|
return fieldTypeToDataTypeMapping[ft&7]
|
|
}
|
|
|
|
// IsLower returns true if the other FieldType has greater precedence than the
|
|
// current value. Undefined has the lowest precedence.
|
|
func (ft FieldType) IsLower(other FieldType) bool { return other < ft }
|
|
|
|
var (
|
|
modelsFieldTypeToFieldTypeMapping = [8]FieldType{
|
|
models.Integer: Integer,
|
|
models.Float: Float,
|
|
models.Boolean: Boolean,
|
|
models.String: String,
|
|
models.Empty: Undefined,
|
|
models.Unsigned: Unsigned,
|
|
6: Undefined,
|
|
7: Undefined,
|
|
}
|
|
)
|
|
|
|
// ModelsFieldTypeToFieldType returns the equivalent FieldType for ft.
|
|
// If ft is an invalid FieldType, the results are undefined.
|
|
func ModelsFieldTypeToFieldType(ft models.FieldType) FieldType {
|
|
return modelsFieldTypeToFieldTypeMapping[ft&7]
|
|
}
|
|
|
|
type MeasurementField struct {
|
|
Key string // Key is the name of the field
|
|
Type FieldType // Type is field type
|
|
Timestamp int64 // Timestamp refers to the maximum timestamp observed for the given field
|
|
}
|
|
|
|
// MeasurementFieldSlice implements sort.Interface and sorts
|
|
// the slice from lowest to highest precedence. Use sort.Reverse
|
|
// to sort from highest to lowest.
|
|
type MeasurementFieldSlice []MeasurementField
|
|
|
|
func (m MeasurementFieldSlice) Len() int {
|
|
return len(m)
|
|
}
|
|
|
|
func (m MeasurementFieldSlice) Less(i, j int) bool {
|
|
ii, jj := &m[i], &m[j]
|
|
return ii.Key < jj.Key ||
|
|
(ii.Key == jj.Key &&
|
|
(ii.Timestamp < jj.Timestamp ||
|
|
(ii.Timestamp == jj.Timestamp && ii.Type.IsLower(jj.Type))))
|
|
}
|
|
|
|
func (m MeasurementFieldSlice) Swap(i, j int) {
|
|
m[i], m[j] = m[j], m[i]
|
|
}
|
|
|
|
// UniqueByKey performs an in-place update of m, removing duplicate elements
|
|
// by Key, keeping the first occurrence of each. If the slice is not sorted,
|
|
// the behavior of UniqueByKey is undefined.
|
|
func (m *MeasurementFieldSlice) UniqueByKey() {
|
|
mm := *m
|
|
if len(mm) < 2 {
|
|
return
|
|
}
|
|
|
|
j := 0
|
|
for i := 1; i < len(mm); i++ {
|
|
if mm[j].Key != mm[i].Key {
|
|
j++
|
|
if j != i {
|
|
// optimization: skip copy if j == i
|
|
mm[j] = mm[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
*m = mm[:j+1]
|
|
}
|
|
|
|
type MeasurementFields struct {
|
|
Fields []MeasurementField
|
|
}
|
|
|
|
type MeasurementFieldsIterator interface {
|
|
// Next advances the iterator to the next value. It returns false
|
|
// when there are no more values.
|
|
Next() bool
|
|
|
|
// Value returns the current value.
|
|
Value() MeasurementFields
|
|
|
|
Stats() CursorStats
|
|
}
|
|
|
|
// EmptyMeasurementFieldsIterator is an implementation of MeasurementFieldsIterator that returns
|
|
// no values.
|
|
var EmptyMeasurementFieldsIterator = &measurementFieldsIterator{}
|
|
|
|
type measurementFieldsIterator struct{}
|
|
|
|
func (m *measurementFieldsIterator) Next() bool { return false }
|
|
func (m *measurementFieldsIterator) Value() MeasurementFields { return MeasurementFields{} }
|
|
func (m *measurementFieldsIterator) Stats() CursorStats { return CursorStats{} }
|
|
|
|
type MeasurementFieldsSliceIterator struct {
|
|
f []MeasurementFields
|
|
v MeasurementFields
|
|
i int
|
|
stats CursorStats
|
|
}
|
|
|
|
func NewMeasurementFieldsSliceIterator(f []MeasurementFields) *MeasurementFieldsSliceIterator {
|
|
return &MeasurementFieldsSliceIterator{f: f}
|
|
}
|
|
|
|
func NewMeasurementFieldsSliceIteratorWithStats(f []MeasurementFields, stats CursorStats) *MeasurementFieldsSliceIterator {
|
|
return &MeasurementFieldsSliceIterator{f: f, stats: stats}
|
|
}
|
|
|
|
func (s *MeasurementFieldsSliceIterator) Next() bool {
|
|
if s.i < len(s.f) {
|
|
s.v = s.f[s.i]
|
|
s.i++
|
|
return true
|
|
}
|
|
s.v = MeasurementFields{}
|
|
return false
|
|
}
|
|
|
|
func (s *MeasurementFieldsSliceIterator) Value() MeasurementFields {
|
|
return s.v
|
|
}
|
|
|
|
func (s *MeasurementFieldsSliceIterator) Stats() CursorStats {
|
|
return s.stats
|
|
}
|
|
|
|
func (s *MeasurementFieldsSliceIterator) toSlice() []MeasurementFields {
|
|
if s.i < len(s.f) {
|
|
return s.f[s.i:]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MeasurementFieldsIteratorFlatMap reads the remainder of i, flattening the results
|
|
// to a single slice.
|
|
func MeasurementFieldsIteratorFlatMap(i MeasurementFieldsIterator) []MeasurementField {
|
|
if i == nil {
|
|
return nil
|
|
}
|
|
|
|
var res []MeasurementField
|
|
if si, ok := i.(*MeasurementFieldsSliceIterator); ok {
|
|
s := si.toSlice()
|
|
sz := 0
|
|
for i := range s {
|
|
sz += len(s[i].Fields)
|
|
}
|
|
res = make([]MeasurementField, 0, sz)
|
|
for i := range s {
|
|
res = append(res, s[i].Fields...)
|
|
}
|
|
} else {
|
|
for i.Next() {
|
|
res = append(res, i.Value().Fields...)
|
|
}
|
|
}
|
|
return res
|
|
}
|