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  }