From 223a7e25db6aa257b49507dc9d87f8668fc11b38 Mon Sep 17 00:00:00 2001 From: Jared O'Connell <46976761+jaredoconnell@users.noreply.github.com> Date: Wed, 6 Dec 2023 17:46:39 -0500 Subject: [PATCH] Switch to including default values (#67) * Switch to including default values * Changed defaults behavior for struct mapped objects, and added tests * break up long lines --------- Co-authored-by: Matthew F Leader --- schema/object.go | 22 +++++------- schema/object_test.go | 81 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/schema/object.go b/schema/object.go index 3c347ba..ebc2c2f 100644 --- a/schema/object.go +++ b/schema/object.go @@ -36,7 +36,7 @@ type ObjectSchema struct { IDValue string `json:"id"` PropertiesValue map[string]*PropertySchema `json:"properties"` - defaultValues map[string]any + defaultValues map[string]any // Key: Object field name, value: The default value defaultValue any defaultValueType reflect.Type @@ -78,16 +78,16 @@ func (o *ObjectSchema) Properties() map[string]*PropertySchema { func (o *ObjectSchema) Unserialize(data any) (result any, err error) { v := reflect.ValueOf(data) if v.Kind() != reflect.Map { - return result, &ConstraintError{ + return nil, &ConstraintError{ Message: fmt.Sprintf("Must be a map, %T given", data), } } rawData, err := o.convertData(v) if err != nil { - return result, err + return nil, err } if err := o.validateFieldInterdependencies(rawData); err != nil { - return result, err + return nil, err } if o.fieldCache != nil { @@ -153,7 +153,7 @@ func (o *ObjectSchema) serializeMap(data map[string]any) (any, error) { return nil, err } - rawData := map[string]any{} + rawSerializedData := map[string]any{} for k, v := range data { property, ok := o.PropertiesValue[k] if !ok { @@ -163,12 +163,9 @@ func (o *ObjectSchema) serializeMap(data map[string]any) (any, error) { if err != nil { return nil, ConstraintErrorAddPathSegment(err, k) } - defaultValue, hasDefaultValue := o.defaultValues[k] - if !hasDefaultValue && defaultValue != serializedValue { - rawData[k] = serializedValue - } + rawSerializedData[k] = serializedValue } - return rawData, nil + return rawSerializedData, nil } func (o *ObjectSchema) serializeStruct(data any) (any, error) { @@ -221,10 +218,7 @@ func (o *ObjectSchema) extractPropertyValue(propertyID string, v reflect.Value, if err != nil { return nil, ConstraintErrorAddPathSegment(err, propertyID) } - if defaultValue, ok := o.defaultValues[propertyID]; !ok || defaultValue != serializedData { - return &serializedData, nil - } - return nil, nil + return &serializedData, nil } func (o *ObjectSchema) getFieldReflection(propertyID string, v reflect.Value, property *PropertySchema) *reflect.Value { diff --git a/schema/object_test.go b/schema/object_test.go index d4adb41..aa73da1 100644 --- a/schema/object_test.go +++ b/schema/object_test.go @@ -2,6 +2,7 @@ package schema_test import ( "go.arcalot.io/assert" + "strconv" "testing" "go.flow.arcalot.io/pluginsdk/schema" @@ -426,6 +427,86 @@ func TestTypedObjectSchema_Any(t *testing.T) { assert.Error(t, err) } +func TestDefaultsStructSerialization(t *testing.T) { + type TestData struct { + Foo *string `json:"foo"` + } + default_foo_value := "abc" + s := schema.NewTypedObject[TestData]( + "TestData", + map[string]*schema.PropertySchema{ + "foo": schema.NewPropertySchema( + schema.NewStringSchema(nil, nil, nil), + nil, + false, + nil, + nil, + nil, + schema.PointerTo(strconv.Quote(default_foo_value)), + nil, + ), + }, + ) + // First, unserialization + unserialized, err := s.Unserialize(map[string]any{}) + assert.NoError(t, err) + assert.NotNil(t, unserialized) + assert.InstanceOf[TestData](t, unserialized) + assert.NotNil(t, unserialized.(TestData).Foo) + // Validate that default is included + assert.Equals(t, *unserialized.(TestData).Foo, default_foo_value) + + // Next, serialization. + serialized, err := s.Serialize(unserialized) + assert.NoError(t, err) + assert.NotNil(t, serialized) + assert.InstanceOf[map[string]any](t, serialized) + actual_value := assert.MapContainsKey[string]( + t, "foo", serialized.(map[string]any)) + assert.Equals(t, + actual_value.(string), + default_foo_value) +} + +func TestDefaultsObjectSerialization(t *testing.T) { + foo_key := "foo" + default_foo_value := "abc" + + s := schema.NewObjectSchema( + "TestData", + map[string]*schema.PropertySchema{ + foo_key: schema.NewPropertySchema( + schema.NewStringSchema(nil, nil, nil), + nil, + false, + nil, + nil, + nil, + schema.PointerTo(strconv.Quote(default_foo_value)), + nil, + ), + }, + ) + // First, unserialization + unserialized, err := s.Unserialize(map[string]any{}) + assert.NoError(t, err) + assert.NotNil(t, unserialized) + assert.InstanceOf[map[string]any](t, unserialized) + assert.MapContainsKey[string](t, foo_key, unserialized.(map[string]any)) + // Validate that default is included + assert.Equals(t, + unserialized.(map[string]any)[foo_key].(string), default_foo_value) + + // Next, serialization. + serialized, err := s.Serialize(unserialized) + assert.NoError(t, err) + assert.NotNil(t, serialized) + assert.InstanceOf[map[string]any](t, serialized) + actual_value := assert.MapContainsKey[string]( + t, foo_key, serialized.(map[string]any)) + assert.Equals(t, actual_value.(string), default_foo_value) +} + var testStructScope = schema.NewScopeSchema(&testStructSchema.ObjectSchema) func TestObjectSchema_ValidateCompatibility(t *testing.T) {