From 67afbf6956fa2fd43779bbf99afdc62a401ad5be Mon Sep 17 00:00:00 2001 From: Evan Phoenix Date: Thu, 11 Jan 2024 14:06:27 -0800 Subject: [PATCH] Always use UseNumber() to avoid float64 lossyness --- v5/merge.go | 27 +++++++++++++++++++-------- v5/patch.go | 22 +++++++++++----------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/v5/merge.go b/v5/merge.go index a7c4573..09c13c0 100644 --- a/v5/merge.go +++ b/v5/merge.go @@ -119,11 +119,11 @@ func MergePatch(docData, patchData []byte) ([]byte, error) { func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) { doc := &partialDoc{} - docErr := json.Unmarshal(docData, doc) + docErr := unmarshal(docData, doc) patch := &partialDoc{} - patchErr := json.Unmarshal(patchData, patch) + patchErr := unmarshal(patchData, patch) if isSyntaxError(docErr) { return nil, errBadJSONDoc @@ -151,7 +151,7 @@ func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) { } } else { patchAry := &partialArray{} - patchErr = json.Unmarshal(patchData, patchAry) + patchErr = unmarshal(patchData, patchAry) if patchErr != nil { return nil, errBadJSONPatch @@ -227,12 +227,12 @@ func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { originalDoc := map[string]interface{}{} modifiedDoc := map[string]interface{}{} - err := json.Unmarshal(originalJSON, &originalDoc) + err := unmarshal(originalJSON, &originalDoc) if err != nil { return nil, errBadJSONDoc } - err = json.Unmarshal(modifiedJSON, &modifiedDoc) + err = unmarshal(modifiedJSON, &modifiedDoc) if err != nil { return nil, errBadJSONDoc } @@ -245,6 +245,12 @@ func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { return json.Marshal(dest) } +func unmarshal(data []byte, into interface{}) error { + dec := json.NewDecoder(bytes.NewReader(data)) + dec.UseNumber() + return dec.Decode(into) +} + // createArrayMergePatch will return an array of merge-patch documents capable // of converting the original document to the modified document for each // pair of JSON documents provided in the arrays. @@ -253,12 +259,12 @@ func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { originalDocs := []json.RawMessage{} modifiedDocs := []json.RawMessage{} - err := json.Unmarshal(originalJSON, &originalDocs) + err := unmarshal(originalJSON, &originalDocs) if err != nil { return nil, errBadJSONDoc } - err = json.Unmarshal(modifiedJSON, &modifiedDocs) + err = unmarshal(modifiedJSON, &modifiedDocs) if err != nil { return nil, errBadJSONDoc } @@ -314,6 +320,11 @@ func matchesValue(av, bv interface{}) bool { if bt == at { return true } + case json.Number: + bt := bv.(json.Number) + if bt == at { + return true + } case float64: bt := bv.(float64) if bt == at { @@ -377,7 +388,7 @@ func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { if len(dst) > 0 { into[key] = dst } - case string, float64, bool: + case string, float64, bool, json.Number: if !matchesValue(av, bv) { into[key] = bv } diff --git a/v5/patch.go b/v5/patch.go index 73ff2c5..48cbc1e 100644 --- a/v5/patch.go +++ b/v5/patch.go @@ -172,7 +172,7 @@ func (err *syntaxError) Error() string { } func (n *partialDoc) UnmarshalJSON(data []byte) error { - if err := json.Unmarshal(data, &n.obj); err != nil { + if err := unmarshal(data, &n.obj); err != nil { return err } buffer := bytes.NewBuffer(data) @@ -252,7 +252,7 @@ func (n *lazyNode) intoDoc() (*partialDoc, error) { return nil, ErrInvalid } - err := json.Unmarshal(*n.raw, &n.doc) + err := unmarshal(*n.raw, &n.doc) if err != nil { return nil, err @@ -271,7 +271,7 @@ func (n *lazyNode) intoAry() (*partialArray, error) { return nil, ErrInvalid } - err := json.Unmarshal(*n.raw, &n.ary) + err := unmarshal(*n.raw, &n.ary) if err != nil { return nil, err @@ -302,7 +302,7 @@ func (n *lazyNode) tryDoc() bool { return false } - err := json.Unmarshal(*n.raw, &n.doc) + err := unmarshal(*n.raw, &n.doc) if err != nil { return false @@ -317,7 +317,7 @@ func (n *lazyNode) tryAry() bool { return false } - err := json.Unmarshal(*n.raw, &n.ary) + err := unmarshal(*n.raw, &n.ary) if err != nil { return false @@ -398,7 +398,7 @@ func (o Operation) Kind() string { if obj, ok := o["op"]; ok && obj != nil { var op string - err := json.Unmarshal(*obj, &op) + err := unmarshal(*obj, &op) if err != nil { return "unknown" @@ -415,7 +415,7 @@ func (o Operation) Path() (string, error) { if obj, ok := o["path"]; ok && obj != nil { var op string - err := json.Unmarshal(*obj, &op) + err := unmarshal(*obj, &op) if err != nil { return "unknown", err @@ -432,7 +432,7 @@ func (o Operation) From() (string, error) { if obj, ok := o["from"]; ok && obj != nil { var op string - err := json.Unmarshal(*obj, &op) + err := unmarshal(*obj, &op) if err != nil { return "unknown", err @@ -461,7 +461,7 @@ func (o Operation) ValueInterface() (interface{}, error) { var v interface{} - err := json.Unmarshal(*obj, &v) + err := unmarshal(*obj, &v) if err != nil { return nil, err @@ -1079,7 +1079,7 @@ func Equal(a, b []byte) bool { func DecodePatch(buf []byte) (Patch, error) { var p Patch - err := json.Unmarshal(buf, &p) + err := unmarshal(buf, &p) if err != nil { return nil, err @@ -1124,7 +1124,7 @@ func (p Patch) ApplyIndentWithOptions(doc []byte, indent string, options *ApplyO pd = &partialDoc{} } - err := json.Unmarshal(doc, pd) + err := unmarshal(doc, pd) if err != nil { return nil, err