@@ -6,6 +6,8 @@ package api
6
6
7
7
import (
8
8
"context"
9
+ "fmt"
10
+ "reflect"
9
11
"strings"
10
12
"sync"
11
13
"sync/atomic"
@@ -266,3 +268,79 @@ func (w *WriteAPIImpl) WritePoint(point *write.Point) {
266
268
func buffer (lines []string ) string {
267
269
return strings .Join (lines , "" )
268
270
}
271
+
272
+ // DataToPoint converts custom point structures into a Point.
273
+ // Each visible field of the point on input must be annotated with
274
+ // 'lp' prefix and values measurement,tag, field or timestamp.
275
+ // Valid point must contain measurement and at least one field.
276
+ //
277
+ // A field with timestamp must be of a type time.Time
278
+ //
279
+ // type TemperatureSensor struct {
280
+ // Measurement string `lp:"measurement"`
281
+ // Sensor string `lp:"tag,sensor"`
282
+ // ID string `lp:"tag,device_id"`
283
+ // Temp float64 `lp:"field,temperature"`
284
+ // Hum int `lp:"field,humidity"`
285
+ // Time time.Time `lp:"timestamp,temperature"`
286
+ // Description string `lp:"-"`
287
+ // }
288
+ func DataToPoint (x interface {}) (* write.Point , error ) {
289
+ if err := checkContainerType (x , false , "point" ); err != nil {
290
+ return nil , err
291
+ }
292
+ t := reflect .TypeOf (x )
293
+ v := reflect .ValueOf (x )
294
+ if t .Kind () == reflect .Ptr {
295
+ t = t .Elem ()
296
+ v = v .Elem ()
297
+ }
298
+ fields := reflect .VisibleFields (t )
299
+
300
+ var measurement string = ""
301
+ var lpTags = make (map [string ]string )
302
+ var lpFields = make (map [string ]interface {})
303
+ var lpTime time.Time
304
+
305
+ for _ , f := range fields {
306
+ name := f .Name
307
+ if tag , ok := f .Tag .Lookup ("lp" ); ok {
308
+ if tag == "-" {
309
+ continue
310
+ }
311
+ parts := strings .Split (tag , "," )
312
+ if len (parts ) > 2 {
313
+ return nil , fmt .Errorf ("multiple tag attributes are not supported" )
314
+ }
315
+ typ := parts [0 ]
316
+ if len (parts ) == 2 {
317
+ name = parts [1 ]
318
+ }
319
+ switch typ {
320
+ case "measurement" :
321
+ if measurement != "" {
322
+ return nil , fmt .Errorf ("multiple measurement fields" )
323
+ }
324
+ measurement = v .FieldByIndex (f .Index ).String ()
325
+ case "tag" :
326
+ lpTags [name ] = v .FieldByIndex (f .Index ).String ()
327
+ case "field" :
328
+ lpFields [name ] = v .FieldByIndex (f .Index ).Interface ()
329
+ case "timestamp" :
330
+ if f .Type != timeType {
331
+ return nil , fmt .Errorf ("cannot use field '%s' as a timestamp" , f .Name )
332
+ }
333
+ lpTime = v .FieldByIndex (f .Index ).Interface ().(time.Time )
334
+ default :
335
+ return nil , fmt .Errorf ("invalid tag %s" , typ )
336
+ }
337
+ }
338
+ }
339
+ if measurement == "" {
340
+ return nil , fmt .Errorf ("no struct field with tag 'measurement'" )
341
+ }
342
+ if len (lpFields ) == 0 {
343
+ return nil , fmt .Errorf ("no struct field with tag 'field'" )
344
+ }
345
+ return write .NewPoint (measurement , lpTags , lpFields , lpTime ), nil
346
+ }
0 commit comments