Skip to content

Commit

Permalink
Switch to including default values (#67)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
jaredoconnell and mfleader authored Dec 6, 2023
1 parent 1064bc1 commit 223a7e2
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 14 deletions.
22 changes: 8 additions & 14 deletions schema/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down
81 changes: 81 additions & 0 deletions schema/object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package schema_test

import (
"go.arcalot.io/assert"
"strconv"
"testing"

"go.flow.arcalot.io/pluginsdk/schema"
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 223a7e2

Please sign in to comment.