From c0bee95cf6f2a5659e484202fc64e4d22806e589 Mon Sep 17 00:00:00 2001 From: George Suntres Date: Tue, 14 Apr 2026 11:29:05 -0400 Subject: [PATCH] Add JsonPrintError --- json.go | 40 ++++++++++++++++++++++++++++++++++++++++ json_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ math.go | 10 ++++++++++ struct.go | 15 ++++++++++++++- 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 json.go create mode 100644 json_test.go diff --git a/json.go b/json.go new file mode 100644 index 0000000..946a5b4 --- /dev/null +++ b/json.go @@ -0,0 +1,40 @@ +package commons + +import ( + "log" + "reflect" + "encoding/json" +) + +func JsonPrintError(err error, content []byte) { + if syntaxErr, ok := err.(*json.SyntaxError); ok { + totalLen := int64(len(content)) + + min := MathMin(int64(50), syntaxErr.Offset) + + from := MathMax(syntaxErr.Offset - min, 0) + to := MathMin(syntaxErr.Offset + min, totalLen) + + sliceBuf := content[from:to] + + log.Printf("Failed to unmarshal %#v \n %s", syntaxErr, string(sliceBuf)) + } else { + log.Printf("%v", err) + } +} + +// JsonEqual check if two json string representations are equal. +func JsonEqual(a, b string) bool { + var o1 any + var o2 any + + if err := json.Unmarshal([]byte(a), &o1); err != nil { + return false + } + + if err := json.Unmarshal([]byte(b), &o2); err != nil { + return false + } + + return reflect.DeepEqual(o1, o2) +} \ No newline at end of file diff --git a/json_test.go b/json_test.go new file mode 100644 index 0000000..ec1b3bf --- /dev/null +++ b/json_test.go @@ -0,0 +1,41 @@ +package commons + +import ( + "log" + "fmt" + "bytes" + "encoding/json" + "testing" +) + +func TestJsonPrintError(t *testing.T) { + + jsonstr := ` + { + "name": "George", + "age": 87, + active": "false", + "properties": { + "one": "two", + "three": "four" + } + } + ` + + var buf bytes.Buffer + log.SetOutput(&buf) + + content := []byte(jsonstr) + var data map[string]any + + err := json.Unmarshal(content, &data) + + JsonPrintError(err, content) + + errOut := fmt.Sprintf("%s", buf.String()) + + if errOut == "" { + t.Fatal("should have printed the error") + } +} + diff --git a/math.go b/math.go index e150b60..b1930b5 100644 --- a/math.go +++ b/math.go @@ -9,3 +9,13 @@ func MathMin[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | } return b } + +// MathMax will compare two integers and return the one with the smaller value. +func MathMax[T ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | ~string](a, b T) T { + if a > b { + return a + } + return b +} \ No newline at end of file diff --git a/struct.go b/struct.go index 5f08c3b..4458c8c 100644 --- a/struct.go +++ b/struct.go @@ -4,6 +4,7 @@ import ( "log" "reflect" "strings" + "bytes" "encoding/json" "github.com/go-viper/mapstructure/v2" @@ -52,8 +53,11 @@ func StructMustToMap(data any) map[string]any { return nil } + dec := json.NewDecoder(bytes.NewReader(b)) + dec.UseNumber() + var res map[string]any - err = json.Unmarshal(b, &res) + err = dec.Decode(&res) if err != nil { log.Printf("Failed to unmarshal %v", err) @@ -219,6 +223,15 @@ func BsonAToSlice(m any) ([]map[string]any, error) { return o.Items, nil } +func MapFromString(s string) (map[string]any, error) { + var b map[string]any + if err := bson.Unmarshal([]byte(s), &b); err != nil { + return nil, err + } + + return b, nil +} + // MapIsSubset given two map[string]any m1 and m2 will determine if m1 is a subset of m2. // Only fields' name is evaluated not their values. func MapIsSubset(subset, superset any) bool {