mirror of
https://github.com/MontFerret/ferret.git
synced 2025-03-05 15:16:07 +02:00
added MERGE object function (#111)
* add pkg/stdlib/objects Length function * rename lenght.go -> length.go * fix tests according to other tests * add new tests to length tests * delete objects method Length * add objects method Has * add objects function Keys * small fixes in Keys and Has functions * change Has function * unit tests for Keys function * add unit tests for merge. also little change in lib.go * add doc to Keys function * Merge function prototype * add unit tests for KEEP function * added KEEP function * added doc for KEYS function * update lib.go * update lib.go * upd merge prototype * addded isEqualObjects function to objects tests * change object method Compare * added unit tests for Compare method * changed Compare method * fix Compare method * rename method Clone to Copy * added Cloneable interface * added Value to Cloneable interface * implemented Cloneable intefrace by array * added some more unit tests for values.Array * fix values.Array.Compare method * added one more unit test * implemented Cloneable interface by Object * unit tests for Object.Clone * move core.IsCloneable to value.go * change Clone function * move IsClonable to package values * updated MERGE unit tests * added MERGE function * added MERGE to lib * added one more test * changed MERGE function
This commit is contained in:
parent
42757a2a5a
commit
446ce3ead5
@ -4,8 +4,9 @@ import "github.com/MontFerret/ferret/pkg/runtime/core"
|
|||||||
|
|
||||||
func NewLib() map[string]core.Function {
|
func NewLib() map[string]core.Function {
|
||||||
return map[string]core.Function{
|
return map[string]core.Function{
|
||||||
"HAS": Has,
|
"HAS": Has,
|
||||||
"KEYS": Keys,
|
"KEYS": Keys,
|
||||||
"KEEP": Keep,
|
"KEEP": Keep,
|
||||||
|
"MERGE": Merge,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
63
pkg/stdlib/objects/merge.go
Normal file
63
pkg/stdlib/objects/merge.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||||
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge the given objects into a single object.
|
||||||
|
* @params objs (Array Of Object OR Objects) - objects to merge.
|
||||||
|
* @returns (Object) - Object created by merging.
|
||||||
|
*/
|
||||||
|
func Merge(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||||
|
err := core.ValidateArgs(args, 1, core.MaxArgs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return values.None, err
|
||||||
|
}
|
||||||
|
|
||||||
|
objs := values.NewArrayWith(args...)
|
||||||
|
|
||||||
|
if len(args) == 1 && args[0].Type() == core.ArrayType {
|
||||||
|
objs = args[0].(*values.Array)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validateArrayOf(core.ObjectType, objs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return values.None, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeArray(objs), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeArray(arr *values.Array) *values.Object {
|
||||||
|
merged, obj := values.NewObject(), values.NewObject()
|
||||||
|
|
||||||
|
arr.ForEach(func(arrValue core.Value, arrIdx int) bool {
|
||||||
|
obj = arrValue.(*values.Object)
|
||||||
|
obj.ForEach(func(objValue core.Value, objKey string) bool {
|
||||||
|
if values.IsCloneable(objValue) {
|
||||||
|
objValue = objValue.(core.Cloneable).Clone()
|
||||||
|
}
|
||||||
|
merged.Set(values.NewString(objKey), objValue)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateArrayOf(typ core.Type, arr *values.Array) (err error) {
|
||||||
|
for idx := values.NewInt(0); idx < arr.Length(); idx++ {
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = core.ValidateType(arr.Get(idx), typ)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
165
pkg/stdlib/objects/merge_test.go
Normal file
165
pkg/stdlib/objects/merge_test.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package objects_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
|
"github.com/MontFerret/ferret/pkg/stdlib/objects"
|
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMerge(t *testing.T) {
|
||||||
|
Convey("When not enought arguments", t, func() {
|
||||||
|
obj, err := objects.Merge(context.Background())
|
||||||
|
|
||||||
|
So(err, ShouldBeError)
|
||||||
|
So(obj.Compare(values.None), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When wrong type of arguments", t, func() {
|
||||||
|
obj, err := objects.Merge(context.Background(), values.NewInt(0))
|
||||||
|
|
||||||
|
So(err, ShouldBeError)
|
||||||
|
So(obj.Compare(values.None), ShouldEqual, 0)
|
||||||
|
|
||||||
|
obj, err = objects.Merge(context.Background(), values.NewObject(), values.NewInt(0))
|
||||||
|
|
||||||
|
So(err, ShouldBeError)
|
||||||
|
So(obj.Compare(values.None), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When too many arrays", t, func() {
|
||||||
|
obj, err := objects.Merge(context.Background(), values.NewArray(0), values.NewArray(0))
|
||||||
|
|
||||||
|
So(err, ShouldBeError)
|
||||||
|
So(obj.Compare(values.None), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Merged object should be independent of source objects", t, func() {
|
||||||
|
obj1 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
)
|
||||||
|
obj2 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop3", values.NewInt(3)),
|
||||||
|
)
|
||||||
|
|
||||||
|
result := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
values.NewObjectProperty("prop3", values.NewInt(3)),
|
||||||
|
)
|
||||||
|
|
||||||
|
merged, err := objects.Merge(context.Background(), obj1, obj2)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
obj1.Remove(values.NewString("prop1"))
|
||||||
|
|
||||||
|
So(merged.Compare(result), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeObjects(t *testing.T) {
|
||||||
|
Convey("Merge single object", t, func() {
|
||||||
|
obj1 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
)
|
||||||
|
result := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
)
|
||||||
|
|
||||||
|
merged, err := objects.Merge(context.Background(), obj1)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(merged.Compare(result), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Merge two objects", t, func() {
|
||||||
|
obj1 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
)
|
||||||
|
obj2 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop3", values.NewInt(3)),
|
||||||
|
)
|
||||||
|
|
||||||
|
result := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
values.NewObjectProperty("prop3", values.NewInt(3)),
|
||||||
|
)
|
||||||
|
|
||||||
|
merged, err := objects.Merge(context.Background(), obj1, obj2)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(merged.Compare(result), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When keys are repeated", t, func() {
|
||||||
|
obj1 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
)
|
||||||
|
obj2 := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(3)),
|
||||||
|
)
|
||||||
|
result := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(3)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewString("str")),
|
||||||
|
)
|
||||||
|
|
||||||
|
merged, err := objects.Merge(context.Background(), obj1, obj2)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(merged.Compare(result), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeArray(t *testing.T) {
|
||||||
|
Convey("Merge array", t, func() {
|
||||||
|
objArr := values.NewArrayWith(
|
||||||
|
values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
),
|
||||||
|
values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop2", values.NewInt(2)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
result := values.NewObjectWith(
|
||||||
|
values.NewObjectProperty("prop1", values.NewInt(1)),
|
||||||
|
values.NewObjectProperty("prop2", values.NewInt(2)),
|
||||||
|
)
|
||||||
|
|
||||||
|
merged, err := objects.Merge(context.Background(), objArr)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(merged.Compare(result), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Merge empty array", t, func() {
|
||||||
|
objArr := values.NewArray(0)
|
||||||
|
result := values.NewObject()
|
||||||
|
|
||||||
|
merged, err := objects.Merge(context.Background(), objArr)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(merged.Compare(result), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When there is not object element inside the array", t, func() {
|
||||||
|
objArr := values.NewArrayWith(
|
||||||
|
values.NewObject(),
|
||||||
|
values.NewInt(0),
|
||||||
|
)
|
||||||
|
|
||||||
|
obj, err := objects.Merge(context.Background(), objArr)
|
||||||
|
|
||||||
|
So(err, ShouldBeError)
|
||||||
|
So(obj.Compare(values.None), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user