Select Git revision
caching_middleware_test.go
options.go 3.25 KiB
package field
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"sync"
)
type Option interface {
Transform(f *Field, v interface{}) (interface{}, error)
}
type PriorityOption interface {
GetPriority() int
}
type NamedOption interface {
GetName() string
}
type OptionValidator interface {
ValidateOption() error
}
//type jsonTransform struct {
// Name string `json:"name"`
// Options json.RawMessage `json:"options,omitempty"`
//}
//
//func (t *Option) MarshalJSON() ([]byte, error) {
// b, err := json.Marshal(t.Transformation)
// if err != nil {
// return nil, err
// }
//
// j := jsonTransform{Name: GetOptionName(t.Transformation), Options: b}
//
// return json.Marshal(&j)
//}
//
//func (t *Option) UnmarshalJSON(b []byte) error {
// var j jsonTransform
// if err := json.Unmarshal(b, &j); err != nil {
// return err
// }
//
// i, ok := nameToOption.Load(j.Name)
// if !ok {
// return fmt.Errorf("unknown transformer name \"%s\"", j.Name)
// }
// typ := i.(reflect.Type)
// val := reflect.New(typ)
// v := val.Interface()
//
// if len(j.Options) > 0 {
// if err := json.Unmarshal(j.Options, v); err != nil {
// return err
// }
// }
//
// tr, _ := v.(Transformation)
// *t = Option{Transformation: tr}
// return nil
//}
var (
nameToOption sync.Map
optionToName sync.Map
)
func GetOptionName(o interface{}) string {
typ := reflect.TypeOf(o)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if val, ok := optionToName.Load(typ); ok {
v := val.(string)
return v
}
return ""
}
func RegisterOption(o interface{}) {
var name string
typ := reflect.TypeOf(o)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if namer, ok := o.(NamedOption); ok {
name = namer.GetName()
} else {
name = typ.Name()
}
nameToOption.Store(name, typ)
optionToName.Store(typ, name)
}
type Options map[string]interface{}
func (options *Options) Add(opts ...interface{}) {
if len(opts) == 0 {
return
}
if *options == nil {
*options = make(Options)
}
for _, o := range opts {
name := GetOptionName(o)
(*options)[name] = o
}
}
//func (options Options) MarshalJSON() ([]byte, error) {
// m := make(map[string]json.RawMessage)
//
// for k,v := range options {
// name := GetOptionName(t)
// b, err := json.Marshal(t)
// if err != nil {
// return nil, err
// }
// m[name] = b
// }
// return json.Marshal(&m)
//}
func (options *Options) UnmarshalJSON(b []byte) error {
m := make(map[string]json.RawMessage)
*options = make(Options)
if err := json.Unmarshal(b, &m); err != nil {
return err
}
for name, opts := range m {
i, ok := nameToOption.Load(name)
if !ok {
return fmt.Errorf("unknown option name \"%s\"", name)
}
typ := i.(reflect.Type)
val := reflect.New(typ)
v := val.Interface()
if len(opts) > 0 {
if err := json.Unmarshal(opts, v); err != nil {
return err
}
}
if validator, ok := v.(OptionValidator); ok {
err := validator.ValidateOption()
if errors.Is(err, ErrSkipOption) {
continue
}
if err != nil {
return err
}
}
options.Add(v)
}
return nil
}
func (options Options) Transform(field *Field, v interface{}) (interface{}, error) {
var err error
for _, t := range options {
o := t.(Option)
v, err = o.Transform(field, v)
if err != nil {
return nil, err
}
}
return v, nil
}