From 675eb0c6ea83cf5e5618684e4ebbbc03659baab4 Mon Sep 17 00:00:00 2001 From: Debaditya Dey Date: Fri, 1 Nov 2024 09:26:37 +0530 Subject: [PATCH 1/2] Fix for Big Integers are getting converted to float before storing thus losing their precision (#1163) --- internal/server/utils/redisCmdAdapter.go | 66 ++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/internal/server/utils/redisCmdAdapter.go b/internal/server/utils/redisCmdAdapter.go index e575ec6bf..f1421a735 100644 --- a/internal/server/utils/redisCmdAdapter.go +++ b/internal/server/utils/redisCmdAdapter.go @@ -1,14 +1,16 @@ package utils import ( + bytes_ext "bytes" "encoding/json" "errors" "fmt" "io" "net/http" + "regexp" "strconv" "strings" - "regexp" + "github.com/dicedb/dice/internal/cmd" diceerrors "github.com/dicedb/dice/internal/errors" ) @@ -72,7 +74,8 @@ func ParseHTTPRequest(r *http.Request) (*cmd.DiceDBCmd, error) { if len(body) > 0 { var jsonBody map[string]interface{} - if err := json.Unmarshal(body, &jsonBody); err != nil { + if err := unmarshalRequestBody(body, &jsonBody); err != nil { + fmt.Println("Error unmarshaling body:", err) return nil, err } @@ -158,9 +161,9 @@ func ParseWebsocketMessage(msg []byte) (*cmd.DiceDBCmd, error) { // handle other commands for _, match := range matches { if match[1] != "" { - cmdArr = append(cmdArr, match[1]) + cmdArr = append(cmdArr, match[1]) } else if match[2] != "" { - cmdArr = append(cmdArr, match[2]) + cmdArr = append(cmdArr, match[2]) } else { cmdArr = append(cmdArr, match[3]) } @@ -224,3 +227,58 @@ func formatValue(val interface{}) string { return string(jsonBytes) } } + +func unmarshalRequestBody(data []byte, v *map[string]interface{}) error { + var rawMap map[string]interface{} + + if err := json.Unmarshal(data, &rawMap); err != nil { + return err + } + + for key, val := range rawMap { + switch val := val.(type) { + case float64: + // force check whether the float64 value is a big integer + // if it is, typecast it and set the value for the key in the rawMap + if val == float64(int64(val)) { + rawMap[key] = json.Number(strconv.FormatInt(int64(val), 10)) + } + case map[string]interface{}: + jsonValue, err := json.Marshal(val) + if err != nil { + return err + } + // recursively unmarshal nested JSON body + var nestedMap map[string]interface{} + if err := unmarshalRequestBody(jsonValue, &nestedMap); err != nil { + return err + } + rawMap[key] = nestedMap + case []interface{}: + for i, item := range val { + if nestedMap, ok := item.(map[string]interface{}); ok { + jsonValue, err := json.Marshal(nestedMap) + if err != nil { + return err + } + // recursively unmarshal nested JSON body + var nestedNestedMap map[string]interface{} + if err := unmarshalRequestBody(jsonValue, &nestedNestedMap); err != nil { + return err + } + val[i] = nestedNestedMap + } + } + } + } + + bytes, err := json.Marshal(rawMap) + if err != nil { + return err + } + + decoder := json.NewDecoder(bytes_ext.NewReader(bytes)) + decoder.UseNumber() // Ensures all numbers are kept as json.Number + return decoder.Decode(&v) + +} From d4b0bc0b65d249c17bb8d7cd4b0b8d2205de1158 Mon Sep 17 00:00:00 2001 From: Debaditya Dey Date: Fri, 1 Nov 2024 16:52:25 +0530 Subject: [PATCH 2/2] Refactoring variables and lint issues (#1163) --- internal/server/utils/redisCmdAdapter.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/server/utils/redisCmdAdapter.go b/internal/server/utils/redisCmdAdapter.go index dd9d78196..2866ba4c8 100644 --- a/internal/server/utils/redisCmdAdapter.go +++ b/internal/server/utils/redisCmdAdapter.go @@ -1,7 +1,7 @@ package utils import ( - bytes_ext "bytes" + "bytes" "encoding/base64" "encoding/json" "errors" @@ -257,11 +257,9 @@ func isBase64Encoded(s string) bool { func unmarshalRequestBody(data []byte, v *map[string]interface{}) error { var rawMap map[string]interface{} - if err := json.Unmarshal(data, &rawMap); err != nil { return err } - for key, val := range rawMap { switch val := val.(type) { case float64: @@ -299,13 +297,12 @@ func unmarshalRequestBody(data []byte, v *map[string]interface{}) error { } } - bytes, err := json.Marshal(rawMap) + jsonBytes, err := json.Marshal(rawMap) if err != nil { return err } - decoder := json.NewDecoder(bytes_ext.NewReader(bytes)) + decoder := json.NewDecoder(bytes.NewReader(jsonBytes)) decoder.UseNumber() // Ensures all numbers are kept as json.Number return decoder.Decode(&v) - }