7
7
package bsoncodec
8
8
9
9
import (
10
- "bytes"
11
10
"errors"
12
11
"fmt"
13
12
"reflect"
@@ -39,16 +38,21 @@ func (de *DecodeError) Unwrap() error {
39
38
// Error implements the error interface.
40
39
func (de * DecodeError ) Error () string {
41
40
// The keys are stored in reverse order because the de.keys slice is builtup while propagating the error up the
42
- // stack of BSON keys. Reverse the keys and join them with "." as they're reversed.
43
- var keyPattern bytes.Buffer
41
+ // stack of BSON keys, so we call de.Keys(), which reverses them.
42
+ keyPath := strings .Join (de .Keys (), "." )
43
+ return fmt .Sprintf ("error decoding key %s: %v" , keyPath , de .wrapped )
44
+ }
45
+
46
+ // Keys returns the BSON key path that caused an error as a slice of strings. The keys in the slice are in top-down
47
+ // order. For example, if the document being unmarshalled was {a: {b: {c: 1}}} and the value for c was supposed to be
48
+ // a string, the keys slice will be ["a", "b", "c"].
49
+ func (de * DecodeError ) Keys () []string {
50
+ reversedKeys := make ([]string , 0 , len (de .keys ))
44
51
for idx := len (de .keys ) - 1 ; idx >= 0 ; idx -- {
45
- keyPattern .WriteString (de .keys [idx ])
46
- if idx != 0 {
47
- keyPattern .WriteByte ('.' )
48
- }
52
+ reversedKeys = append (reversedKeys , de .keys [idx ])
49
53
}
50
54
51
- return fmt . Sprintf ( "error decoding key %s: %v" , keyPattern . String (), de . wrapped )
55
+ return reversedKeys
52
56
}
53
57
54
58
// Zeroer allows custom struct types to implement a report of zero
@@ -206,11 +210,6 @@ func newDecodeError(key string, original error) error {
206
210
return de
207
211
}
208
212
209
- func newDecodeErrorFromFieldDescription (fd fieldDescription , original error ) error {
210
- fullName := fmt .Sprintf ("%s(field %s)" , fd .name , fd .fieldName )
211
- return newDecodeError (fullName , original )
212
- }
213
-
214
213
// DecodeValue implements the Codec interface.
215
214
// By default, map types in val will not be cleared. If a map has existing key/value pairs, it will be extended with the new ones from vr.
216
215
// For slices, the decoder will set the length of the slice to zero and append all elements. The underlying array will not be cleared.
@@ -320,7 +319,7 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
320
319
321
320
if ! field .CanSet () { // Being settable is a super set of being addressable.
322
321
innerErr := fmt .Errorf ("field %v is not settable" , field )
323
- return newDecodeErrorFromFieldDescription (fd , innerErr )
322
+ return newDecodeError (fd . name , innerErr )
324
323
}
325
324
if field .Kind () == reflect .Ptr && field .IsNil () {
326
325
field .Set (reflect .New (field .Type ().Elem ()))
@@ -329,19 +328,19 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
329
328
330
329
dctx := DecodeContext {Registry : r .Registry , Truncate : fd .truncate || r .Truncate }
331
330
if fd .decoder == nil {
332
- return newDecodeErrorFromFieldDescription (fd , ErrNoDecoder {Type : field .Elem ().Type ()})
331
+ return newDecodeError (fd . name , ErrNoDecoder {Type : field .Elem ().Type ()})
333
332
}
334
333
335
334
if decoder , ok := fd .decoder .(ValueDecoder ); ok {
336
335
err = decoder .DecodeValue (dctx , vr , field .Elem ())
337
336
if err != nil {
338
- return newDecodeErrorFromFieldDescription (fd , err )
337
+ return newDecodeError (fd . name , err )
339
338
}
340
339
continue
341
340
}
342
341
err = fd .decoder .DecodeValue (dctx , vr , field )
343
342
if err != nil {
344
- return newDecodeErrorFromFieldDescription (fd , err )
343
+ return newDecodeError (fd . name , err )
345
344
}
346
345
}
347
346
0 commit comments