github.com/ngicks/gokugen@v0.0.5/impl/work_registry/param_unmarshaller.go (about) 1 package workregistry 2 3 import ( 4 "context" 5 "encoding/json" 6 "time" 7 8 "github.com/mitchellh/mapstructure" 9 "github.com/ngicks/gokugen" 10 "github.com/ngicks/gokugen/cron" 11 syncparam "github.com/ngicks/type-param-common/sync-param" 12 ) 13 14 type Unmarshaller = func(naive any) (unmarshalled any, err error) 15 16 // UnmarshalAny is reference Unmarshaller implementation. 17 // If naive is T it simply returns naive. 18 // If naive is []byte then unmarshal it as a json string. 19 // Else, UnmarshalAny treats naive as naively unmarshalled json value 20 // (e.g. map[any]any, []any or other literal values). 21 // It copies values from naive to unmarshaled through reflection. 22 func UnmarshalAny[T any](naive any) (unmarshalled any, err error) { 23 if _, ok := naive.(T); ok { 24 return naive, nil 25 } 26 27 var val T 28 29 if bin, ok := naive.([]byte); ok { 30 err = json.Unmarshal(bin, &val) 31 if err != nil { 32 return 33 } 34 unmarshalled = val 35 return 36 } 37 38 err = mapstructure.Decode(naive, &val) 39 if err != nil { 40 return 41 } 42 return val, nil 43 } 44 45 type UnmarshallerRegistry interface { 46 Load(key string) (value Unmarshaller, ok bool) 47 } 48 49 type AnyUnmarshaller struct { 50 syncparam.Map[string, Unmarshaller] 51 } 52 53 // AddType stores UnmarshalAny instantiated with T into the registry. 54 // AddType is an external function, not a method for *AnyUnmarshaller, 55 // since Go curently does not allow us to add type parameters to methods individually. 56 func AddType[T any](key string, registry *AnyUnmarshaller) { 57 registry.Store(key, UnmarshalAny[T]) 58 } 59 60 type ParamUnmarshaller struct { 61 inner cron.WorkRegistry 62 marshallerRegistry UnmarshallerRegistry 63 } 64 65 func NewParamUnmarshaller( 66 inner cron.WorkRegistry, 67 marshallerRegistry UnmarshallerRegistry, 68 ) *ParamUnmarshaller { 69 return &ParamUnmarshaller{ 70 inner: inner, 71 marshallerRegistry: marshallerRegistry, 72 } 73 } 74 75 func (p *ParamUnmarshaller) Load(key string) (value gokugen.WorkFnWParam, ok bool) { 76 work, ok := p.inner.Load(key) 77 if !ok { 78 return 79 } 80 81 unmarshaller, ok := p.marshallerRegistry.Load(key) 82 if !ok { 83 return 84 } 85 86 value = func(taskCtx context.Context, scheduled time.Time, param any) (any, error) { 87 unmarshaled, err := unmarshaller(param) 88 if err != nil { 89 return nil, err 90 } 91 return work(taskCtx, scheduled, unmarshaled) 92 } 93 94 return 95 }