diff --git a/lang/core/value/get.go b/lang/core/value/get.go index def3a58ee..b5eefe5ec 100644 --- a/lang/core/value/get.go +++ b/lang/core/value/get.go @@ -88,7 +88,8 @@ type GetFunc struct { init *interfaces.Init - key string + key string + args []types.Value last types.Value result types.Value // last calculated output @@ -229,7 +230,13 @@ func (obj *GetFunc) Stream(ctx context.Context) error { } obj.last = input // store for next - key := input.Struct()[getArgNameKey].Str() + args, err := interfaces.StructToCallableArgs(input) // []types.Value, error) + if err != nil { + return err + } + obj.args = args + + key := args[0].Str() if key == "" { return fmt.Errorf("can't use an empty key") } @@ -263,7 +270,7 @@ func (obj *GetFunc) Stream(ctx context.Context) error { // return errwrap.Wrapf(err, "channel watch failed on `%s`", obj.key) //} - result, err := obj.getValue(ctx) // get the value... + result, err := obj.Call(ctx, obj.args) // get the value... if err != nil { return err } @@ -287,8 +294,12 @@ func (obj *GetFunc) Stream(ctx context.Context) error { } } -// getValue gets the value we're looking for. -func (obj *GetFunc) getValue(ctx context.Context) (types.Value, error) { +// Call this function with the input args and return the value if it is possible +// to do so at this time. This was previously getValue which gets the value +// we're looking for. +func (obj *GetFunc) Call(ctx context.Context, args []types.Value) (types.Value, error) { + key := args[0].Str() + typ, exists := obj.Info().Sig.Out.Map[getFieldNameValue] // type of value field if !exists || typ == nil { // programming error @@ -303,9 +314,9 @@ func (obj *GetFunc) getValue(ctx context.Context) (types.Value, error) { // step that might be needed if the value started out empty... // TODO: We could even add a stored: bool field in the returned struct! isReady := true // assume true - val, err := obj.init.Local.ValueGet(ctx, obj.key) + val, err := obj.init.Local.ValueGet(ctx, key) if err != nil { - return nil, errwrap.Wrapf(err, "channel read failed on `%s`", obj.key) + return nil, errwrap.Wrapf(err, "channel read failed on `%s`", key) } if val == nil { // val doesn't exist isReady = false @@ -324,7 +335,7 @@ func (obj *GetFunc) getValue(ctx context.Context) (types.Value, error) { // an str for example, this error happens... Do we want // to: (1) coerce? -- no; (2) error? -- yep for now; (3) // improve type unification? -- if it's possible, yes. - return nil, errwrap.Wrapf(err, "type mismatch, check type in Value[%s]", obj.key) + return nil, errwrap.Wrapf(err, "type mismatch, check type in Value[%s]", key) } } diff --git a/lang/core/world/getval.go b/lang/core/world/getval.go index 4272e4e65..3300042f3 100644 --- a/lang/core/world/getval.go +++ b/lang/core/world/getval.go @@ -60,7 +60,8 @@ func init() { type GetValFunc struct { init *interfaces.Init - key string + key string + args []types.Value last types.Value result types.Value // last calculated output @@ -132,7 +133,13 @@ func (obj *GetValFunc) Stream(ctx context.Context) error { } obj.last = input // store for next - key := input.Struct()[getValArgNameKey].Str() + args, err := interfaces.StructToCallableArgs(input) // []types.Value, error) + if err != nil { + return err + } + obj.args = args + + key := args[0].Str() if key == "" { return fmt.Errorf("can't use an empty key") } @@ -169,7 +176,7 @@ func (obj *GetValFunc) Stream(ctx context.Context) error { return errwrap.Wrapf(err, "channel watch failed on `%s`", obj.key) } - result, err := obj.getValue(ctx) // get the value... + result, err := obj.Call(ctx, obj.args) // get the value... if err != nil { return err } @@ -193,14 +200,17 @@ func (obj *GetValFunc) Stream(ctx context.Context) error { } } -// getValue gets the value we're looking for. -func (obj *GetValFunc) getValue(ctx context.Context) (types.Value, error) { +// Call this function with the input args and return the value if it is possible +// to do so at this time. This was previously getValue which gets the value +// we're looking for. +func (obj *GetValFunc) Call(ctx context.Context, args []types.Value) (types.Value, error) { + key := args[0].Str() exists := true // assume true - val, err := obj.init.World.StrGet(ctx, obj.key) + val, err := obj.init.World.StrGet(ctx, key) if err != nil && obj.init.World.StrIsNotExist(err) { exists = false // val doesn't exist } else if err != nil { - return nil, errwrap.Wrapf(err, "channel read failed on `%s`", obj.key) + return nil, errwrap.Wrapf(err, "channel read failed on `%s`", key) } s := &types.StrValue{V: val} diff --git a/lang/core/world/kvlookup.go b/lang/core/world/kvlookup.go index ad6a5950c..5b3da01df 100644 --- a/lang/core/world/kvlookup.go +++ b/lang/core/world/kvlookup.go @@ -51,12 +51,15 @@ func init() { funcs.ModuleRegister(ModuleName, KVLookupFuncName, func() interfaces.Func { return &KVLookupFunc{} }) } +var _ interfaces.CallableFunc = &KVLookupFunc{} + // KVLookupFunc is special function which returns all the values of a given key // in the exposed world. It is similar to exchange, but it does not set a key. type KVLookupFunc struct { init *interfaces.Init namespace string + args []types.Value last types.Value result types.Value // last calculated output @@ -127,7 +130,13 @@ func (obj *KVLookupFunc) Stream(ctx context.Context) error { } obj.last = input // store for next - namespace := input.Struct()[kvLookupArgNameNamespace].Str() + args, err := interfaces.StructToCallableArgs(input) // []types.Value, error) + if err != nil { + return err + } + obj.args = args + + namespace := args[0].Str() if namespace == "" { return fmt.Errorf("can't use an empty namespace") } @@ -145,7 +154,7 @@ func (obj *KVLookupFunc) Stream(ctx context.Context) error { return err } - result, err := obj.buildMap(ctx) // build the map... + result, err := obj.Call(ctx, obj.args) // build the map... if err != nil { return err } @@ -174,7 +183,7 @@ func (obj *KVLookupFunc) Stream(ctx context.Context) error { return errwrap.Wrapf(err, "channel watch failed on `%s`", obj.namespace) } - result, err := obj.buildMap(ctx) // build the map... + result, err := obj.Call(ctx, obj.args) // build the map... if err != nil { return err } @@ -198,11 +207,14 @@ func (obj *KVLookupFunc) Stream(ctx context.Context) error { } } -// buildMap builds the result map which we'll need. It uses struct variables. -func (obj *KVLookupFunc) buildMap(ctx context.Context) (types.Value, error) { - keyMap, err := obj.init.World.StrMapGet(ctx, obj.namespace) +// Call this function with the input args and return the value if it is possible +// to do so at this time. This was previously buildMap, which builds the result +// map which we'll need. It uses struct variables. +func (obj *KVLookupFunc) Call(ctx context.Context, args []types.Value) (types.Value, error) { + namespace := args[0].Str() + keyMap, err := obj.init.World.StrMapGet(ctx, namespace) if err != nil { - return nil, errwrap.Wrapf(err, "channel read failed on `%s`", obj.namespace) + return nil, errwrap.Wrapf(err, "channel read failed on `%s`", namespace) } d := types.NewMap(obj.Info().Sig.Out)