forked from shopspring/decimal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decimal_bson.go
78 lines (64 loc) · 2.4 KB
/
decimal_bson.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package decimal
import (
"fmt"
"reflect"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsonrw"
)
func init() {
// Auto register our Decimal encoder and decoder for bson when this package is imported.
RegisterBSONDecimalCodec(bson.DefaultRegistry)
}
// RegisterBSONDecimalCodec registers the encoder and decoder for [Decimal].
// The encoder/decoder are automatically registered on [bson.DefaultRegistry] on package import.
func RegisterBSONDecimalCodec(registry *bsoncodec.Registry) {
// Register custom encoder and decoder for decimal type
registry.RegisterTypeEncoder(decimalType, bsoncodec.ValueEncoderFunc(decimalBSONEncodeValue))
registry.RegisterTypeDecoder(decimalType, bsoncodec.ValueDecoderFunc(decimalBSONDecodeValue))
}
// decimalType is the reflected type of a [Decimal].
var decimalType = reflect.TypeOf(Decimal{})
// decimalBSONEncodeValue encodes a shopspring decimal to string.
// This is the safest format as it contains the entire value and can be decoded from.
func decimalBSONEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if val.Type() != decimalType {
// ShopSpring decimal
return bsoncodec.ValueEncoderError{
// prefix with GC to avoid any mongodb name collisions
// They have a Decimal128 type which this is not.
Name: "GCDecimalEncodeValue",
Types: []reflect.Type{decimalType},
Received: val,
}
}
// Convert to a decimal
dec := val.Interface().(Decimal)
return vw.WriteString(dec.String())
}
// decimalBSONDecodeValue decodes a string into a decimal.
func decimalBSONDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || !val.CanSet() || val.Type() != decimalType {
return bsoncodec.ValueDecoderError{
// prefix with GC to avoid any mongodb name collisions
// They have a Decimal128 type which this is not.
Name: "GCDecimalDecodeValue",
Types: []reflect.Type{decimalType},
Received: val,
}
}
// Only read from string
if vr.Type() != bson.TypeString {
return fmt.Errorf("received invalid BSON type to decode into Decimal: %s", vr.Type())
}
b, err := vr.ReadString()
if err != nil {
return err
}
result, err := NewFromString(b)
if err != nil {
return fmt.Errorf("error creating new decimal from string: %w", err)
}
val.Set(reflect.ValueOf(result))
return nil
}