189 lines
5.0 KiB
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
|
|
}
|