Skip to content

Commit 745f04e

Browse files
committed
Add BSON Proxy support
GODRIVER-413 Change-Id: I600841a34012adc3d3b95272bf36008212453576
1 parent 97764fe commit 745f04e

File tree

4 files changed

+114
-1
lines changed

4 files changed

+114
-1
lines changed

bson/bsoncodec/default_value_encoders.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) {
3535
RegisterEncoder(tJSONNumber, ValueEncoderFunc(dve.JSONNumberEncodeValue)).
3636
RegisterEncoder(tURL, ValueEncoderFunc(dve.URLEncodeValue)).
3737
RegisterEncoder(tValueMarshaler, ValueEncoderFunc(dve.ValueMarshalerEncodeValue)).
38+
RegisterEncoder(tProxy, ValueEncoderFunc(dve.ProxyEncodeValue)).
3839
RegisterDefaultEncoder(reflect.Bool, ValueEncoderFunc(dve.BooleanEncodeValue)).
3940
RegisterDefaultEncoder(reflect.Int, ValueEncoderFunc(dve.IntEncodeValue)).
4041
RegisterDefaultEncoder(reflect.Int8, ValueEncoderFunc(dve.IntEncodeValue)).
@@ -442,3 +443,25 @@ func (dve DefaultValueEncoders) ValueMarshalerEncodeValue(ec EncodeContext, vw b
442443
}
443444
return bsonrw.Copier{}.CopyValueFromBytes(vw, t, val)
444445
}
446+
447+
// ProxyEncodeValue is the ValueEncoderFunc for Proxy implementations.
448+
func (dve DefaultValueEncoders) ProxyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, i interface{}) error {
449+
proxy, ok := i.(Proxy)
450+
if !ok {
451+
return ValueEncoderError{
452+
Name: "ProxyEncodeValue",
453+
Types: []interface{}{(Proxy)(nil)},
454+
Received: i,
455+
}
456+
}
457+
458+
val, err := proxy.ProxyBSON()
459+
if err != nil {
460+
return err
461+
}
462+
encoder, err := ec.LookupEncoder(reflect.TypeOf(val))
463+
if err != nil {
464+
return err
465+
}
466+
return encoder.EncodeValue(ec, vw, val)
467+
}

bson/bsoncodec/default_value_encoders_test.go

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,48 @@ func TestDefaultValueEncoders(t *testing.T) {
453453
},
454454
},
455455
},
456+
{
457+
"ProxyEncodeValue",
458+
ValueEncoderFunc(dve.ProxyEncodeValue),
459+
[]subtest{
460+
{
461+
"wrong type",
462+
wrong,
463+
nil,
464+
nil,
465+
bsonrwtest.Nothing,
466+
ValueEncoderError{
467+
Name: "ProxyEncodeValue",
468+
Types: []interface{}{(Proxy)(nil)},
469+
Received: wrong,
470+
},
471+
},
472+
{
473+
"Proxy error",
474+
testProxy{err: errors.New("proxy error")},
475+
nil,
476+
nil,
477+
bsonrwtest.Nothing,
478+
errors.New("proxy error"),
479+
},
480+
{
481+
"Lookup error",
482+
testProxy{ret: nil},
483+
&EncodeContext{Registry: buildDefaultRegistry()},
484+
nil,
485+
bsonrwtest.Nothing,
486+
ErrNilType,
487+
},
488+
{
489+
"success",
490+
testProxy{ret: int64(1234567890)},
491+
&EncodeContext{Registry: buildDefaultRegistry()},
492+
nil,
493+
bsonrwtest.WriteInt64,
494+
nil,
495+
},
496+
},
497+
},
456498
}
457499

458500
for _, tc := range testCases {
@@ -704,6 +746,8 @@ func TestDefaultValueEncoders(t *testing.T) {
704746
AC decimal.Decimal128
705747
AD *time.Time
706748
AE testValueMarshaler
749+
AF Proxy
750+
AG testProxy
707751
}{
708752
A: true,
709753
B: 123,
@@ -729,6 +773,8 @@ func TestDefaultValueEncoders(t *testing.T) {
729773
AC: decimal128,
730774
AD: &now,
731775
AE: testValueMarshaler{t: bsontype.String, buf: bsoncore.AppendString(nil, "hello, world")},
776+
AF: testProxy{ret: struct{ Hello string }{Hello: "world!"}},
777+
AG: testProxy{ret: struct{ Pi float64 }{Pi: 3.14159}},
732778
},
733779
buildDocument(func(doc []byte) []byte {
734780
doc = bsoncore.AppendBooleanElement(doc, "a", true)
@@ -753,6 +799,8 @@ func TestDefaultValueEncoders(t *testing.T) {
753799
doc = bsoncore.AppendDecimal128Element(doc, "ac", decimal128)
754800
doc = bsoncore.AppendDateTimeElement(doc, "ad", now.UnixNano()/int64(time.Millisecond))
755801
doc = bsoncore.AppendStringElement(doc, "ae", "hello, world")
802+
doc = bsoncore.AppendDocumentElement(doc, "af", buildDocument(bsoncore.AppendStringElement(nil, "hello", "world!")))
803+
doc = bsoncore.AppendDocumentElement(doc, "ag", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)))
756804
return doc
757805
}(nil)),
758806
nil,
@@ -785,6 +833,8 @@ func TestDefaultValueEncoders(t *testing.T) {
785833
AC []decimal.Decimal128
786834
AD []*time.Time
787835
AE []testValueMarshaler
836+
AF []Proxy
837+
AG []testProxy
788838
}{
789839
A: []bool{true},
790840
B: []int32{123},
@@ -818,6 +868,14 @@ func TestDefaultValueEncoders(t *testing.T) {
818868
{t: bsontype.String, buf: bsoncore.AppendString(nil, "hello")},
819869
{t: bsontype.String, buf: bsoncore.AppendString(nil, "world")},
820870
},
871+
AF: []Proxy{
872+
testProxy{ret: struct{ Hello string }{Hello: "world!"}},
873+
testProxy{ret: struct{ Foo string }{Foo: "bar"}},
874+
},
875+
AG: []testProxy{
876+
{ret: struct{ One int64 }{One: 1234567890}},
877+
{ret: struct{ Pi float64 }{Pi: 3.14159}},
878+
},
821879
},
822880
buildDocument(func(doc []byte) []byte {
823881
doc = appendArrayElement(doc, "a", bsoncore.AppendBooleanElement(nil, "0", true))
@@ -867,6 +925,22 @@ func TestDefaultValueEncoders(t *testing.T) {
867925
doc = appendArrayElement(doc, "ae",
868926
bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "hello"), "1", "world"),
869927
)
928+
doc = appendArrayElement(doc, "af",
929+
bsoncore.AppendDocumentElement(
930+
bsoncore.AppendDocumentElement(nil, "0",
931+
bsoncore.BuildDocument(nil, bsoncore.AppendStringElement(nil, "hello", "world!")),
932+
), "1",
933+
bsoncore.BuildDocument(nil, bsoncore.AppendStringElement(nil, "foo", "bar")),
934+
),
935+
)
936+
doc = appendArrayElement(doc, "ag",
937+
bsoncore.AppendDocumentElement(
938+
bsoncore.AppendDocumentElement(nil, "0",
939+
bsoncore.BuildDocument(nil, bsoncore.AppendInt64Element(nil, "one", 1234567890)),
940+
), "1",
941+
bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
942+
),
943+
)
870944
return doc
871945
}(nil)),
872946
nil,
@@ -888,7 +962,7 @@ func TestDefaultValueEncoders(t *testing.T) {
888962
if diff := cmp.Diff([]byte(b), tc.b); diff != "" {
889963
t.Errorf("Bytes written differ: (-got +want)\n%s", diff)
890964
t.Errorf("Bytes\ngot: %v\nwant:%v\n", b, tc.b)
891-
t.Errorf("Readers\ngot: %v\nwant:%v\n", b, tc.b)
965+
t.Errorf("Readers\ngot: %v\nwant:%v\n", bsoncore.Document(b), bsoncore.Document(tc.b))
892966
}
893967
})
894968
}
@@ -904,3 +978,10 @@ type testValueMarshaler struct {
904978
func (tvm testValueMarshaler) MarshalBSONValue() (bsontype.Type, []byte, error) {
905979
return tvm.t, tvm.buf, tvm.err
906980
}
981+
982+
type testProxy struct {
983+
ret interface{}
984+
err error
985+
}
986+
987+
func (tp testProxy) ProxyBSON() (interface{}, error) { return tp.ret, tp.err }

bson/bsoncodec/proxy.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package bsoncodec
2+
3+
// Proxy is an interface implemented by types that cannot themselves be directly encoded. Types
4+
// that implement this interface with have ProxyBSON called during the encoding process and that
5+
// value will be encoded in place for the implementer.
6+
type Proxy interface {
7+
ProxyBSON() (interface{}, error)
8+
}

bson/bsoncodec/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ var tJSONNumber = reflect.TypeOf(json.Number(""))
5151

5252
var tValueMarshaler = reflect.TypeOf((*ValueMarshaler)(nil)).Elem()
5353
var tValueUnmarshaler = reflect.TypeOf((*ValueUnmarshaler)(nil)).Elem()
54+
var tProxy = reflect.TypeOf((*Proxy)(nil)).Elem()

0 commit comments

Comments
 (0)