Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing #1163 : Inconsistent Behaviour in http server : Big Integers are getting converted to float before storing thus losing their precision #1227

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion internal/server/utils/redisCmdAdapter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package utils

import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
Expand Down Expand Up @@ -75,7 +76,8 @@

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
}

Expand Down Expand Up @@ -252,3 +254,55 @@
}
return false
}

func unmarshalRequestBody(data []byte, v *map[string]interface{}) error {

Check failure on line 258 in internal/server/utils/redisCmdAdapter.go

View workflow job for this annotation

GitHub Actions / lint

ptrToRefParam: consider `v' to be of non-pointer type (gocritic)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since maps are already reference types, no need to send them as pointers.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AshwinKul28 When you pass a map to a function, Go passes a reference to the map, meaning any modifications to the contents of the map itself (adding, removing, or updating keys and values) are indeed reflected outside the function.
But, in this case, I'm trying to overwrite the entire reference itself of v in the last line of the method using deoder.Decode(&v), basically trying to store the decoded map reference in the input map, so that the caller can directly access the map without a need for reassignment. So, passing by reference makes sense here IMO.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AshwinKul28 If there are no further comments, let's merge this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @deydebaditya sorry got occupied with other stuff. I see one lint error which is what I was talking about earlier in this thread. Since map is a ref type no need to pass it as pointer again.

Once you make that change hope linter checks will be successful

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
}
}
}
}

jsonBytes, err := json.Marshal(rawMap)
if err != nil {
return err
}

decoder := json.NewDecoder(bytes.NewReader(jsonBytes))
decoder.UseNumber() // Ensures all numbers are kept as json.Number
return decoder.Decode(&v)
}
Loading