Skip to content

Commit

Permalink
use option instead of tag
Browse files Browse the repository at this point in the history
  • Loading branch information
zak905 committed Mar 12, 2022
1 parent 36c9802 commit 57be419
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 40 deletions.
31 changes: 21 additions & 10 deletions cache.go
Expand Up @@ -17,21 +17,19 @@ var invalidPath = errors.New("schema: invalid path")
// newCache returns a new cache.
func newCache() *cache {
c := cache{
m: make(map[reflect.Type]*structInfo),
regconv: make(map[reflect.Type]Converter),
tag: "schema",
defaultTag: "default",
m: make(map[reflect.Type]*structInfo),
regconv: make(map[reflect.Type]Converter),
tag: "schema",
}
return &c
}

// cache caches meta-data about a struct.
type cache struct {
l sync.RWMutex
m map[reflect.Type]*structInfo
regconv map[reflect.Type]Converter
tag string
defaultTag string
l sync.RWMutex
m map[reflect.Type]*structInfo
regconv map[reflect.Type]Converter
tag string
}

// registerConverter registers a converter function for a custom type.
Expand Down Expand Up @@ -199,7 +197,7 @@ func (c *cache) createField(field reflect.StructField, parentAlias string) *fiel
isSliceOfStructs: isSlice && isStruct,
isAnonymous: field.Anonymous,
isRequired: options.Contains("required"),
defaultValue: field.Tag.Get(c.defaultTag),
defaultValue: options.getDefaultOptionValue(),
}
}

Expand Down Expand Up @@ -307,3 +305,16 @@ func (o tagOptions) Contains(option string) bool {
}
return false
}

func (o tagOptions) getDefaultOptionValue() string {
for _, s := range o {
if strings.HasPrefix(s, "default:") {
if t := strings.Split(s, ":"); len(t) > 0 {
return t[1]
}
break
}
}

return ""
}
4 changes: 2 additions & 2 deletions decoder.go
Expand Up @@ -117,12 +117,12 @@ func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError {
errs.merge(MultiError{"default-" + f.name: errors.New("required fields cannot have a default value")})
} else if f.defaultValue != "" && vCurrent.IsZero() && !f.isRequired {
if f.typ.Kind() == reflect.Struct || f.typ.Kind() == reflect.Slice {
errs.merge(MultiError{"default-" + f.name: errors.New("default tag is supported only on: bool, float variants, string, unit variants types or their corresponding pointers")})
errs.merge(MultiError{"default-" + f.name: errors.New("default option is supported only on: bool, float variants, string, unit variants types or their corresponding pointers")})
} else if f.typ.Kind() == reflect.Ptr {
t1 := f.typ.Elem()

if t1.Kind() == reflect.Struct || t1.Kind() == reflect.Slice {
errs.merge(MultiError{"default-" + f.name: errors.New("default tag is supported only on: bool, float variants, string, unit variants types or their corresponding pointers")})
errs.merge(MultiError{"default-" + f.name: errors.New("default option is supported only on: bool, float variants, string, unit variants types or their corresponding pointers")})
}

vCurrent.Set(convertPointer(t1.Kind(), f.defaultValue))
Expand Down
53 changes: 25 additions & 28 deletions decoder_test.go
Expand Up @@ -2027,20 +2027,18 @@ func TestUnmashalPointerToEmbedded(t *testing.T) {

func TestDefaultValuesAreSet(t *testing.T) {

//TODO: Test nesting and update repos

type N struct {
S1 string `schema:"s1" default:"test1"`
I2 int `schema:"i2" default:"22"`
S1 string `schema:"s1,default:test1"`
I2 int `schema:"i2,default:22"`
}

type D struct {
N
S string `schema:"s" default:"test1"`
I int `schema:"i" default:"21"`
B bool `schema:"b" default:"false"`
F float64 `schema:"f" default:"3.14"`
U uint `schema:"u" default:"1"`
S string `schema:"s,default:test1"`
I int `schema:"i,default:21"`
B bool `schema:"b,default:false"`
F float64 `schema:"f,default:3.14"`
U uint `schema:"u,default:1"`
}

data := map[string][]string{}
Expand Down Expand Up @@ -2071,11 +2069,11 @@ func TestDefaultValuesAreSet(t *testing.T) {

type P struct {
*N
S *string `schema:"s" default:"test1"`
I *int `schema:"i" default:"21"`
B *bool `schema:"b" default:"false"`
F *float64 `schema:"f" default:"3.14"`
U *uint `schema:"u" default:"1"`
S *string `schema:"s,default:test1"`
I *int `schema:"i,default:21"`
B *bool `schema:"b,default:false"`
F *float64 `schema:"f,default:3.14"`
U *uint `schema:"u,default:1"`
}

p := P{N: &N{}}
Expand All @@ -2099,11 +2097,11 @@ func TestDefaultValuesAreSet(t *testing.T) {

func TestDefaultValuesAreIgnoredIfValuesAreProvided(t *testing.T) {
type D struct {
S string `schema:"s" default:"test1"`
I int `schema:"i" default:"21"`
B bool `schema:"b" default:"false"`
F float64 `schema:"f" default:"3.14"`
U uint `schema:"u" default:"1"`
S string `schema:"s,default:test1"`
I int `schema:"i,default:21"`
B bool `schema:"b,default:false"`
F float64 `schema:"f,default:3.14"`
U uint `schema:"u,default:1"`
}

data := map[string][]string{"s": {"s"}, "i": {"1"}, "b": {"true"}, "f": {"0.22"}, "u": {"14"}}
Expand Down Expand Up @@ -2132,11 +2130,11 @@ func TestDefaultValuesAreIgnoredIfValuesAreProvided(t *testing.T) {
func TestRequiredFieldsCannotHaveDefaults(t *testing.T) {

type D struct {
S string `schema:"s,required" default:"test1"`
I int `schema:"i,required" default:"21"`
B bool `schema:"b,required" default:"false"`
F float64 `schema:"f,required" default:"3.14"`
U uint `schema:"u,required" default:"1"`
S string `schema:"s,required,default:test1"`
I int `schema:"i,required,default:21"`
B bool `schema:"b,required,default:false"`
F float64 `schema:"f,required,default:3.14"`
U uint `schema:"u,required,default:1"`
}

data := map[string][]string{"s": {"s"}, "i": {"1"}, "b": {"true"}, "f": {"0.22"}, "u": {"14"}}
Expand All @@ -2158,8 +2156,8 @@ func TestRequiredFieldsCannotHaveDefaults(t *testing.T) {
func TestDefaultsAreNotSupportedForStructsAndSlices(t *testing.T) {

type D struct {
S S1 `schema:"s" default:"{f1:0}"`
A []string `schema:"s" default:"test1,test2"`
S S1 `schema:"s,default:{f1:0}"`
A []string `schema:"s,default:test1,test2"`
}

d := D{}
Expand All @@ -2170,10 +2168,9 @@ func TestDefaultsAreNotSupportedForStructsAndSlices(t *testing.T) {

err := decoder.Decode(&d, data)

expected := "default tag is supported only on: bool, float variants, string, unit variants types or their corresponding pointers"
expected := "default option is supported only on: bool, float variants, string, unit variants types or their corresponding pointers"

if err == nil || !strings.Contains(err.Error(), expected) {
t.Errorf("decoding should fail with error msg %s got %q", expected, err)
}

}

0 comments on commit 57be419

Please sign in to comment.