expr icon indicating copy to clipboard operation
expr copied to clipboard

type conversion

Open alexec opened this issue 4 years ago • 9 comments

I want to do the following

expr.Eval("value + 2", map[string]interface{"value": "1"})

But value is a string. Casting func?

expr.Eval("int(value) + 2", map[string]interface{"value": "1"})

alexec avatar Feb 12 '21 00:02 alexec

You can add helper. Like this: func Int(s string) { ... }

antonmedv avatar Feb 12 '21 07:02 antonmedv

It would be nice to have build in support.

alexec avatar Feb 12 '21 16:02 alexec

I was thinking about it too. But still can’t find good solution what will simple enough to explain to not programmer users of expr.

antonmedv avatar Feb 12 '21 22:02 antonmedv

could it be optional? E.g expr.TypeConvertors()

In Golang, I think there are only so many conversions you can do. One challenge is if the casting was not sensible due to loss of accuracy (e.g. to float64) or just invalid (the string "foo" to int)

alexec avatar Feb 12 '21 22:02 alexec

Yes, we need to find reasonable behaviour in case of loss of accuracy , or other errors.

antonmedv avatar Feb 13 '21 07:02 antonmedv

var castErr error // stash any casting error here
	replaceMap["int"] = func(s string) int {
		v, err := strconv.Atoi(s)
		if err != nil {
			castErr = fmt.Errorf("failed to cast %q to int: %w", s, err)
		}
		return v
	}
	replaceMap["array"] = func(s string) []interface{} {
		array := make([]interface{}, 0)
		if err := json.Unmarshal([]byte(s), &array); err != nil {
			castErr = fmt.Errorf("failed to cast %q to array: %w", s, err)
		}
		return array
	}

	result, err := expr.Eval(expression, bellows.Expand(replaceMap))
	if err == nil {
		err = castErr
	}
	if err != nil {
		return nil, fmt.Errorf("failed to evaluate expression %q: %w", expression, err)
	}

alexec avatar Feb 14 '21 00:02 alexec

Array cast looks more like Json.parse.

antonmedv avatar Feb 14 '21 09:02 antonmedv

One solution to this might be for users to add the Sprig functions. They have a big library and it seems to work nicely:

http://masterminds.github.io/sprig/conversion.html

There are security issues with Sprig methinks, need to understand what sub-set of commands are safe.

alexec avatar Feb 16 '21 02:02 alexec

I think adding some basic casting based on https://github.com/spf13/cast would be useful.

toFloat, toString, ...

paralin avatar Jan 06 '22 22:01 paralin

Looking forward to this enhancement. It would be a massive life-saving feature by avoiding putting custom patch functions in every time into map.

I was thinking about this, maybe you can introduce a new Node type: ConversionNode with a new OpCode: OpConversion. (IDK there is already a OpCast opcode, it seems to do something for the config.Expect stuff) - don't know much about the internals, just using the keywords as a placeholder.

But still can’t find good solution what will simple enough - @antonmedv

What about:

  • float64(Foo.Bar)
  • int("Baz.Qux")
  • string(Quux)

If conversion fails, the Compile() func should return an error.

Dentrax avatar Nov 15 '22 17:11 Dentrax

Yeah, I’m working on adding this feature)

antonmedv avatar Nov 15 '22 17:11 antonmedv

Added int() and float().

antonmedv avatar Jan 30 '23 21:01 antonmedv