influxdb/macro.go

189 lines
5.0 KiB
Go

package platform
import (
"context"
"encoding/json"
"fmt"
)
// MacroService describes a service for managing Macros
type MacroService interface {
// FindMacro finds a single macro from the store by its ID
FindMacroByID(ctx context.Context, id ID) (*Macro, error)
// FindMacros returns all macros in the store
FindMacros(ctx context.Context) ([]*Macro, error)
// CreateMacro creates a new macro and assigns it an ID
CreateMacro(ctx context.Context, m *Macro) error
// UpdateMacro updates a single macro with a changeset
UpdateMacro(ctx context.Context, id ID, update *MacroUpdate) (*Macro, error)
// ReplaceMacro replaces a single macro
ReplaceMacro(ctx context.Context, macro *Macro) error
// DeleteMacro removes a macro from the store
DeleteMacro(ctx context.Context, id ID) error
}
// A Macro describes a keyword that can be expanded into several possible
// values when used in an InfluxQL or Flux query
type Macro struct {
ID ID `json:"id,omitempty"`
Name string `json:"name"`
Selected []string `json:"selected"`
Arguments *MacroArguments `json:"arguments"`
}
// A MacroUpdate describes a set of changes that can be applied to a Macro
type MacroUpdate struct {
Name string `json:"name"`
Selected []string `json:"selected"`
Arguments *MacroArguments `json:"arguments"`
}
// A MacroArguments contains arguments used when expanding a Macro
type MacroArguments struct {
Type string `json:"type"` // "constant", "map", or "query"
Values interface{} `json:"values"` // either MacroQueryValues, MacroConstantValues, MacroMapValues
}
// MacroQueryValues contains a query used when expanding a query-based Macro
type MacroQueryValues struct {
Query string `json:"query"`
Language string `json:"language"` // "influxql" or "flux"
}
// MacroConstantValues are the data for expanding a constants-based Macro
type MacroConstantValues []string
// MacroMapValues are the data for expanding a map-based Macro
type MacroMapValues map[string]string
// Valid returns an error if a Macro contains invalid data
func (m *Macro) Valid() error {
if m.Name == "" {
return fmt.Errorf("name empty")
}
validTypes := map[string]bool{
"constant": true,
"map": true,
"query": true,
}
if _, prs := validTypes[m.Arguments.Type]; !prs {
return fmt.Errorf("invalid arguments type")
}
if len(m.Selected) == 0 {
return fmt.Errorf("no selected values")
}
return nil
}
// Valid returns an error if a Macro changeset is not valid
func (u *MacroUpdate) Valid() error {
if u.Name == "" && u.Selected == nil && u.Arguments == nil {
return fmt.Errorf("no fields supplied in update")
}
return nil
}
// Apply applies non-zero fields from a MacroUpdate to a Macro
func (u *MacroUpdate) Apply(m *Macro) error {
if u.Name != "" {
m.Name = u.Name
}
if u.Selected != nil {
m.Selected = u.Selected
}
if u.Arguments != nil {
m.Arguments = u.Arguments
}
return nil
}
// UnmarshalJSON unmarshals json into a MacroArguments struct, using the `Type`
// field to assign the approriate struct to the `Values` field
func (a *MacroArguments) UnmarshalJSON(data []byte) error {
type Alias MacroArguments
aux := struct{ *Alias }{Alias: (*Alias)(a)}
err := json.Unmarshal(data, &aux)
if err != nil {
return err
}
// Decode the polymorphic MacroArguments.Values field into the approriate struct
switch aux.Type {
case "constant":
values, ok := aux.Values.([]interface{})
if !ok {
return fmt.Errorf("error parsing %v as MacroConstantArguments", aux.Values)
}
macroValues := make(MacroConstantValues, len(values))
for i, v := range values {
if _, ok := v.(string); !ok {
return fmt.Errorf("expected macro constant value to be string but received %T", v)
}
macroValues[i] = v.(string)
}
a.Values = macroValues
case "map":
values, ok := aux.Values.(map[string]interface{})
if !ok {
return fmt.Errorf("error parsing %v as MacroMapArguments", aux.Values)
}
macroValues := MacroMapValues{}
for k, v := range values {
if _, ok := v.(string); !ok {
return fmt.Errorf("expected macro map value to be string but received %T", v)
}
macroValues[k] = v.(string)
}
a.Values = macroValues
case "query":
values, ok := aux.Values.(map[string]interface{})
if !ok {
return fmt.Errorf("error parsing %v as MacroQueryArguments", aux.Values)
}
macroValues := MacroQueryValues{}
query, prs := values["query"]
if !prs {
return fmt.Errorf("\"query\" key not present in MacroQueryArguments")
}
if _, ok := query.(string); !ok {
return fmt.Errorf("expected \"query\" to be string but received %T", query)
}
language, prs := values["language"]
if !prs {
return fmt.Errorf("\"language\" key not present in MacroQueryArguments")
}
if _, ok := language.(string); !ok {
return fmt.Errorf("expected \"language\" to be string but received %T", language)
}
macroValues.Query = query.(string)
macroValues.Language = language.(string)
a.Values = macroValues
default:
return fmt.Errorf("unknown MacroArguments type %s", aux.Type)
}
return nil
}