Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
qingyang-hu committed May 24, 2024
1 parent 9c32dc7 commit a99d3e3
Show file tree
Hide file tree
Showing 16 changed files with 359 additions and 218 deletions.
6 changes: 3 additions & 3 deletions bson/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var ErrDecodeToNil = errors.New("cannot Decode to nil value")
// ConfigurableDecoderRegistry refers a DecoderRegistry that is configurable with *RegistryOpt.
type ConfigurableDecoderRegistry interface {
DecoderRegistry
SetCodecOptions(opts ...*RegistryOpt)
SetCodecOption(opt *RegistryOpt) error
}

// A Decoder reads and decodes BSON documents from a stream. It reads from a ValueReader as
Expand Down Expand Up @@ -82,6 +82,6 @@ func (d *Decoder) Decode(val interface{}) error {
}

// SetBehavior set the decoder behavior with *RegistryOpt.
func (d *Decoder) SetBehavior(opts ...*RegistryOpt) {
d.reg.SetCodecOptions(opts...)
func (d *Decoder) SetBehavior(opt *RegistryOpt) error {
return d.reg.SetCodecOption(opt)
}
10 changes: 8 additions & 2 deletions bson/decoder_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ func ExampleDecoder_SetBehavior_defaultDocumentM() {
// type if the decode destination has no type information. The Properties
// field in the City struct will be decoded as a "M" (i.e. map) instead
// of the default "D".
decoder.SetBehavior(bson.DefaultDocumentM)
err = decoder.SetBehavior(bson.DefaultDocumentM)
if err != nil {
panic(err)
}

var res City
err = decoder.Decode(&res)
Expand Down Expand Up @@ -114,7 +117,10 @@ func ExampleDecoder_SetBehavior_useJSONStructTags() {

// Configure the Decoder to use "json" struct tags when decoding if "bson"
// struct tags are not present.
decoder.SetBehavior(bson.UseJSONStructTags)
err = decoder.SetBehavior(bson.UseJSONStructTags)
if err != nil {
panic(err)
}

var res Product
err = decoder.Decode(&res)
Expand Down
26 changes: 14 additions & 12 deletions bson/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "AllowTruncatingDoubles",
configure: func(dec *Decoder) {
dec.SetBehavior(AllowTruncatingDoubles)
_ = dec.SetBehavior(AllowTruncatingDoubles)
},
input: bsoncore.NewDocumentBuilder().
AppendDouble("myInt", 1.999).
Expand Down Expand Up @@ -286,7 +286,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "BinaryAsSlice",
configure: func(dec *Decoder) {
dec.SetBehavior(BinaryAsSlice)
_ = dec.SetBehavior(BinaryAsSlice)
},
input: bsoncore.NewDocumentBuilder().
AppendBinary("myBinary", TypeBinaryGeneric, []byte{}).
Expand All @@ -299,7 +299,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "DefaultDocumentD nested",
configure: func(dec *Decoder) {
dec.SetBehavior(DefaultDocumentD)
_ = dec.SetBehavior(DefaultDocumentD)
},
input: bsoncore.NewDocumentBuilder().
AppendDocument("myDocument", bsoncore.NewDocumentBuilder().
Expand All @@ -316,7 +316,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "DefaultDocumentM nested",
configure: func(dec *Decoder) {
dec.SetBehavior(DefaultDocumentM)
_ = dec.SetBehavior(DefaultDocumentM)
},
input: bsoncore.NewDocumentBuilder().
AppendDocument("myDocument", bsoncore.NewDocumentBuilder().
Expand All @@ -333,7 +333,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "UseJSONStructTags",
configure: func(dec *Decoder) {
dec.SetBehavior(UseJSONStructTags)
_ = dec.SetBehavior(UseJSONStructTags)
},
input: bsoncore.NewDocumentBuilder().
AppendString("jsonFieldName", "test value").
Expand All @@ -346,7 +346,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "UseLocalTimeZone",
configure: func(dec *Decoder) {
dec.SetBehavior(UseLocalTimeZone)
_ = dec.SetBehavior(UseLocalTimeZone)
},
input: bsoncore.NewDocumentBuilder().
AppendDateTime("myTime", 1684349179939).
Expand All @@ -359,7 +359,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "ZeroMaps",
configure: func(dec *Decoder) {
dec.SetBehavior(ZeroMaps)
_ = dec.SetBehavior(ZeroMaps)
},
input: bsoncore.NewDocumentBuilder().
AppendDocument("myMap", bsoncore.NewDocumentBuilder().
Expand All @@ -376,7 +376,7 @@ func TestDecoderConfiguration(t *testing.T) {
{
description: "ZeroStructs",
configure: func(dec *Decoder) {
dec.SetBehavior(ZeroStructs)
_ = dec.SetBehavior(ZeroStructs)
},
input: bsoncore.NewDocumentBuilder().
AppendString("myString", "test value").
Expand Down Expand Up @@ -417,10 +417,11 @@ func TestDecoderConfiguration(t *testing.T) {

dec := NewDecoder(NewValueReader(input))

dec.SetBehavior(DefaultDocumentM)
err := dec.SetBehavior(DefaultDocumentM)
require.NoError(t, err, "SetBehavior error")

var got interface{}
err := dec.Decode(&got)
err = dec.Decode(&got)
require.NoError(t, err, "Decode error")

want := M{
Expand All @@ -441,10 +442,11 @@ func TestDecoderConfiguration(t *testing.T) {

dec := NewDecoder(NewValueReader(input))

dec.SetBehavior(DefaultDocumentD)
err := dec.SetBehavior(DefaultDocumentD)
require.NoError(t, err, "SetBehavior error")

var got interface{}
err := dec.Decode(&got)
err = dec.Decode(&got)
require.NoError(t, err, "Decode error")

want := D{
Expand Down
6 changes: 3 additions & 3 deletions bson/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// ConfigurableEncoderRegistry refers a EncoderRegistry that is configurable with *RegistryOpt.
type ConfigurableEncoderRegistry interface {
EncoderRegistry
SetCodecOptions(opts ...*RegistryOpt)
SetCodecOption(opt *RegistryOpt) error
}

// An Encoder writes a serialization format to an output stream. It writes to a ValueWriter
Expand Down Expand Up @@ -61,6 +61,6 @@ func (e *Encoder) Encode(val interface{}) error {
}

// SetBehavior set the encoder behavior with *RegistryOpt.
func (e *Encoder) SetBehavior(opts ...*RegistryOpt) {
e.reg.SetCodecOptions(opts...)
func (e *Encoder) SetBehavior(opt *RegistryOpt) error {
return e.reg.SetCodecOption(opt)
}
21 changes: 15 additions & 6 deletions bson/encoder_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ func ExampleEncoder_SetBehavior_intMinSize() {
vw := bson.NewValueWriter(buf)

enc := bson.NewEncoder(vw)
enc.SetBehavior(bson.IntMinSize)
err := enc.SetBehavior(bson.IntMinSize)
if err != nil {
panic(err)
}

err := enc.Encode(foo{2})
err = enc.Encode(foo{2})
if err != nil {
panic(err)
}
Expand All @@ -84,14 +87,17 @@ func ExampleEncoder_SetBehavior_stringifyMapKeysWithFmt() {

// Configure the Encoder to convert Go map keys to BSON document field names
// using fmt.Sprintf instead of the default string conversion logic.
encoder.SetBehavior(bson.StringifyMapKeysWithFmt)
err := encoder.SetBehavior(bson.StringifyMapKeysWithFmt)
if err != nil {
panic(err)
}

// Use the Encoder to marshal a BSON document that contains is a map of
// city and state to a list of zip codes in that city.
zipCodes := map[CityState][]int{
{City: "New York", State: "NY"}: {10001, 10301, 10451},
}
err := encoder.Encode(zipCodes)
err = encoder.Encode(zipCodes)
if err != nil {
panic(err)
}
Expand All @@ -115,7 +121,10 @@ func ExampleEncoder_SetBehavior_useJSONStructTags() {

// Configure the Encoder to use "json" struct tags when decoding if "bson"
// struct tags are not present.
encoder.SetBehavior(bson.UseJSONStructTags)
err := encoder.SetBehavior(bson.UseJSONStructTags)
if err != nil {
panic(err)
}

// Use the Encoder to marshal a BSON document that contains the name, SKU,
// and price (in cents) of a product.
Expand All @@ -124,7 +133,7 @@ func ExampleEncoder_SetBehavior_useJSONStructTags() {
SKU: "AB12345",
Price: 399,
}
err := encoder.Encode(product)
err = encoder.Encode(product)
if err != nil {
panic(err)
}
Expand Down
16 changes: 8 additions & 8 deletions bson/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "ErrorOnInlineDuplicates",
configure: func(enc *Encoder) {
enc.SetBehavior(ErrorOnInlineDuplicates)
_ = enc.SetBehavior(ErrorOnInlineDuplicates)
},
input: inlineDuplicateOuter{
Inline: inlineDuplicateInner{Duplicate: "inner"},
Expand All @@ -173,7 +173,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "IntMinSize",
configure: func(enc *Encoder) {
enc.SetBehavior(IntMinSize)
_ = enc.SetBehavior(IntMinSize)
},
input: D{
{Key: "myInt", Value: int(1)},
Expand All @@ -194,7 +194,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "StringifyMapKeysWithFmt",
configure: func(enc *Encoder) {
enc.SetBehavior(StringifyMapKeysWithFmt)
_ = enc.SetBehavior(StringifyMapKeysWithFmt)
},
input: map[stringerTest]string{
{}: "test value",
Expand All @@ -207,7 +207,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "NilMapAsEmpty",
configure: func(enc *Encoder) {
enc.SetBehavior(NilMapAsEmpty)
_ = enc.SetBehavior(NilMapAsEmpty)
},
input: D{{Key: "myMap", Value: map[string]string(nil)}},
want: bsoncore.NewDocumentBuilder().
Expand All @@ -218,7 +218,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "NilSliceAsEmpty",
configure: func(enc *Encoder) {
enc.SetBehavior(NilSliceAsEmpty)
_ = enc.SetBehavior(NilSliceAsEmpty)
},
input: D{{Key: "mySlice", Value: []string(nil)}},
want: bsoncore.NewDocumentBuilder().
Expand All @@ -229,7 +229,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "NilByteSliceAsEmpty",
configure: func(enc *Encoder) {
enc.SetBehavior(NilByteSliceAsEmpty)
_ = enc.SetBehavior(NilByteSliceAsEmpty)
},
input: D{{Key: "myBytes", Value: []byte(nil)}},
want: bsoncore.NewDocumentBuilder().
Expand All @@ -241,7 +241,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "OmitZeroStruct",
configure: func(enc *Encoder) {
enc.SetBehavior(OmitZeroStruct)
_ = enc.SetBehavior(OmitZeroStruct)
},
input: struct {
Zero zeroStruct `bson:",omitempty"`
Expand All @@ -253,7 +253,7 @@ func TestEncoderConfiguration(t *testing.T) {
{
description: "UseJSONStructTags",
configure: func(enc *Encoder) {
enc.SetBehavior(UseJSONStructTags)
_ = enc.SetBehavior(UseJSONStructTags)
},
input: struct {
StructFieldName string `json:"jsonFieldName"`
Expand Down
19 changes: 12 additions & 7 deletions bson/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,21 @@ type Registry struct {
codecTypeMap map[reflect.Type][]interface{}
}

// SetCodecOptions configures Registry using a *RegistryOpt.
func (r *Registry) SetCodecOptions(opts ...*RegistryOpt) {
for _, opt := range opts {
v, ok := r.codecTypeMap[opt.typ]
if ok && v != nil {
for i := range v {
_ = opt.fn.Call([]reflect.Value{reflect.ValueOf(v[i])})
// SetCodecOption configures Registry using a *RegistryOpt.
func (r *Registry) SetCodecOption(opt *RegistryOpt) error {
v, ok := r.codecTypeMap[opt.typ]
if !ok || len(v) == 0 {
return fmt.Errorf("could not find codec %s", opt.typ.String())
}
for i := range v {
rtns := opt.fn.Call([]reflect.Value{reflect.ValueOf(v[i])})
for _, r := range rtns {
if !r.IsNil() {
return r.Interface().(error)
}
}
}
return nil
}

// LookupEncoder returns the first matching encoder in the Registry. It uses the following lookup
Expand Down
Loading

0 comments on commit a99d3e3

Please sign in to comment.