Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit d417b47

Browse files
committed
add support for 'required' tag value
1 parent 14428cd commit d417b47

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

mapstructure.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,9 +1230,19 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
12301230
fieldName := field.Name
12311231

12321232
tagValue := field.Tag.Get(d.config.TagName)
1233-
tagValue = strings.SplitN(tagValue, ",", 2)[0]
1234-
if tagValue != "" {
1235-
fieldName = tagValue
1233+
tagFieldValue := strings.SplitN(tagValue, ",", 2)[0]
1234+
if tagFieldValue != "" {
1235+
fieldName = tagFieldValue
1236+
}
1237+
1238+
// If "required" is specified in the tag, we need make sure it is present.
1239+
required := false
1240+
tagParts := strings.Split(tagValue, ",")
1241+
for _, tag := range tagParts[1:] {
1242+
if tag == "required" {
1243+
required = true
1244+
break
1245+
}
12361246
}
12371247

12381248
rawMapKey := reflect.ValueOf(fieldName)
@@ -1255,6 +1265,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
12551265
}
12561266

12571267
if !rawMapVal.IsValid() {
1268+
if required {
1269+
err := fmt.Errorf("'%s' is missing required key: %s", name, fieldName)
1270+
errors = appendErrors(errors, err)
1271+
}
12581272
// There was no matching key in the map for the value in
12591273
// the struct. Just ignore.
12601274
continue

mapstructure_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ type StructWithOmitEmpty struct {
160160
OmitMapField map[string]interface{} `mapstructure:"omittable-map,omitempty"`
161161
NestedField *Nested `mapstructure:"visible-nested"`
162162
OmitNestedField *Nested `mapstructure:"omittable-nested,omitempty"`
163+
type Required struct {
164+
RequiredBar string `mapstructure:"bar,required"`
165+
Value string `mapstructure:"foo"`
163166
}
164167

165168
type TypeConversionResult struct {
@@ -2230,6 +2233,17 @@ func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) {
22302233

22312234
if !reflect.DeepEqual(actual, expected) {
22322235
t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
2236+
func TestRequired(t *testing.T) {
2237+
t.Parallel()
2238+
2239+
input := map[string]interface{}{
2240+
"foo": "bar",
2241+
}
2242+
2243+
var result Required
2244+
err := Decode(input, &result)
2245+
if err == nil {
2246+
t.Fatal("unexpected success decoding required field was missing")
22332247
}
22342248
}
22352249

0 commit comments

Comments
 (0)