diff --git a/lib/typing/mongo/bson.go b/lib/typing/mongo/bson.go index 5db6dc598..0c1f5e29a 100644 --- a/lib/typing/mongo/bson.go +++ b/lib/typing/mongo/bson.go @@ -3,6 +3,7 @@ package mongo import ( "encoding/base64" "fmt" + "math" "regexp" "strings" "time" @@ -64,12 +65,17 @@ func bsonBinaryValueToMap(value primitive.Binary) (any, error) { case bson.TypeBinaryUUIDOld, bson.TypeBinaryUUID: - parsedUUID, err := uuid.FromBytes(value.Data) - if err != nil { - return nil, err + if len(value.Data) == 16 { + // UUIDs must be 16 bytes + parsedUUID, err := uuid.FromBytes(value.Data) + if err != nil { + return nil, err + } + + return parsedUUID.String(), nil } - return parsedUUID.String(), nil + fallthrough default: return map[string]any{ "$binary": map[string]any{ @@ -103,12 +109,20 @@ func bsonValueToGoValue(value any) (any, error) { return map[string]any{"$minKey": 1}, nil case primitive.JavaScript: return map[string]any{"$code": string(v)}, nil + case primitive.CodeWithScope: + return map[string]any{"$code": string(v.Code), "$scope": v.Scope}, nil case nil, bool, string, int32, int64, - float32, float64: + float32: + return v, nil + case float64: + if math.IsNaN(v) || math.IsInf(v, 0) { + return nil, nil + } + return v, nil default: return nil, fmt.Errorf("unexpected type: %T, value: %v", v, v) diff --git a/lib/typing/mongo/bson_test.go b/lib/typing/mongo/bson_test.go index 1b0492d9c..b2c186ae3 100644 --- a/lib/typing/mongo/bson_test.go +++ b/lib/typing/mongo/bson_test.go @@ -45,6 +45,8 @@ func TestJSONEToMap(t *testing.T) { "$binary": "hW5W/8uwQR6FWpiwi4dRQA==", "$type": "04" }, + "Binary": {"$binary": {"base64": "c8edabc3f7384ca3b68dab92a91478a3", "subType": "04"}}, + "another_unique_id_v1": {"$binary": "ITG8xP+xRcquqqw3QT5IkA==", "$type": "04"}, "fileChecksum": { "$binary": "1B2M2Y8AsgTpgAmY7PhCfg==", "$type": "05" @@ -74,10 +76,13 @@ func TestJSONEToMap(t *testing.T) { "$timestamp": { "t": 1678929517, "i": 1 } }, "test_nan": NaN, + "test_nan_v2": {"$numberDouble": "NaN"}, "test_nan_string": "NaN", "test_nan_string33": "NaNaNaNa", "test_infinity": Infinity, "test_infinity_string": "Infinity", + "test_infinity_v2": {"$numberDouble": "Infinity"}, + "test_negative_infinity_v2": {"$numberDouble": "-Infinity"}, "test_infinity_string1": "Infinity123", "test_negative_infinity": -Infinity, "test_negative_infinity_string": "-Infinity", @@ -90,6 +95,8 @@ func TestJSONEToMap(t *testing.T) { result, err := JSONEToMap(bsonData) assert.NoError(t, err) + assert.Equal(t, map[string]any{"$binary": map[string]any{"base64": "c8edabc3f7384ca3b68dab92a91478a3", "subType": "04"}}, result["Binary"]) + // String assert.Equal(t, "Robin Tang", result["full_name"]) @@ -97,6 +104,13 @@ func TestJSONEToMap(t *testing.T) { assert.Equal(t, "13.37", result["test_decimal"]) assert.Equal(t, 13.37, result["test_decimal_2"]) + { + // V2 of NaN and Infinity + assert.Nil(t, result["test_nan_v2"]) + assert.Nil(t, result["test_infinity_v2"]) + assert.Nil(t, result["test_negative_infinity_v2"]) + } + assert.Equal(t, int64(10004), result["_id"]) assert.Equal(t, int64(107), result["product_id"]) assert.Equal(t, int32(1), result["quantity"]) @@ -257,6 +271,13 @@ func TestBsonValueToGoValue(t *testing.T) { assert.NoError(t, err) assert.Equal(t, map[string]any{"$code": "function() {return 0.10;}"}, result) } + { + // primitive.CodeWithScope + code := primitive.CodeWithScope{Code: "function() {return 0.10;}", Scope: true} + result, err := bsonValueToGoValue(code) + assert.NoError(t, err) + assert.Equal(t, map[string]any{"$code": "function() {return 0.10;}", "$scope": true}, result) + } { // something totally random type randomDataType struct{}