Skip to content

Commit 730e825

Browse files
Merge branch 'release/1.12' of github.com:mongodb/mongo-go-driver into release/1.12
2 parents f14bd3a + d219098 commit 730e825

33 files changed

+614
-116
lines changed

bson/bsoncodec/default_value_decoders.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,12 +1540,12 @@ func (dvd DefaultValueDecoders) ValueUnmarshalerDecodeValue(_ DecodeContext, vr
15401540
return err
15411541
}
15421542

1543-
fn := val.Convert(tValueUnmarshaler).MethodByName("UnmarshalBSONValue")
1544-
errVal := fn.Call([]reflect.Value{reflect.ValueOf(t), reflect.ValueOf(src)})[0]
1545-
if !errVal.IsNil() {
1546-
return errVal.Interface().(error)
1543+
m, ok := val.Interface().(ValueUnmarshaler)
1544+
if !ok {
1545+
// NB: this error should be unreachable due to the above checks
1546+
return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val}
15471547
}
1548-
return nil
1548+
return m.UnmarshalBSONValue(t, src)
15491549
}
15501550

15511551
// UnmarshalerDecodeValue is the ValueDecoderFunc for Unmarshaler implementations.
@@ -1588,12 +1588,12 @@ func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(_ DecodeContext, vr bsonr
15881588
val = val.Addr() // If the type doesn't implement the interface, a pointer to it must.
15891589
}
15901590

1591-
fn := val.Convert(tUnmarshaler).MethodByName("UnmarshalBSON")
1592-
errVal := fn.Call([]reflect.Value{reflect.ValueOf(src)})[0]
1593-
if !errVal.IsNil() {
1594-
return errVal.Interface().(error)
1591+
m, ok := val.Interface().(Unmarshaler)
1592+
if !ok {
1593+
// NB: this error should be unreachable due to the above checks
1594+
return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val}
15951595
}
1596-
return nil
1596+
return m.UnmarshalBSON(src)
15971597
}
15981598

15991599
// EmptyInterfaceDecodeValue is the ValueDecoderFunc for interface{}.

bson/bsoncodec/default_value_decoders_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1530,13 +1530,22 @@ func TestDefaultValueDecoders(t *testing.T) {
15301530
errors.New("copy error"),
15311531
},
15321532
{
1533-
"Unmarshaler",
1533+
// Only the pointer form of testUnmarshaler implements Unmarshaler
1534+
"value does not implement Unmarshaler",
15341535
testUnmarshaler{Val: bsoncore.AppendDouble(nil, 3.14159)},
15351536
nil,
15361537
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14159)},
15371538
bsonrwtest.ReadDouble,
15381539
nil,
15391540
},
1541+
{
1542+
"Unmarshaler",
1543+
&testUnmarshaler{Val: bsoncore.AppendDouble(nil, 3.14159)},
1544+
nil,
1545+
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14159)},
1546+
bsonrwtest.ReadDouble,
1547+
nil,
1548+
},
15401549
},
15411550
},
15421551
{

bson/bsoncodec/default_value_encoders.go

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -564,12 +564,14 @@ func (dve DefaultValueEncoders) ValueMarshalerEncodeValue(_ EncodeContext, vw bs
564564
return ValueEncoderError{Name: "ValueMarshalerEncodeValue", Types: []reflect.Type{tValueMarshaler}, Received: val}
565565
}
566566

567-
fn := val.Convert(tValueMarshaler).MethodByName("MarshalBSONValue")
568-
returns := fn.Call(nil)
569-
if !returns[2].IsNil() {
570-
return returns[2].Interface().(error)
567+
m, ok := val.Interface().(ValueMarshaler)
568+
if !ok {
569+
return vw.WriteNull()
570+
}
571+
t, data, err := m.MarshalBSONValue()
572+
if err != nil {
573+
return err
571574
}
572-
t, data := returns[0].Interface().(bsontype.Type), returns[1].Interface().([]byte)
573575
return bsonrw.Copier{}.CopyValueFromBytes(vw, t, data)
574576
}
575577

@@ -593,12 +595,14 @@ func (dve DefaultValueEncoders) MarshalerEncodeValue(_ EncodeContext, vw bsonrw.
593595
return ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: val}
594596
}
595597

596-
fn := val.Convert(tMarshaler).MethodByName("MarshalBSON")
597-
returns := fn.Call(nil)
598-
if !returns[1].IsNil() {
599-
return returns[1].Interface().(error)
598+
m, ok := val.Interface().(Marshaler)
599+
if !ok {
600+
return vw.WriteNull()
601+
}
602+
data, err := m.MarshalBSON()
603+
if err != nil {
604+
return err
600605
}
601-
data := returns[0].Interface().([]byte)
602606
return bsonrw.Copier{}.CopyValueFromBytes(vw, bsontype.EmbeddedDocument, data)
603607
}
604608

@@ -622,23 +626,31 @@ func (dve DefaultValueEncoders) ProxyEncodeValue(ec EncodeContext, vw bsonrw.Val
622626
return ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: val}
623627
}
624628

625-
fn := val.Convert(tProxy).MethodByName("ProxyBSON")
626-
returns := fn.Call(nil)
627-
if !returns[1].IsNil() {
628-
return returns[1].Interface().(error)
629+
m, ok := val.Interface().(Proxy)
630+
if !ok {
631+
return vw.WriteNull()
632+
}
633+
v, err := m.ProxyBSON()
634+
if err != nil {
635+
return err
636+
}
637+
if v == nil {
638+
encoder, err := ec.LookupEncoder(nil)
639+
if err != nil {
640+
return err
641+
}
642+
return encoder.EncodeValue(ec, vw, reflect.ValueOf(nil))
629643
}
630-
data := returns[0]
631-
var encoder ValueEncoder
632-
var err error
633-
if data.Elem().IsValid() {
634-
encoder, err = ec.LookupEncoder(data.Elem().Type())
635-
} else {
636-
encoder, err = ec.LookupEncoder(nil)
644+
vv := reflect.ValueOf(v)
645+
switch vv.Kind() {
646+
case reflect.Ptr, reflect.Interface:
647+
vv = vv.Elem()
637648
}
649+
encoder, err := ec.LookupEncoder(vv.Type())
638650
if err != nil {
639651
return err
640652
}
641-
return encoder.EncodeValue(ec, vw, data.Elem())
653+
return encoder.EncodeValue(ec, vw, vv)
642654
}
643655

644656
// JavaScriptEncodeValue is the ValueEncoderFunc for the primitive.JavaScript type.

bson/bsontype/bsontype.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,14 @@ func (bt Type) String() string {
102102
return "invalid"
103103
}
104104
}
105+
106+
// IsValid will return true if the Type is valid.
107+
func (bt Type) IsValid() bool {
108+
switch bt {
109+
case Double, String, EmbeddedDocument, Array, Binary, Undefined, ObjectID, Boolean, DateTime, Null, Regex,
110+
DBPointer, JavaScript, Symbol, CodeWithScope, Int32, Timestamp, Int64, Decimal128, MinKey, MaxKey:
111+
return true
112+
default:
113+
return false
114+
}
115+
}

bson/mgocompat/setter_getter.go

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package mgocompat
88

99
import (
10+
"errors"
1011
"reflect"
1112

1213
"go.mongodb.org/mongo-driver/bson"
@@ -73,16 +74,15 @@ func SetterDecodeValue(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val ref
7374
return err
7475
}
7576

76-
fn := val.Convert(tSetter).MethodByName("SetBSON")
77-
78-
errVal := fn.Call([]reflect.Value{reflect.ValueOf(bson.RawValue{Type: t, Value: src})})[0]
79-
if !errVal.IsNil() {
80-
err = errVal.Interface().(error)
81-
if err == ErrSetZero {
82-
val.Set(reflect.Zero(val.Type()))
83-
return nil
77+
m, ok := val.Interface().(Setter)
78+
if !ok {
79+
return bsoncodec.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
80+
}
81+
if err := m.SetBSON(bson.RawValue{Type: t, Value: src}); err != nil {
82+
if !errors.Is(err, ErrSetZero) {
83+
return err
8484
}
85-
return err
85+
val.Set(reflect.Zero(val.Type()))
8686
}
8787
return nil
8888
}
@@ -104,17 +104,23 @@ func GetterEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val re
104104
return bsoncodec.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val}
105105
}
106106

107-
fn := val.Convert(tGetter).MethodByName("GetBSON")
108-
returns := fn.Call(nil)
109-
if !returns[1].IsNil() {
110-
return returns[1].Interface().(error)
107+
m, ok := val.Interface().(Getter)
108+
if !ok {
109+
return vw.WriteNull()
110+
}
111+
x, err := m.GetBSON()
112+
if err != nil {
113+
return err
114+
}
115+
if x == nil {
116+
return vw.WriteNull()
111117
}
112-
intermediate := returns[0]
113-
encoder, err := ec.Registry.LookupEncoder(intermediate.Type())
118+
vv := reflect.ValueOf(x)
119+
encoder, err := ec.Registry.LookupEncoder(vv.Type())
114120
if err != nil {
115121
return err
116122
}
117-
return encoder.EncodeValue(ec, vw, intermediate)
123+
return encoder.EncodeValue(ec, vw, vv)
118124
}
119125

120126
// isImplementationNil returns if val is a nil pointer and inter is implemented on a concrete type

bson/primitive_codecs.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package bson
88

99
import (
1010
"errors"
11+
"fmt"
1112
"reflect"
1213

1314
"go.mongodb.org/mongo-driver/bson/bsoncodec"
@@ -45,15 +46,26 @@ func (pc PrimitiveCodecs) RegisterPrimitiveCodecs(rb *bsoncodec.RegistryBuilder)
4546

4647
// RawValueEncodeValue is the ValueEncoderFunc for RawValue.
4748
//
48-
// Deprecated: Use bson.NewRegistry to get a registry with all primitive encoders and decoders
49-
// registered.
49+
// If the RawValue's Type is "invalid" and the RawValue's Value is not empty or
50+
// nil, then this method will return an error.
51+
//
52+
// Deprecated: Use bson.NewRegistry to get a registry with all primitive
53+
// encoders and decoders registered.
5054
func (PrimitiveCodecs) RawValueEncodeValue(_ bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
5155
if !val.IsValid() || val.Type() != tRawValue {
52-
return bsoncodec.ValueEncoderError{Name: "RawValueEncodeValue", Types: []reflect.Type{tRawValue}, Received: val}
56+
return bsoncodec.ValueEncoderError{
57+
Name: "RawValueEncodeValue",
58+
Types: []reflect.Type{tRawValue},
59+
Received: val,
60+
}
5361
}
5462

5563
rawvalue := val.Interface().(RawValue)
5664

65+
if !rawvalue.Type.IsValid() {
66+
return fmt.Errorf("the RawValue Type specifies an invalid BSON type: %#x", byte(rawvalue.Type))
67+
}
68+
5769
return bsonrw.Copier{}.CopyValueFromBytes(vw, rawvalue.Type, rawvalue.Value)
5870
}
5971

bson/primitive_codecs_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ func compareErrors(err1, err2 error) bool {
6565
}
6666

6767
func TestDefaultValueEncoders(t *testing.T) {
68+
t.Parallel()
69+
6870
var pc PrimitiveCodecs
6971

7072
var wrong = func(string, string) string { return "wrong" }
@@ -107,6 +109,28 @@ func TestDefaultValueEncoders(t *testing.T) {
107109
bsonrwtest.WriteDouble,
108110
nil,
109111
},
112+
{
113+
"RawValue Type is zero with non-zero value",
114+
RawValue{
115+
Type: 0x00,
116+
Value: bsoncore.AppendDouble(nil, 3.14159),
117+
},
118+
nil,
119+
nil,
120+
bsonrwtest.Nothing,
121+
fmt.Errorf("the RawValue Type specifies an invalid BSON type: 0x0"),
122+
},
123+
{
124+
"RawValue Type is invalid",
125+
RawValue{
126+
Type: 0x8F,
127+
Value: bsoncore.AppendDouble(nil, 3.14159),
128+
},
129+
nil,
130+
nil,
131+
bsonrwtest.Nothing,
132+
fmt.Errorf("the RawValue Type specifies an invalid BSON type: 0x8f"),
133+
},
110134
},
111135
},
112136
{
@@ -166,9 +190,17 @@ func TestDefaultValueEncoders(t *testing.T) {
166190
}
167191

168192
for _, tc := range testCases {
193+
tc := tc // Capture the range variable
194+
169195
t.Run(tc.name, func(t *testing.T) {
196+
t.Parallel()
197+
170198
for _, subtest := range tc.subtests {
199+
subtest := subtest // Capture the range variable
200+
171201
t.Run(subtest.name, func(t *testing.T) {
202+
t.Parallel()
203+
172204
var ec bsoncodec.EncodeContext
173205
if subtest.ectx != nil {
174206
ec = *subtest.ectx
@@ -192,6 +224,8 @@ func TestDefaultValueEncoders(t *testing.T) {
192224
}
193225

194226
t.Run("success path", func(t *testing.T) {
227+
t.Parallel()
228+
195229
oid := primitive.NewObjectID()
196230
oids := []primitive.ObjectID{primitive.NewObjectID(), primitive.NewObjectID(), primitive.NewObjectID()}
197231
var str = new(string)
@@ -426,7 +460,11 @@ func TestDefaultValueEncoders(t *testing.T) {
426460
}
427461

428462
for _, tc := range testCases {
463+
tc := tc // Capture the range variable
464+
429465
t.Run(tc.name, func(t *testing.T) {
466+
t.Parallel()
467+
430468
b := make(bsonrw.SliceWriter, 0, 512)
431469
vw, err := bsonrw.NewBSONValueWriter(&b)
432470
noerr(t, err)

bson/raw_value.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ type RawValue struct {
3737
r *bsoncodec.Registry
3838
}
3939

40+
// IsZero reports whether the RawValue is zero, i.e. no data is present on
41+
// the RawValue. It returns true if Type is 0 and Value is empty or nil.
42+
func (rv RawValue) IsZero() bool {
43+
return rv.Type == 0x00 && len(rv.Value) == 0
44+
}
45+
4046
// Unmarshal deserializes BSON into the provided val. If RawValue cannot be unmarshaled into val, an
4147
// error is returned. This method will use the registry used to create the RawValue, if the RawValue
4248
// was created from partial BSON processing, or it will use the default registry. Users wishing to

0 commit comments

Comments
 (0)