Skip to content

Commit 8724a8b

Browse files
committed
feat(decoder-configs) add AllowUnsetPointer option to skip unset errors for pointer fields
1 parent 1072f34 commit 8724a8b

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

mapstructure.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ type DecoderConfig struct {
222222
// will affect all nested structs as well.
223223
ErrorUnset bool
224224

225+
// AllowUnsetPointer, if set to true, will prevent fields with pointer types
226+
// from being reported as unset, even if ErrorUnset is true and the field was
227+
// not present in the input data. This allows pointer fields to be optional
228+
// without triggering an error when they are missing.
229+
AllowUnsetPointer bool
230+
225231
// ZeroFields, if set to true, will zero fields before writing them.
226232
// For example, a map will be emptied before decoded values are put in
227233
// it. If this is false, a map will be merged.
@@ -1459,9 +1465,9 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
14591465
}
14601466

14611467
if !rawMapVal.IsValid() {
1462-
// There was no matching key in the map for the value in
1463-
// the struct. Remember it for potential errors and metadata.
1464-
targetValKeysUnused[fieldName] = struct{}{}
1468+
if !(d.config.AllowUnsetPointer && fieldValue.Kind() == reflect.Ptr) {
1469+
targetValKeysUnused[fieldName] = struct{}{}
1470+
}
14651471
continue
14661472
}
14671473
}

mapstructure_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,32 @@ func TestDecoder_ErrorUnset(t *testing.T) {
16751675
}
16761676
}
16771677

1678+
func TestDecoder_ErrorUnset_AllowUnsetPointer(t *testing.T) {
1679+
t.Parallel()
1680+
1681+
input := map[string]interface{}{
1682+
"vstring": "hello",
1683+
"foo": "bar",
1684+
}
1685+
1686+
var result BasicPointer
1687+
config := &DecoderConfig{
1688+
ErrorUnset: true,
1689+
AllowUnsetPointer: true,
1690+
Result: &result,
1691+
}
1692+
1693+
decoder, err := NewDecoder(config)
1694+
if err != nil {
1695+
t.Fatalf("err: %s", err)
1696+
}
1697+
1698+
err = decoder.Decode(input)
1699+
if err != nil {
1700+
t.Fatal("error not expected")
1701+
}
1702+
}
1703+
16781704
func TestMap(t *testing.T) {
16791705
t.Parallel()
16801706

0 commit comments

Comments
 (0)