2017-12-19 13:16:39 +01:00

137 lines
3.6 KiB
Go

package common
import (
"fmt"
"strings"
"github.com/elastic/go-ucfg/yaml"
)
//This reflects allowed attributes for field definitions in the fields.yml.
//No logic is put into this data structure.
//The purpose is to enable using different kinds of transformation, on top of the same data structure.
//Current transformation:
// -ElasticSearch Template
// -Kibana Index Pattern
type Fields []Field
type Field struct {
Name string `config:"name"`
Type string `config:"type"`
Description string `config:"description"`
Format string `config:"format"`
ScalingFactor int `config:"scaling_factor"`
Fields Fields `config:"fields"`
MultiFields Fields `config:"multi_fields"`
ObjectType string `config:"object_type"`
Enabled *bool `config:"enabled"`
Analyzer string `config:"analyzer"`
SearchAnalyzer string `config:"search_analyzer"`
Norms bool `config:"norms"`
Dynamic DynamicType `config:"dynamic"`
Index *bool `config:"index"`
DocValues *bool `config:"doc_values"`
CopyTo string `config:"copy_to"`
// Kibana specific
Analyzed *bool `config:"analyzed"`
Count int `config:"count"`
Searchable *bool `config:"searchable"`
Aggregatable *bool `config:"aggregatable"`
Script string `config:"script"`
// Kibana params
Pattern string `config:"pattern"`
InputFormat string `config:"input_format"`
OutputFormat string `config:"output_format"`
OutputPrecision *int `config:"output_precision"`
LabelTemplate string `config:"label_template"`
UrlTemplate []VersionizedString `config:"url_template"`
OpenLinkInCurrentTab *bool `config:"open_link_in_current_tab"`
Path string
}
type VersionizedString struct {
MinVersion string `config:"min_version"`
Value string `config:"value"`
}
type DynamicType struct{ Value interface{} }
func (d *DynamicType) Unpack(s string) error {
switch s {
case "true":
d.Value = true
case "false":
d.Value = false
case "strict":
d.Value = s
default:
return fmt.Errorf("'%v' is invalid dynamic setting", s)
}
return nil
}
func LoadFieldsYaml(path string) (Fields, error) {
keys := []Field{}
cfg, err := yaml.NewConfigWithFile(path)
if err != nil {
return nil, err
}
cfg.Unpack(&keys)
fields := Fields{}
for _, key := range keys {
fields = append(fields, key.Fields...)
}
return fields, nil
}
// HasKey checks if inside fields the given key exists
// The key can be in the form of a.b.c and it will check if the nested field exist
// In case the key is `a` and there is a value `a.b` false is return as it only
// returns true if it's a leave node
func (f Fields) HasKey(key string) bool {
keys := strings.Split(key, ".")
return f.hasKey(keys)
}
// Recursively generates the correct key based on the dots
// The mapping requires "properties" between each layer. This is added here.
func GenerateKey(key string) string {
if strings.Contains(key, ".") {
keys := strings.SplitN(key, ".", 2)
key = keys[0] + ".properties." + GenerateKey(keys[1])
}
return key
}
func (f Fields) hasKey(keys []string) bool {
// Nothing to compare anymore
if len(keys) == 0 {
return false
}
key := keys[0]
keys = keys[1:]
for _, field := range f {
if field.Name == key {
if len(field.Fields) > 0 {
return field.Fields.hasKey(keys)
}
// Last entry in the tree but still more keys
if len(keys) > 0 {
return false
}
return true
}
}
return false
}