Skip to content

Commit

Permalink
chore: refactor DataToPoint
Browse files Browse the repository at this point in the history
  • Loading branch information
sranka committed Nov 28, 2023
1 parent 1342ca6 commit 496f4bc
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 78 deletions.
86 changes: 86 additions & 0 deletions api/data_to_point.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package api

import (
"fmt"
"reflect"
"strings"
"time"

"github.com/influxdata/influxdb-client-go/v2/api/write"
)

// DataToPoint converts custom point structures into a Point.
// Each visible field of the point on input must be annotated with
// 'lp' prefix and values measurement,tag, field or timestamp.
// Valid point must contain measurement and at least one field.
//
// A field with timestamp must be of a type time.Time
//
// type TemperatureSensor struct {
// Measurement string `lp:"measurement"`
// Sensor string `lp:"tag,sensor"`
// ID string `lp:"tag,device_id"`
// Temp float64 `lp:"field,temperature"`
// Hum int `lp:"field,humidity"`
// Time time.Time `lp:"timestamp,temperature"`
// Description string `lp:"-"`
// }
func DataToPoint(x interface{}) (*write.Point, error) {
if err := checkContainerType(x, false, "point"); err != nil {
return nil, err
}
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
if t.Kind() == reflect.Ptr {
t = t.Elem()
v = v.Elem()
}
fields := reflect.VisibleFields(t)

var measurement string = ""
var lpTags = make(map[string]string)
var lpFields = make(map[string]interface{})
var lpTime time.Time

for _, f := range fields {
name := f.Name
if tag, ok := f.Tag.Lookup("lp"); ok {
if tag == "-" {
continue
}
parts := strings.Split(tag, ",")
if len(parts) > 2 {
return nil, fmt.Errorf("multiple tag attributes are not supported")
}
typ := parts[0]
if len(parts) == 2 {
name = parts[1]
}
switch typ {
case "measurement":
if measurement != "" {
return nil, fmt.Errorf("multiple measurement fields")
}
measurement = v.FieldByIndex(f.Index).String()
case "tag":
lpTags[name] = v.FieldByIndex(f.Index).String()
case "field":
lpFields[name] = v.FieldByIndex(f.Index).Interface()
case "timestamp":
if f.Type != timeType {
return nil, fmt.Errorf("cannot use field '%s' as a timestamp", f.Name)
}
lpTime = v.FieldByIndex(f.Index).Interface().(time.Time)
default:
return nil, fmt.Errorf("invalid tag %s", typ)
}
}
}
if measurement == "" {
return nil, fmt.Errorf("no struct field with tag 'measurement'")
}
if len(lpFields) == 0 {
return nil, fmt.Errorf("no struct field with tag 'field'")
}
return write.NewPoint(measurement, lpTags, lpFields, lpTime), nil
}
78 changes: 0 additions & 78 deletions api/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ package api

import (
"context"
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -268,79 +266,3 @@ func (w *WriteAPIImpl) WritePoint(point *write.Point) {
func buffer(lines []string) string {
return strings.Join(lines, "")
}

// DataToPoint converts custom point structures into a Point.
// Each visible field of the point on input must be annotated with
// 'lp' prefix and values measurement,tag, field or timestamp.
// Valid point must contain measurement and at least one field.
//
// A field with timestamp must be of a type time.Time
//
// type TemperatureSensor struct {
// Measurement string `lp:"measurement"`
// Sensor string `lp:"tag,sensor"`
// ID string `lp:"tag,device_id"`
// Temp float64 `lp:"field,temperature"`
// Hum int `lp:"field,humidity"`
// Time time.Time `lp:"timestamp,temperature"`
// Description string `lp:"-"`
// }
func DataToPoint(x interface{}) (*write.Point, error) {
if err := checkContainerType(x, false, "point"); err != nil {
return nil, err
}
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
if t.Kind() == reflect.Ptr {
t = t.Elem()
v = v.Elem()
}
fields := reflect.VisibleFields(t)

var measurement string = ""
var lpTags = make(map[string]string)
var lpFields = make(map[string]interface{})
var lpTime time.Time

for _, f := range fields {
name := f.Name
if tag, ok := f.Tag.Lookup("lp"); ok {
if tag == "-" {
continue
}
parts := strings.Split(tag, ",")
if len(parts) > 2 {
return nil, fmt.Errorf("multiple tag attributes are not supported")
}
typ := parts[0]
if len(parts) == 2 {
name = parts[1]
}
switch typ {
case "measurement":
if measurement != "" {
return nil, fmt.Errorf("multiple measurement fields")
}
measurement = v.FieldByIndex(f.Index).String()
case "tag":
lpTags[name] = v.FieldByIndex(f.Index).String()
case "field":
lpFields[name] = v.FieldByIndex(f.Index).Interface()
case "timestamp":
if f.Type != timeType {
return nil, fmt.Errorf("cannot use field '%s' as a timestamp", f.Name)
}
lpTime = v.FieldByIndex(f.Index).Interface().(time.Time)
default:
return nil, fmt.Errorf("invalid tag %s", typ)
}
}
}
if measurement == "" {
return nil, fmt.Errorf("no struct field with tag 'measurement'")
}
if len(lpFields) == 0 {
return nil, fmt.Errorf("no struct field with tag 'field'")
}
return write.NewPoint(measurement, lpTags, lpFields, lpTime), nil
}

0 comments on commit 496f4bc

Please sign in to comment.