github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/objects/zip.go (about) 1 package objects 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/MontFerret/ferret/pkg/runtime/core" 8 "github.com/MontFerret/ferret/pkg/runtime/values" 9 "github.com/MontFerret/ferret/pkg/runtime/values/types" 10 ) 11 12 // ZIP returns an object assembled from the separate parameters keys and values. 13 // Keys and values must be arrays and have the same length. 14 // @param {String[]} keys - An array of strings, to be used as key names in the result. 15 // @param {Object[]} values - An array of core.Value, to be used as key values. 16 // @return {Object} - An object with the keys and values assembled. 17 func Zip(_ context.Context, args ...core.Value) (core.Value, error) { 18 err := core.ValidateArgs(args, 2, 2) 19 20 if err != nil { 21 return values.None, err 22 } 23 24 for _, arg := range args { 25 err = core.ValidateType(arg, types.Array) 26 27 if err != nil { 28 return values.None, err 29 } 30 } 31 32 keys := args[0].(*values.Array) 33 vals := args[1].(*values.Array) 34 35 if keys.Length() != vals.Length() { 36 return values.None, core.Error( 37 core.ErrInvalidArgument, 38 fmt.Sprintf("keys and values must have the same length. got keys: %d, values: %d", 39 keys.Length(), vals.Length(), 40 ), 41 ) 42 } 43 44 err = validateArrayOf(types.String, keys) 45 46 if err != nil { 47 return values.None, err 48 } 49 50 zipped := values.NewObject() 51 52 var k values.String 53 var val core.Value 54 var exists bool 55 keyExists := map[values.String]bool{} 56 57 keys.ForEach(func(key core.Value, idx int) bool { 58 k = key.(values.String) 59 60 // this is necessary to implement ArangoDB's behavior. 61 // in ArangoDB the first value in values is 62 // associated with each key. Ex.: 63 // -- query -- 64 // > RETURN ZIP( 65 // > ["a", "b", "a"], [1, 2, 3] 66 // > ) 67 // -- result -- 68 // > [{"a": 1,"b": 2}] 69 if _, exists = keyExists[k]; exists { 70 return true 71 } 72 keyExists[k] = true 73 74 val = vals.Get(values.NewInt(idx)) 75 cloneable, ok := val.(core.Cloneable) 76 77 if ok { 78 val = cloneable.Clone() 79 } 80 81 zipped.Set(k, val) 82 83 return true 84 }) 85 86 return zipped, nil 87 }