2018-10-25 14:01:25 +02:00
|
|
|
package objects
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
2019-02-13 19:31:18 +02:00
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
2018-10-25 14:01:25 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// MergeRecursive recursively merge the given objects into a single object.
|
|
|
|
// @params objs (Objects) - objects to merge.
|
|
|
|
// @returns (Object) - Object created by merging.
|
|
|
|
func MergeRecursive(_ context.Context, args ...core.Value) (core.Value, error) {
|
|
|
|
err := core.ValidateArgs(args, 1, core.MaxArgs)
|
|
|
|
if err != nil {
|
|
|
|
return values.None, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, arg := range args {
|
2019-02-13 19:31:18 +02:00
|
|
|
if err = core.ValidateType(arg, types.Object); err != nil {
|
2018-10-25 14:01:25 +02:00
|
|
|
return values.None, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
merged := values.NewObject()
|
|
|
|
|
|
|
|
for _, arg := range args {
|
|
|
|
merged = merge(merged, arg).(*values.Object)
|
|
|
|
}
|
|
|
|
|
|
|
|
return merged.Clone(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func merge(src, dst core.Value) core.Value {
|
|
|
|
if src.Type() != dst.Type() {
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
if src.Type() != types.Object {
|
2018-10-25 14:01:25 +02:00
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
srcObj := src.(*values.Object)
|
|
|
|
dstObj := dst.(*values.Object)
|
|
|
|
|
|
|
|
if dstObj.Length() == 0 {
|
|
|
|
return src
|
|
|
|
}
|
|
|
|
|
|
|
|
keyObj := values.NewString("")
|
|
|
|
exists := values.NewBoolean(false)
|
|
|
|
var srcVal core.Value
|
|
|
|
|
|
|
|
dstObj.ForEach(func(val core.Value, key string) bool {
|
|
|
|
keyObj = values.NewString(key)
|
|
|
|
|
|
|
|
if srcVal, exists = srcObj.Get(keyObj); exists {
|
|
|
|
val = merge(srcVal, val)
|
|
|
|
}
|
|
|
|
|
|
|
|
srcObj.Set(keyObj, val)
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
return src
|
|
|
|
}
|