Skip to content

Commit 53d0660

Browse files
committed
Ensure ancestor information is used when decoding
A new Ancestor field is added to the DecodeContext and is used when decoding a BSON Embedded Document into an interface{}. GODRIVER-699 Change-Id: Ie364ff52106e231950b83d3c9a197363d76cf19f
1 parent f43e267 commit 53d0660

File tree

4 files changed

+43
-8
lines changed

4 files changed

+43
-8
lines changed

bson/bsoncodec/bsoncodec.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ type EncodeContext struct {
114114
type DecodeContext struct {
115115
*Registry
116116
Truncate bool
117+
// Ancestor is the type of a containing document. This is mainly used to determine what type
118+
// should be used when decoding an embedded document into an empty interface. For example, if
119+
// Ancestor is a bson.M, BSON embedded document values being decoded into an empty interface
120+
// will be decoded into a bson.M.
121+
Ancestor reflect.Type
117122
}
118123

119124
// ValueCodec is the interface that groups the methods to encode and decode

bson/bsoncodec/default_value_decoders.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
8383
RegisterDefaultDecoder(reflect.Ptr, NewPointerCodec()).
8484
RegisterTypeMapEntry(bsontype.Double, tFloat64).
8585
RegisterTypeMapEntry(bsontype.String, tString).
86-
RegisterTypeMapEntry(bsontype.EmbeddedDocument, tD).
8786
RegisterTypeMapEntry(bsontype.Array, tA).
8887
RegisterTypeMapEntry(bsontype.Binary, tBinary).
8988
RegisterTypeMapEntry(bsontype.Undefined, tUndefined).
@@ -675,6 +674,10 @@ func (dvd DefaultValueDecoders) MapDecodeValue(dc DecodeContext, vr bsonrw.Value
675674
return err
676675
}
677676

677+
if eType == tEmpty {
678+
dc.Ancestor = val.Type()
679+
}
680+
678681
for {
679682
key, vr, err := dr.ReadElement()
680683
if err == bsonrw.ErrEOD {
@@ -758,6 +761,7 @@ func (dvd DefaultValueDecoders) SliceDecodeValue(dc DecodeContext, vr bsonrw.Val
758761
var elemsFunc func(DecodeContext, bsonrw.ValueReader, reflect.Value) ([]reflect.Value, error)
759762
switch val.Type().Elem() {
760763
case tE:
764+
dc.Ancestor = val.Type()
761765
elemsFunc = dvd.decodeD
762766
default:
763767
elemsFunc = dvd.decodeDefault
@@ -852,11 +856,19 @@ func (dvd DefaultValueDecoders) EmptyInterfaceDecodeValue(dc DecodeContext, vr b
852856

853857
rtype, err := dc.LookupTypeMapEntry(vr.Type())
854858
if err != nil {
855-
if vr.Type() == bsontype.Null {
859+
switch vr.Type() {
860+
case bsontype.EmbeddedDocument:
861+
if dc.Ancestor != nil {
862+
rtype = dc.Ancestor
863+
break
864+
}
865+
rtype = tD
866+
case bsontype.Null:
856867
val.Set(reflect.Zero(val.Type()))
857868
return vr.ReadNull()
869+
default:
870+
return err
858871
}
859-
return err
860872
}
861873

862874
decoder, err := dc.LookupDecoder(rtype)

bson/bsoncodec/default_value_decoders_test.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2274,6 +2274,11 @@ func TestDefaultValueDecoders(t *testing.T) {
22742274
AS []byte
22752275
AT map[string]interface{}
22762276
AU primitive.CodeWithScope
2277+
AV primitive.M
2278+
AW primitive.D
2279+
AX map[string]interface{}
2280+
AY []primitive.E
2281+
AZ interface{}
22772282
}{
22782283
A: true,
22792284
B: 123,
@@ -2315,6 +2320,11 @@ func TestDefaultValueDecoders(t *testing.T) {
23152320
AS: nil,
23162321
AT: nil,
23172322
AU: primitive.CodeWithScope{Code: "var hello = 'world';", Scope: primitive.D{{"pi", 3.14159}}},
2323+
AV: primitive.M{"foo": primitive.M{"bar": "baz"}},
2324+
AW: primitive.D{{"foo", primitive.D{{"bar", "baz"}}}},
2325+
AX: map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}},
2326+
AY: []primitive.E{{"foo", []primitive.E{{"bar", "baz"}}}},
2327+
AZ: primitive.D{{"foo", primitive.D{{"bar", "baz"}}}},
23182328
},
23192329
buildDocument(func(doc []byte) []byte {
23202330
doc = bsoncore.AppendBooleanElement(doc, "a", true)
@@ -2361,6 +2371,13 @@ func TestDefaultValueDecoders(t *testing.T) {
23612371
doc = bsoncore.AppendCodeWithScopeElement(doc, "au",
23622372
"var hello = 'world';", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
23632373
)
2374+
for _, name := range [5]string{"av", "aw", "ax", "ay", "az"} {
2375+
doc = bsoncore.AppendDocumentElement(doc, name, buildDocument(
2376+
bsoncore.AppendDocumentElement(nil, "foo", buildDocument(
2377+
bsoncore.AppendStringElement(nil, "bar", "baz"),
2378+
)),
2379+
))
2380+
}
23642381
return doc
23652382
}(nil)),
23662383
nil,
@@ -2576,11 +2593,6 @@ func TestDefaultValueDecoders(t *testing.T) {
25762593
string("foo bar baz"),
25772594
bsontype.String,
25782595
},
2579-
{
2580-
"Embedded Document - primitive.D",
2581-
primitive.D{{"foo", nil}},
2582-
bsontype.EmbeddedDocument,
2583-
},
25842596
{
25852597
"Array - primitive.A",
25862598
primitive.A{3.14159},

bson/bsoncodec/registry.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ func (rb *RegistryBuilder) RegisterDefaultDecoder(kind reflect.Kind, dec ValueDe
191191
// RegisterTypeMapEntry will register the provided type to the BSON type. The primary usage for this
192192
// mapping is decoding situations where an empty interface is used and a default type needs to be
193193
// created and decoded into.
194+
//
195+
// NOTE: It is unlikely that registering a type for BSON Embedded Document is actually desired. By
196+
// registering a type map entry for BSON Embedded Document the type registered will be used in any
197+
// case where a BSON Embedded Document will be decoded into an empty interface. For example, if you
198+
// register primitive.M, the EmptyInterface decoder will always use primitive.M, even if an ancestor
199+
// was a primitive.D.
194200
func (rb *RegistryBuilder) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) *RegistryBuilder {
195201
rb.typeMap[bt] = rt
196202
return rb

0 commit comments

Comments
 (0)