From 060d69e18c984ee46de0a68abf5f97a563d0cbeb Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Tue, 28 Nov 2023 11:57:57 +0100 Subject: [PATCH 1/8] feat: refactor reflections utilities as per v3 --- api/query.go | 16 ----------- api/reflection.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 api/reflection.go diff --git a/api/query.go b/api/query.go index bce3e96..a547148 100644 --- a/api/query.go +++ b/api/query.go @@ -289,22 +289,6 @@ func checkParamsType(p interface{}) error { return nil } -// getFieldType extracts type of value -func getFieldType(v reflect.Value) reflect.Type { - t := v.Type() - if t.Kind() == reflect.Ptr { - t = t.Elem() - v = v.Elem() - } - if t.Kind() == reflect.Interface && !v.IsNil() { - t = reflect.ValueOf(v.Interface()).Type() - } - return t -} - -// timeType is the exact type for the Time -var timeType = reflect.TypeOf(time.Time{}) - // validParamType validates that t is primitive type or string or interface func validParamType(t reflect.Type) bool { return (t.Kind() > reflect.Invalid && t.Kind() < reflect.Complex64) || diff --git a/api/reflection.go b/api/reflection.go new file mode 100644 index 0000000..e012b5f --- /dev/null +++ b/api/reflection.go @@ -0,0 +1,72 @@ +package api + +import ( + "fmt" + "reflect" + "time" +) + +// checkContainerType validates the value is struct with simple type fields +// or a map with key as string and value as a simple type +func checkContainerType(p interface{}, alsoMap bool, usage string) error { + if p == nil { + return nil + } + t := reflect.TypeOf(p) + v := reflect.ValueOf(p) + if t.Kind() == reflect.Ptr { + t = t.Elem() + v = v.Elem() + } + if t.Kind() != reflect.Struct && (!alsoMap || t.Kind() != reflect.Map) { + return fmt.Errorf("cannot use %v as %s", t, usage) + } + switch t.Kind() { + case reflect.Struct: + fields := reflect.VisibleFields(t) + for _, f := range fields { + fv := v.FieldByIndex(f.Index) + t := getFieldType(fv) + if !validFieldType(t) { + return fmt.Errorf("cannot use field '%s' of type '%v' as a %s", f.Name, t, usage) + } + + } + case reflect.Map: + key := t.Key() + if key.Kind() != reflect.String { + return fmt.Errorf("cannot use map key of type '%v' for %s name", key, usage) + } + for _, k := range v.MapKeys() { + f := v.MapIndex(k) + t := getFieldType(f) + if !validFieldType(t) { + return fmt.Errorf("cannot use map value type '%v' as a %s", t, usage) + } + } + } + return nil +} + +// getFieldType extracts type of value +func getFieldType(v reflect.Value) reflect.Type { + t := v.Type() + if t.Kind() == reflect.Ptr { + t = t.Elem() + v = v.Elem() + } + if t.Kind() == reflect.Interface && !v.IsNil() { + t = reflect.ValueOf(v.Interface()).Type() + } + return t +} + +// timeType is the exact type for the Time +var timeType = reflect.TypeOf(time.Time{}) + +// validFieldType validates that t is primitive type or string or interface +func validFieldType(t reflect.Type) bool { + return (t.Kind() > reflect.Invalid && t.Kind() < reflect.Complex64) || + t.Kind() == reflect.String || + t == timeType +} From ccdad29f879abb34e18f4f45ea247f62b2ec17ff Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Tue, 28 Nov 2023 12:31:27 +0100 Subject: [PATCH 2/8] feat: add DataToPoint --- api/write.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++ api/write/point.go | 6 ++++ 2 files changed, 84 insertions(+) diff --git a/api/write.go b/api/write.go index 313d21a..02c4d4b 100644 --- a/api/write.go +++ b/api/write.go @@ -6,6 +6,8 @@ package api import ( "context" + "fmt" + "reflect" "strings" "sync" "sync/atomic" @@ -266,3 +268,79 @@ 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 +} diff --git a/api/write/point.go b/api/write/point.go index 91c9c0e..76f61d7 100644 --- a/api/write/point.go +++ b/api/write/point.go @@ -84,6 +84,12 @@ func (m *Point) Name() string { return m.measurement } +// Name returns the name of measurement of a point. +func (m *Point) SetName(name string) *Point { + m.measurement = name + return m +} + // NewPointWithMeasurement creates a empty Point // Use AddTag and AddField to fill point with data func NewPointWithMeasurement(measurement string) *Point { From 1342ca605b2921bac9cb591e6534c8b3167e09ef Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Tue, 28 Nov 2023 14:33:38 +0100 Subject: [PATCH 3/8] chore: remove unused setter --- api/write/point.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/api/write/point.go b/api/write/point.go index 76f61d7..91c9c0e 100644 --- a/api/write/point.go +++ b/api/write/point.go @@ -84,12 +84,6 @@ func (m *Point) Name() string { return m.measurement } -// Name returns the name of measurement of a point. -func (m *Point) SetName(name string) *Point { - m.measurement = name - return m -} - // NewPointWithMeasurement creates a empty Point // Use AddTag and AddField to fill point with data func NewPointWithMeasurement(measurement string) *Point { From 496f4bc84ebd0bb17dce8f17f3e54244d131dce7 Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Tue, 28 Nov 2023 14:36:34 +0100 Subject: [PATCH 4/8] chore: refactor DataToPoint --- api/data_to_point.go | 86 ++++++++++++++++++++++++++++++++++++++++++++ api/write.go | 78 ---------------------------------------- 2 files changed, 86 insertions(+), 78 deletions(-) create mode 100644 api/data_to_point.go diff --git a/api/data_to_point.go b/api/data_to_point.go new file mode 100644 index 0000000..bfb5740 --- /dev/null +++ b/api/data_to_point.go @@ -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 +} diff --git a/api/write.go b/api/write.go index 02c4d4b..313d21a 100644 --- a/api/write.go +++ b/api/write.go @@ -6,8 +6,6 @@ package api import ( "context" - "fmt" - "reflect" "strings" "sync" "sync/atomic" @@ -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 -} From 925548b951a7d97eea2301d9bf9ac758b399fd55 Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Tue, 28 Nov 2023 15:34:58 +0100 Subject: [PATCH 5/8] feat: add TestDataToPoint --- api/data_to_point.go | 8 +- api/data_to_point_test.go | 216 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 api/data_to_point_test.go diff --git a/api/data_to_point.go b/api/data_to_point.go index bfb5740..8ecc71c 100644 --- a/api/data_to_point.go +++ b/api/data_to_point.go @@ -37,7 +37,7 @@ func DataToPoint(x interface{}) (*write.Point, error) { } fields := reflect.VisibleFields(t) - var measurement string = "" + var measurement = "" var lpTags = make(map[string]string) var lpFields = make(map[string]interface{}) var lpTime time.Time @@ -63,8 +63,14 @@ func DataToPoint(x interface{}) (*write.Point, error) { } measurement = v.FieldByIndex(f.Index).String() case "tag": + if name == "" { + return nil, fmt.Errorf("cannot use field '%s': invalid lp tag name \"\"", f.Name) + } lpTags[name] = v.FieldByIndex(f.Index).String() case "field": + if name == "" { + return nil, fmt.Errorf("cannot use field '%s': invalid lp field name \"\"", f.Name) + } lpFields[name] = v.FieldByIndex(f.Index).Interface() case "timestamp": if f.Type != timeType { diff --git a/api/data_to_point_test.go b/api/data_to_point_test.go new file mode 100644 index 0000000..4c842bc --- /dev/null +++ b/api/data_to_point_test.go @@ -0,0 +1,216 @@ +package api + +import ( + "bytes" + "fmt" + "testing" + "time" + + "github.com/influxdata/influxdb-client-go/v2/api/write" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + lp "github.com/influxdata/line-protocol" +) + +func TestDataToPoint(t *testing.T) { + pointToLine := func(point *write.Point) string { + var buffer bytes.Buffer + e := lp.NewEncoder(&buffer) + e.SetFieldTypeSupport(lp.UintSupport) + e.FailOnFieldErr(true) + _, err := e.Encode(point) + if err != nil { + panic(err) + } + return buffer.String() + } + now := time.Now() + tests := []struct { + name string + s interface{} + line string + error string + }{{ + name: "test normal structure", + s: 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"` + Description string `lp:"-"` + }{ + "air", + "SHT31", + "10", + 23.5, + 55, + now, + "Room temp", + }, + line: fmt.Sprintf("air,device_id=10,sensor=SHT31 humidity=55i,temperature=23.5 %d\n", now.UnixNano()), + }, + { + name: "test pointer to normal structure", + s: &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"` + Description string `lp:"-"` + }{ + "air", + "SHT31", + "10", + 23.5, + 55, + now, + "Room temp", + }, + line: fmt.Sprintf("air,device_id=10,sensor=SHT31 humidity=55i,temperature=23.5 %d\n", now.UnixNano()), + }, { + name: "test no tag, no timestamp", + s: &struct { + Measurement string `lp:"measurement"` + Temp float64 `lp:"field,temperature"` + }{ + "air", + 23.5, + }, + line: "air temperature=23.5\n", + }, + { + name: "test default struct field name", + s: &struct { + Measurement string `lp:"measurement"` + Sensor string `lp:"tag"` + Temp float64 `lp:"field"` + }{ + "air", + "SHT31", + 23.5, + }, + line: "air,Sensor=SHT31 Temp=23.5\n", + }, + { + name: "test missing struct field tag name", + s: &struct { + Measurement string `lp:"measurement"` + Sensor string `lp:"tag,"` + Temp float64 `lp:"field"` + }{ + "air", + "SHT31", + 23.5, + }, + error: `cannot use field 'Sensor': invalid lp tag name ""`, + }, + { + name: "test missing struct field field name", + s: &struct { + Measurement string `lp:"measurement"` + Temp float64 `lp:"field,"` + }{ + "air", + 23.5, + }, + error: `cannot use field 'Temp': invalid lp field name ""`, + }, + { + name: "test missing measurement", + s: &struct { + Measurement string `lp:"tag"` + Sensor string `lp:"tag"` + Temp float64 `lp:"field"` + }{ + "air", + "SHT31", + 23.5, + }, + error: `no struct field with tag 'measurement'`, + }, + { + name: "test no field", + s: &struct { + Measurement string `lp:"measurement"` + Sensor string `lp:"tag"` + Temp float64 `lp:"tag"` + }{ + "air", + "SHT31", + 23.5, + }, + error: `no struct field with tag 'field'`, + }, + { + name: "test double measurement", + s: &struct { + Measurement string `lp:"measurement"` + Sensor string `lp:"measurement"` + Temp float64 `lp:"field,a"` + Hum float64 `lp:"field,a"` + }{ + "air", + "SHT31", + 23.5, + 43.1, + }, + error: `multiple measurement fields`, + }, + { + name: "test multiple tag attributes", + s: &struct { + Measurement string `lp:"measurement"` + Sensor string `lp:"tag,a,a"` + Temp float64 `lp:"field,a"` + Hum float64 `lp:"field,a"` + }{ + "air", + "SHT31", + 23.5, + 43.1, + }, + error: `multiple tag attributes are not supported`, + }, + { + name: "test wrong timestamp type", + s: &struct { + Measurement string `lp:"measurement"` + Sensor string `lp:"tag,sensor"` + Temp float64 `lp:"field,a"` + Hum float64 `lp:"timestamp"` + }{ + "air", + "SHT31", + 23.5, + 43.1, + }, + error: `cannot use field 'Hum' as a timestamp`, + }, + { + name: "test map", + s: map[string]interface{}{ + "measurement": "air", + "sensor": "SHT31", + "temp": 23.5, + }, + error: `cannot use map[string]interface {} as point`, + }, + } + for _, ts := range tests { + t.Run(ts.name, func(t *testing.T) { + point, err := DataToPoint(ts.s) + if ts.error == "" { + require.NoError(t, err) + assert.Equal(t, ts.line, pointToLine(point)) + } else { + require.Error(t, err) + assert.Equal(t, ts.error, err.Error()) + } + }) + } +} From f168bda5a938edc54114da99035a4d3b0d42779b Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Wed, 29 Nov 2023 12:16:51 +0100 Subject: [PATCH 6/8] chore: remove unused code --- api/data_to_point.go | 10 +++++++--- api/reflection.go | 43 ------------------------------------------- 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/api/data_to_point.go b/api/data_to_point.go index 8ecc71c..4977958 100644 --- a/api/data_to_point.go +++ b/api/data_to_point.go @@ -26,15 +26,15 @@ import ( // 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() } + if t.Kind() != reflect.Struct { + return nil, fmt.Errorf("cannot use %v as point", t) + } fields := reflect.VisibleFields(t) var measurement = "" @@ -56,6 +56,10 @@ func DataToPoint(x interface{}) (*write.Point, error) { if len(parts) == 2 { name = parts[1] } + t := getFieldType(v.FieldByIndex(f.Index)) + if !validFieldType(t) { + return nil, fmt.Errorf("cannot use field '%s' of type '%v' as to create a point", f.Name, t) + } switch typ { case "measurement": if measurement != "" { diff --git a/api/reflection.go b/api/reflection.go index e012b5f..8becc40 100644 --- a/api/reflection.go +++ b/api/reflection.go @@ -1,53 +1,10 @@ package api import ( - "fmt" "reflect" "time" ) -// checkContainerType validates the value is struct with simple type fields -// or a map with key as string and value as a simple type -func checkContainerType(p interface{}, alsoMap bool, usage string) error { - if p == nil { - return nil - } - t := reflect.TypeOf(p) - v := reflect.ValueOf(p) - if t.Kind() == reflect.Ptr { - t = t.Elem() - v = v.Elem() - } - if t.Kind() != reflect.Struct && (!alsoMap || t.Kind() != reflect.Map) { - return fmt.Errorf("cannot use %v as %s", t, usage) - } - switch t.Kind() { - case reflect.Struct: - fields := reflect.VisibleFields(t) - for _, f := range fields { - fv := v.FieldByIndex(f.Index) - t := getFieldType(fv) - if !validFieldType(t) { - return fmt.Errorf("cannot use field '%s' of type '%v' as a %s", f.Name, t, usage) - } - - } - case reflect.Map: - key := t.Key() - if key.Kind() != reflect.String { - return fmt.Errorf("cannot use map key of type '%v' for %s name", key, usage) - } - for _, k := range v.MapKeys() { - f := v.MapIndex(k) - t := getFieldType(f) - if !validFieldType(t) { - return fmt.Errorf("cannot use map value type '%v' as a %s", t, usage) - } - } - } - return nil -} - // getFieldType extracts type of value func getFieldType(v reflect.Value) reflect.Type { t := v.Type() From e9166da3ebe98f63f615c805b4735f0a0fc62fa1 Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Wed, 29 Nov 2023 12:53:48 +0100 Subject: [PATCH 7/8] chore: update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e3d411..37bfa9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 2.13.0 [unreleased] +### Features + +- [#394](https://github.com/influxdata/influxdb-client-go/pull/394) Add `DataToPoint` utility to convert a struct to a `write.Point` + ### Dependencies - [#393](https://github.com/influxdata/influxdb-client-go/pull/393) Replace deprecated `io/ioutil` - [#392](https://github.com/influxdata/influxdb-client-go/pull/392) Upgrade `deepmap/oapi-codegen` to new major version From 425a78382c48a2e5784ed939d9f9be76541f5c52 Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Wed, 29 Nov 2023 13:06:57 +0100 Subject: [PATCH 8/8] feat: improve tests --- api/data_to_point_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/api/data_to_point_test.go b/api/data_to_point_test.go index 4c842bc..d78317d 100644 --- a/api/data_to_point_test.go +++ b/api/data_to_point_test.go @@ -200,6 +200,28 @@ func TestDataToPoint(t *testing.T) { }, error: `cannot use map[string]interface {} as point`, }, + { + name: "test unsupported field type", + s: &struct { + Measurement string `lp:"measurement"` + Temp complex64 `lp:"field,a"` + }{ + "air", + complex(1, 1), + }, + error: `cannot use field 'Temp' of type 'complex64' as to create a point`, + }, + { + name: "test unsupported lp tag value", + s: &struct { + Measurement string `lp:"measurement"` + Temp float64 `lp:"data,a"` + }{ + "air", + 1.0, + }, + error: `invalid tag data`, + }, } for _, ts := range tests { t.Run(ts.name, func(t *testing.T) {