mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +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:
		| @@ -4,8 +4,9 @@ import "github.com/MontFerret/ferret/pkg/runtime/core" | ||||
|  | ||||
| func NewLib() map[string]core.Function { | ||||
| 	return map[string]core.Function{ | ||||
| 		"HAS":  Has, | ||||
| 		"KEYS": Keys, | ||||
| 		"KEEP": Keep, | ||||
| 		"HAS":   Has, | ||||
| 		"KEYS":  Keys, | ||||
| 		"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) | ||||
| 	}) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user