mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
Add toPairs() and fromPairs()
This commit is contained in:
@@ -584,6 +584,70 @@ var Builtins = []*ast.Function{
|
||||
return anyType, fmt.Errorf("cannot get values from %s", args[0])
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "toPairs",
|
||||
Func: func(args ...any) (any, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf("cannot transform %s to pairs", v.Kind())
|
||||
}
|
||||
keys := v.MapKeys()
|
||||
out := make([][2]any, len(keys))
|
||||
for i, key := range keys {
|
||||
out[i] = [2]any{key.Interface(), v.MapIndex(key).Interface()}
|
||||
}
|
||||
return out, nil
|
||||
},
|
||||
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
||||
if len(args) != 1 {
|
||||
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
switch kind(args[0]) {
|
||||
case reflect.Interface, reflect.Map:
|
||||
return arrayType, nil
|
||||
}
|
||||
return anyType, fmt.Errorf("cannot transform %s to pairs", args[0])
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "fromPairs",
|
||||
Func: func(args ...any) (any, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
v := reflect.ValueOf(args[0])
|
||||
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||
return nil, fmt.Errorf("cannot transform %s from pairs", v)
|
||||
}
|
||||
out := reflect.MakeMap(mapType)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
pair := deref(v.Index(i))
|
||||
if pair.Kind() != reflect.Array && pair.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("invalid pair %v", pair)
|
||||
}
|
||||
if pair.Len() != 2 {
|
||||
return nil, fmt.Errorf("invalid pair length %v", pair)
|
||||
}
|
||||
key := pair.Index(0)
|
||||
value := pair.Index(1)
|
||||
out.SetMapIndex(key, value)
|
||||
}
|
||||
return out.Interface(), nil
|
||||
},
|
||||
Validate: func(args []reflect.Type) (reflect.Type, error) {
|
||||
if len(args) != 1 {
|
||||
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
|
||||
}
|
||||
switch kind(args[0]) {
|
||||
case reflect.Interface, reflect.Slice, reflect.Array:
|
||||
return mapType, nil
|
||||
}
|
||||
return anyType, fmt.Errorf("cannot transform %s from pairs", args[0])
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sort",
|
||||
Func: func(args ...any) (any, error) {
|
||||
|
||||
@@ -94,6 +94,10 @@ func TestBuiltin(t *testing.T) {
|
||||
{`get({foo: 1, bar: 2}, "unknown")`, nil},
|
||||
{`"foo" in keys({foo: 1, bar: 2})`, true},
|
||||
{`1 in values({foo: 1, bar: 2})`, true},
|
||||
{`len(toPairs({foo: 1, bar: 2}))`, 2},
|
||||
{`len(toPairs({}))`, 0},
|
||||
{`fromPairs([["foo", 1], ["bar", 2]])`, map[any]any{"foo": 1, "bar": 2}},
|
||||
{`fromPairs(toPairs({foo: 1, bar: 2}))`, map[any]any{"foo": 1, "bar": 2}},
|
||||
{`groupBy(1..9, # % 2)`, map[any][]any{0: {2, 4, 6, 8}, 1: {1, 3, 5, 7, 9}}},
|
||||
{`groupBy(1..9, # % 2)[0]`, []any{2, 4, 6, 8}},
|
||||
{`groupBy(1..3, # > 1)[true]`, []any{2, 3}},
|
||||
|
||||
+1
-1
@@ -9,8 +9,8 @@ var (
|
||||
anyType = reflect.TypeOf(new(any)).Elem()
|
||||
integerType = reflect.TypeOf(0)
|
||||
floatType = reflect.TypeOf(float64(0))
|
||||
stringType = reflect.TypeOf("")
|
||||
arrayType = reflect.TypeOf([]any{})
|
||||
mapType = reflect.TypeOf(map[any]any{})
|
||||
)
|
||||
|
||||
func kind(t reflect.Type) reflect.Kind {
|
||||
|
||||
Reference in New Issue
Block a user