mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 11:20:27 -06:00
137 lines
3.0 KiB
Go
137 lines
3.0 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
jsoniter "github.com/json-iterator/go"
|
|
)
|
|
|
|
type doc struct {
|
|
path []string
|
|
iterator *jsoniter.Iterator
|
|
fields []*data.Field
|
|
fieldNames map[string]struct{}
|
|
fieldTips map[string]Field
|
|
}
|
|
|
|
func (d *doc) next() error {
|
|
switch d.iterator.WhatIsNext() {
|
|
case jsoniter.StringValue:
|
|
d.addString(d.iterator.ReadString())
|
|
case jsoniter.NumberValue:
|
|
d.addNumber(d.iterator.ReadFloat64())
|
|
case jsoniter.BoolValue:
|
|
d.addBool(d.iterator.ReadBool())
|
|
case jsoniter.NilValue:
|
|
d.addNil()
|
|
d.iterator.ReadNil()
|
|
case jsoniter.ArrayValue:
|
|
index := 0
|
|
size := len(d.path)
|
|
for d.iterator.ReadArray() {
|
|
d.path = append(d.path, fmt.Sprintf("[%d]", index))
|
|
err := d.next()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.path = d.path[:size]
|
|
index++
|
|
}
|
|
case jsoniter.ObjectValue:
|
|
size := len(d.path)
|
|
for fname := d.iterator.ReadObject(); fname != ""; fname = d.iterator.ReadObject() {
|
|
if size > 0 {
|
|
d.path = append(d.path, ".")
|
|
}
|
|
d.path = append(d.path, fname)
|
|
err := d.next()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.path = d.path[:size]
|
|
}
|
|
case jsoniter.InvalidValue:
|
|
return fmt.Errorf("invalid value")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *doc) key() string {
|
|
return strings.Join(d.path, "")
|
|
}
|
|
|
|
func (d *doc) addString(v string) {
|
|
f := data.NewFieldFromFieldType(data.FieldTypeNullableString, 1)
|
|
f.Name = d.key()
|
|
f.SetConcrete(0, v)
|
|
d.fields = append(d.fields, f)
|
|
d.fieldNames[d.key()] = struct{}{}
|
|
}
|
|
|
|
func (d *doc) addNumber(v float64) {
|
|
f := data.NewFieldFromFieldType(data.FieldTypeNullableFloat64, 1)
|
|
f.Name = d.key()
|
|
f.SetConcrete(0, v)
|
|
d.fields = append(d.fields, f)
|
|
d.fieldNames[d.key()] = struct{}{}
|
|
}
|
|
|
|
func (d *doc) addBool(v bool) {
|
|
f := data.NewFieldFromFieldType(data.FieldTypeNullableBool, 1)
|
|
f.Name = d.key()
|
|
f.SetConcrete(0, v)
|
|
d.fields = append(d.fields, f)
|
|
d.fieldNames[d.key()] = struct{}{}
|
|
}
|
|
|
|
func (d *doc) addNil() {
|
|
if tip, ok := d.fieldTips[d.key()]; ok {
|
|
f := data.NewFieldFromFieldType(tip.Type, 1)
|
|
f.Name = d.key()
|
|
f.Set(0, nil)
|
|
d.fields = append(d.fields, f)
|
|
d.fieldNames[d.key()] = struct{}{}
|
|
} else {
|
|
logger.Warn("Skip nil field", "key", d.key())
|
|
}
|
|
}
|
|
|
|
func jsonDocToFrame(name string, body []byte, fields map[string]Field, nowTimeFunc func() time.Time) (*data.Frame, error) {
|
|
d := doc{
|
|
iterator: jsoniter.ParseBytes(jsoniter.ConfigDefault, body),
|
|
path: make([]string, 0),
|
|
fieldTips: fields,
|
|
fieldNames: map[string]struct{}{},
|
|
}
|
|
|
|
f := data.NewFieldFromFieldType(data.FieldTypeTime, 1)
|
|
f.Name = "Time"
|
|
f.Set(0, nowTimeFunc())
|
|
d.fields = append(d.fields, f)
|
|
|
|
err := d.next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(d.fields) < 2 {
|
|
return nil, fmt.Errorf("no fields found")
|
|
}
|
|
|
|
for name, tip := range fields {
|
|
if _, ok := d.fieldNames[name]; ok {
|
|
continue
|
|
}
|
|
f := data.NewFieldFromFieldType(tip.Type, 1)
|
|
f.Name = name
|
|
f.Set(0, nil)
|
|
f.Config = tip.Config
|
|
d.fields = append(d.fields, f)
|
|
}
|
|
|
|
return data.NewFrame(name, d.fields...), nil
|
|
}
|