Skip to content

Commit bb93394

Browse files
Merge pull request #2253 from RafaelCenzano/GODRIVER-3594
GODRIVER-3594: Add AsFloat64() and AsFloat64OK() conversion functions
2 parents d17ef8b + 2f375c2 commit bb93394

File tree

5 files changed

+311
-25
lines changed

5 files changed

+311
-25
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
repos:
33
- repo: https://github.com/pre-commit/pre-commit-hooks
4-
rev: v4.5.0
4+
rev: v6.0.0
55
hooks:
66
- id: check-case-conflict
77
- id: check-executables-have-shebangs

bson/raw_value.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,14 @@ func (rv RawValue) AsInt64() int64 { return convertToCoreValue(rv).AsInt64() }
294294
// panicking.
295295
func (rv RawValue) AsInt64OK() (int64, bool) { return convertToCoreValue(rv).AsInt64OK() }
296296

297+
// AsFloat64 returns a BSON number as a float64. If the BSON type is not a numeric one, this method
298+
// will panic.
299+
func (rv RawValue) AsFloat64() float64 { return convertToCoreValue(rv).AsFloat64() }
300+
301+
// AsFloat64OK is the same as AsFloat64, except that it returns a boolean instead of
302+
// panicking.
303+
func (rv RawValue) AsFloat64OK() (float64, bool) { return convertToCoreValue(rv).AsFloat64OK() }
304+
297305
// Decimal128 returns the decimal the Value represents. It panics if the value is a BSON type other than
298306
// decimal.
299307
func (rv RawValue) Decimal128() Decimal128 { return NewDecimal128(convertToCoreValue(rv).Decimal128()) }

internal/integration/unified/matches.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -245,26 +245,14 @@ func evaluateSpecialComparison(ctx context.Context, assertionDoc bson.Raw, actua
245245
if assertionVal.Type != bson.TypeInt32 && assertionVal.Type != bson.TypeInt64 && assertionVal.Type != bson.TypeDouble {
246246
return fmt.Errorf("expected assertionVal to be an Int32, Int64, or Double but got a %s", assertionVal.Type)
247247
}
248-
if actual.Type != bson.TypeInt32 && actual.Type != bson.TypeInt64 && assertionVal.Type != bson.TypeDouble {
248+
if actual.Type != bson.TypeInt32 && actual.Type != bson.TypeInt64 && actual.Type != bson.TypeDouble {
249249
return fmt.Errorf("expected value to be an Int32, Int64, or Double but got a %s", actual.Type)
250250
}
251251

252252
// Numeric values can be compared even if their types are different (e.g. if expected is an int32 and actual
253253
// is an int64).
254-
255-
// TODO(GODRIVER-3594): If we decide to add AsDoubleOK() as a method to RawValue, this following conversion should be updated.
256-
var expectedF64 float64
257-
if assertionVal.Type == bson.TypeDouble {
258-
expectedF64 = assertionVal.Double()
259-
} else {
260-
expectedF64 = float64(assertionVal.AsInt64())
261-
}
262-
var actualF64 float64
263-
if actual.Type == bson.TypeDouble {
264-
actualF64 = actual.Double()
265-
} else {
266-
actualF64 = float64(actual.AsInt64())
267-
}
254+
var expectedF64 = assertionVal.AsFloat64()
255+
var actualF64 = actual.AsFloat64()
268256

269257
if actualF64 > expectedF64 {
270258
return fmt.Errorf("expected numeric value %f to be less than or equal %f", actualF64, expectedF64)

x/bsonx/bsoncore/value.go

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ func (v Value) AsInt64() int64 {
137137
}
138138
i64 = int64(f64)
139139
case TypeInt32:
140-
var ok bool
141140
i32, _, ok := ReadInt32(v.Data)
142141
if !ok {
143142
panic(NewInsufficientBytesError(v.Data, v.Data))
@@ -170,7 +169,6 @@ func (v Value) AsInt64OK() (int64, bool) {
170169
}
171170
i64 = int64(f64)
172171
case TypeInt32:
173-
var ok bool
174172
i32, _, ok := ReadInt32(v.Data)
175173
if !ok {
176174
return 0, false
@@ -190,17 +188,69 @@ func (v Value) AsInt64OK() (int64, bool) {
190188

191189
// AsFloat64 returns a BSON number as an float64. If the BSON type is not a numeric one, this method
192190
// will panic.
193-
//
194-
// TODO(GODRIVER-2751): Implement AsFloat64.
195-
// func (v Value) AsFloat64() float64
191+
func (v Value) AsFloat64() float64 {
192+
if !v.IsNumber() {
193+
panic(ElementTypeError{"bsoncore.Value.AsFloat64", v.Type})
194+
}
195+
var f64 float64
196+
switch v.Type {
197+
case TypeDouble:
198+
var ok bool
199+
f64, _, ok = ReadDouble(v.Data)
200+
if !ok {
201+
panic(NewInsufficientBytesError(v.Data, v.Data))
202+
}
203+
case TypeInt32:
204+
i32, _, ok := ReadInt32(v.Data)
205+
if !ok {
206+
panic(NewInsufficientBytesError(v.Data, v.Data))
207+
}
208+
f64 = float64(i32)
209+
case TypeInt64:
210+
i64, _, ok := ReadInt64(v.Data)
211+
if !ok {
212+
panic(NewInsufficientBytesError(v.Data, v.Data))
213+
}
214+
f64 = float64(i64)
215+
case TypeDecimal128:
216+
panic(ElementTypeError{"bsoncore.Value.AsFloat64", v.Type})
217+
}
218+
return f64
219+
}
196220

197221
// AsFloat64OK functions the same as AsFloat64 but returns a boolean instead of panicking. False
198222
// indicates an error.
199-
//
200-
// TODO(GODRIVER-2751): Implement AsFloat64OK.
201-
// func (v Value) AsFloat64OK() (float64, bool)
223+
func (v Value) AsFloat64OK() (float64, bool) {
224+
if !v.IsNumber() {
225+
return 0, false
226+
}
227+
var f64 float64
228+
switch v.Type {
229+
case TypeDouble:
230+
var ok bool
231+
f64, _, ok = ReadDouble(v.Data)
232+
if !ok {
233+
return 0, false
234+
}
235+
case TypeInt32:
236+
i32, _, ok := ReadInt32(v.Data)
237+
if !ok {
238+
return 0, false
239+
}
240+
f64 = float64(i32)
241+
case TypeInt64:
242+
i64, _, ok := ReadInt64(v.Data)
243+
if !ok {
244+
return 0, false
245+
}
246+
f64 = float64(i64)
247+
case TypeDecimal128:
248+
return 0, false
249+
}
250+
return f64, true
251+
}
202252

203-
// Equal compaes v to v2 and returns true if they are equal.
253+
// Equal compares v to v2 and returns true if they are equal.
204254
func (v Value) Equal(v2 Value) bool {
205255
if v.Type != v2.Type {
206256
return false

x/bsonx/bsoncore/value_test.go

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,246 @@ func TestValue(t *testing.T) {
634634
nil,
635635
[]any{uint64(12345), uint64(67890), true},
636636
},
637+
{
638+
"AsInt32/Not Number", Value.AsInt32, Value{Type: TypeString},
639+
ElementTypeError{"bsoncore.Value.AsInt32", TypeString},
640+
nil,
641+
},
642+
{
643+
"AsInt32/Double/Insufficient Bytes", Value.AsInt32, Value{Type: TypeDouble, Data: []byte{0x01, 0x02, 0x03}},
644+
NewInsufficientBytesError([]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03}),
645+
nil,
646+
},
647+
{
648+
"AsInt32/Int32/Insufficient Bytes", Value.AsInt32, Value{Type: TypeInt32, Data: []byte{0x01, 0x02}},
649+
NewInsufficientBytesError([]byte{0x01, 0x02}, []byte{0x01, 0x02}),
650+
nil,
651+
},
652+
{
653+
"AsInt32/Int64/Insufficient Bytes", Value.AsInt32, Value{Type: TypeInt64, Data: []byte{0x01, 0x02, 0x03}},
654+
NewInsufficientBytesError([]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03}),
655+
nil,
656+
},
657+
{
658+
"AsInt32/Decimal128", Value.AsInt32, Value{Type: TypeDecimal128, Data: AppendDecimal128(nil, 12345, 67890)},
659+
ElementTypeError{"bsoncore.Value.AsInt32", TypeDecimal128},
660+
nil,
661+
},
662+
{
663+
"AsInt32/From Double", Value.AsInt32, Value{Type: TypeDouble, Data: AppendDouble(nil, 42.7)},
664+
nil,
665+
[]any{int32(42)},
666+
},
667+
{
668+
"AsInt32/From Int32", Value.AsInt32, Value{Type: TypeInt32, Data: AppendInt32(nil, 12345)},
669+
nil,
670+
[]any{int32(12345)},
671+
},
672+
{
673+
"AsInt32/From Int64", Value.AsInt32, Value{Type: TypeInt64, Data: AppendInt64(nil, 98765)},
674+
nil,
675+
[]any{int32(98765)},
676+
},
677+
{
678+
"AsInt32OK/Not Number", Value.AsInt32OK, Value{Type: TypeString},
679+
nil,
680+
[]any{int32(0), false},
681+
},
682+
{
683+
"AsInt32OK/Double/Insufficient Bytes", Value.AsInt32OK, Value{Type: TypeDouble, Data: []byte{0x01, 0x02, 0x03}},
684+
nil,
685+
[]any{int32(0), false},
686+
},
687+
{
688+
"AsInt32OK/Int32/Insufficient Bytes", Value.AsInt32OK, Value{Type: TypeInt32, Data: []byte{0x01, 0x02}},
689+
nil,
690+
[]any{int32(0), false},
691+
},
692+
{
693+
"AsInt32OK/Int64/Insufficient Bytes", Value.AsInt32OK, Value{Type: TypeInt64, Data: []byte{0x01, 0x02, 0x03}},
694+
nil,
695+
[]any{int32(0), false},
696+
},
697+
{
698+
"AsInt32OK/Decimal128", Value.AsInt32OK, Value{Type: TypeDecimal128, Data: AppendDecimal128(nil, 12345, 67890)},
699+
nil,
700+
[]any{int32(0), false},
701+
},
702+
{
703+
"AsInt32OK/From Double", Value.AsInt32OK, Value{Type: TypeDouble, Data: AppendDouble(nil, 42.7)},
704+
nil,
705+
[]any{int32(42), true},
706+
},
707+
{
708+
"AsInt32OK/From Int32", Value.AsInt32OK, Value{Type: TypeInt32, Data: AppendInt32(nil, 12345)},
709+
nil,
710+
[]any{int32(12345), true},
711+
},
712+
{
713+
"AsInt32OK/From Int64", Value.AsInt32OK, Value{Type: TypeInt64, Data: AppendInt64(nil, 98765)},
714+
nil,
715+
[]any{int32(98765), true},
716+
},
717+
{
718+
"AsInt64/Not Number", Value.AsInt64, Value{Type: TypeString},
719+
ElementTypeError{"bsoncore.Value.AsInt64", TypeString},
720+
nil,
721+
},
722+
{
723+
"AsInt64/Double/Insufficient Bytes", Value.AsInt64, Value{Type: TypeDouble, Data: []byte{0x01, 0x02, 0x03}},
724+
NewInsufficientBytesError([]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03}),
725+
nil,
726+
},
727+
{
728+
"AsInt64/Int32/Insufficient Bytes", Value.AsInt64, Value{Type: TypeInt32, Data: []byte{0x01, 0x02}},
729+
NewInsufficientBytesError([]byte{0x01, 0x02}, []byte{0x01, 0x02}),
730+
nil,
731+
},
732+
{
733+
"AsInt64/Int64/Insufficient Bytes", Value.AsInt64, Value{Type: TypeInt64, Data: []byte{0x01, 0x02, 0x03}},
734+
NewInsufficientBytesError([]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03}),
735+
nil,
736+
},
737+
{
738+
"AsInt64/Decimal128", Value.AsInt64, Value{Type: TypeDecimal128, Data: AppendDecimal128(nil, 12345, 67890)},
739+
ElementTypeError{"bsoncore.Value.AsInt64", TypeDecimal128},
740+
nil,
741+
},
742+
{
743+
"AsInt64/From Double", Value.AsInt64, Value{Type: TypeDouble, Data: AppendDouble(nil, 123456.9)},
744+
nil,
745+
[]any{int64(123456)},
746+
},
747+
{
748+
"AsInt64/From Int32", Value.AsInt64, Value{Type: TypeInt32, Data: AppendInt32(nil, 12345)},
749+
nil,
750+
[]any{int64(12345)},
751+
},
752+
{
753+
"AsInt64/From Int64", Value.AsInt64, Value{Type: TypeInt64, Data: AppendInt64(nil, 9876543210)},
754+
nil,
755+
[]any{int64(9876543210)},
756+
},
757+
{
758+
"AsInt64OK/Not Number", Value.AsInt64OK, Value{Type: TypeString},
759+
nil,
760+
[]any{int64(0), false},
761+
},
762+
{
763+
"AsInt64OK/Double/Insufficient Bytes", Value.AsInt64OK, Value{Type: TypeDouble, Data: []byte{0x01, 0x02, 0x03}},
764+
nil,
765+
[]any{int64(0), false},
766+
},
767+
{
768+
"AsInt64OK/Int32/Insufficient Bytes", Value.AsInt64OK, Value{Type: TypeInt32, Data: []byte{0x01, 0x02}},
769+
nil,
770+
[]any{int64(0), false},
771+
},
772+
{
773+
"AsInt64OK/Int64/Insufficient Bytes", Value.AsInt64OK, Value{Type: TypeInt64, Data: []byte{0x01, 0x02, 0x03}},
774+
nil,
775+
[]any{int64(0), false},
776+
},
777+
{
778+
"AsInt64OK/Decimal128", Value.AsInt64OK, Value{Type: TypeDecimal128, Data: AppendDecimal128(nil, 12345, 67890)},
779+
nil,
780+
[]any{int64(0), false},
781+
},
782+
{
783+
"AsInt64OK/From Double", Value.AsInt64OK, Value{Type: TypeDouble, Data: AppendDouble(nil, 123456.9)},
784+
nil,
785+
[]any{int64(123456), true},
786+
},
787+
{
788+
"AsInt64OK/From Int32", Value.AsInt64OK, Value{Type: TypeInt32, Data: AppendInt32(nil, 12345)},
789+
nil,
790+
[]any{int64(12345), true},
791+
},
792+
{
793+
"AsInt64OK/From Int64", Value.AsInt64OK, Value{Type: TypeInt64, Data: AppendInt64(nil, 9876543210)},
794+
nil,
795+
[]any{int64(9876543210), true},
796+
},
797+
{
798+
"AsFloat64/Not Number", Value.AsFloat64, Value{Type: TypeString},
799+
ElementTypeError{"bsoncore.Value.AsFloat64", TypeString},
800+
nil,
801+
},
802+
{
803+
"AsFloat64/Double/Insufficient Bytes", Value.AsFloat64, Value{Type: TypeDouble, Data: []byte{0x01, 0x02, 0x03}},
804+
NewInsufficientBytesError([]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03}),
805+
nil,
806+
},
807+
{
808+
"AsFloat64/Int32/Insufficient Bytes", Value.AsFloat64, Value{Type: TypeInt32, Data: []byte{0x01, 0x02}},
809+
NewInsufficientBytesError([]byte{0x01, 0x02}, []byte{0x01, 0x02}),
810+
nil,
811+
},
812+
{
813+
"AsFloat64/Int64/Insufficient Bytes", Value.AsFloat64, Value{Type: TypeInt64, Data: []byte{0x01, 0x02, 0x03}},
814+
NewInsufficientBytesError([]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03}),
815+
nil,
816+
},
817+
{
818+
"AsFloat64/Decimal128", Value.AsFloat64, Value{Type: TypeDecimal128, Data: AppendDecimal128(nil, 12345, 67890)},
819+
ElementTypeError{"bsoncore.Value.AsFloat64", TypeDecimal128},
820+
nil,
821+
},
822+
{
823+
"AsFloat64/From Double", Value.AsFloat64, Value{Type: TypeDouble, Data: AppendDouble(nil, 3.14159)},
824+
nil,
825+
[]any{float64(3.14159)},
826+
},
827+
{
828+
"AsFloat64/From Int32", Value.AsFloat64, Value{Type: TypeInt32, Data: AppendInt32(nil, 42)},
829+
nil,
830+
[]any{float64(42)},
831+
},
832+
{
833+
"AsFloat64/From Int64", Value.AsFloat64, Value{Type: TypeInt64, Data: AppendInt64(nil, 1234567890)},
834+
nil,
835+
[]any{float64(1234567890)},
836+
},
837+
{
838+
"AsFloat64OK/Not Number", Value.AsFloat64OK, Value{Type: TypeString},
839+
nil,
840+
[]any{float64(0), false},
841+
},
842+
{
843+
"AsFloat64OK/Double/Insufficient Bytes", Value.AsFloat64OK, Value{Type: TypeDouble, Data: []byte{0x01, 0x02, 0x03}},
844+
nil,
845+
[]any{float64(0), false},
846+
},
847+
{
848+
"AsFloat64OK/Int32/Insufficient Bytes", Value.AsFloat64OK, Value{Type: TypeInt32, Data: []byte{0x01, 0x02}},
849+
nil,
850+
[]any{float64(0), false},
851+
},
852+
{
853+
"AsFloat64OK/Int64/Insufficient Bytes", Value.AsFloat64OK, Value{Type: TypeInt64, Data: []byte{0x01, 0x02, 0x03}},
854+
nil,
855+
[]any{float64(0), false},
856+
},
857+
{
858+
"AsFloat64OK/Decimal128", Value.AsFloat64OK, Value{Type: TypeDecimal128, Data: AppendDecimal128(nil, 12345, 67890)},
859+
nil,
860+
[]any{float64(0), false},
861+
},
862+
{
863+
"AsFloat64OK/From Double", Value.AsFloat64OK, Value{Type: TypeDouble, Data: AppendDouble(nil, 3.14159)},
864+
nil,
865+
[]any{float64(3.14159), true},
866+
},
867+
{
868+
"AsFloat64OK/From Int32", Value.AsFloat64OK, Value{Type: TypeInt32, Data: AppendInt32(nil, 42)},
869+
nil,
870+
[]any{float64(42), true},
871+
},
872+
{
873+
"AsFloat64OK/From Int64", Value.AsFloat64OK, Value{Type: TypeInt64, Data: AppendInt64(nil, 1234567890)},
874+
nil,
875+
[]any{float64(1234567890), true},
876+
},
637877
{
638878
"Timestamp.String/Success", Value.String, Value{Type: TypeTimestamp, Data: AppendTimestamp(nil, 12345, 67890)},
639879
nil,

0 commit comments

Comments
 (0)