Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Ability to correctly distinguish float from int. (#2398)
With JSON mutations, we previously couldn't distinguish an int from float, using the standard json.Unmarshal. Now, we use a json.Decoder, with `UseNumber`, which allows us to correctly distinguish int from float.

This fixes #2377 and #2378 .
  • Loading branch information
manishrjain committed May 18, 2018
1 parent 7f21b82 commit 9d0022e
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
30 changes: 26 additions & 4 deletions edgraph/nquads_from_json.go
Expand Up @@ -8,6 +8,7 @@
package edgraph

import (
"bytes"
"encoding/json"
"fmt"
"strconv"
Expand Down Expand Up @@ -93,6 +94,21 @@ type mapResponse struct {

func handleBasicType(k string, v interface{}, op int, nq *api.NQuad) error {
switch v.(type) {
case json.Number:
n := v.(json.Number)
if strings.Index(n.String(), ".") >= 0 {
f, err := n.Float64()
if err != nil {
return err
}
nq.ObjectValue = &api.Value{&api.Value_DoubleVal{f}}
return nil
}
i, err := n.Int64()
if err != nil {
return err
}
nq.ObjectValue = &api.Value{&api.Value_IntVal{i}}
case string:
predWithLang := strings.SplitN(k, "@", 2)
if len(predWithLang) == 2 && predWithLang[0] != "" {
Expand Down Expand Up @@ -234,7 +250,7 @@ func mapToNquads(m map[string]interface{}, idx *int, op int, parentPred string)
}

switch v.(type) {
case string, float64, bool:
case string, float64, bool, json.Number:
if err := handleBasicType(pred, v, op, &nq); err != nil {
return mr, err
}
Expand Down Expand Up @@ -283,7 +299,7 @@ func mapToNquads(m map[string]interface{}, idx *int, op int, parentPred string)
}

switch iv := item.(type) {
case string, float64:
case string, float64, json.Number:
if err := handleBasicType(pred, iv, op, &nq); err != nil {
return mr, err
}
Expand Down Expand Up @@ -319,11 +335,17 @@ const (
)

func nquadsFromJson(b []byte, op int) ([]*api.NQuad, error) {
buffer := bytes.NewBuffer(b)
dec := json.NewDecoder(buffer)
dec.UseNumber()
ms := make(map[string]interface{})
var list []interface{}
if err := json.Unmarshal(b, &ms); err != nil {
if err := dec.Decode(&ms); err != nil {
// Couldn't parse as map, lets try to parse it as a list.
if err = json.Unmarshal(b, &list); err != nil {

buffer.Reset() // The previous contents are used. Reset here.
buffer.Write(b) // Rewrite b into buffer, so it can be consumed.
if err = dec.Decode(&list); err != nil {
return nil, err
}
}
Expand Down
32 changes: 29 additions & 3 deletions edgraph/server_test.go
Expand Up @@ -82,7 +82,7 @@ func TestNquadsFromJson1(t *testing.T) {
oval := &api.Value{&api.Value_StrVal{"Alice"}}
require.Contains(t, nq, makeNquad("_:blank-0", "name", oval))

oval = &api.Value{&api.Value_DoubleVal{26}}
oval = &api.Value{&api.Value_IntVal{26}}
require.Contains(t, nq, makeNquad("_:blank-0", "age", oval))

oval = &api.Value{&api.Value_BoolVal{true}}
Expand Down Expand Up @@ -156,13 +156,39 @@ func TestNquadsFromJson3(t *testing.T) {
}

func TestNquadsFromJson4(t *testing.T) {
json := `[{"name":"Alice","mobile":"040123456","car":"MA0123"}]`
json := `[{"name":"Alice","mobile":"040123456","car":"MA0123", "age": 21, "weight": 58.7}]`

nq, err := nquadsFromJson([]byte(json), set)
require.NoError(t, err)
require.Equal(t, 3, len(nq))
require.Equal(t, 5, len(nq))
oval := &api.Value{&api.Value_StrVal{"Alice"}}
require.Contains(t, nq, makeNquad("_:blank-0", "name", oval))
require.Contains(t, nq, makeNquad("_:blank-0", "age", &api.Value{&api.Value_IntVal{21}}))
require.Contains(t, nq, makeNquad("_:blank-0", "weight",
&api.Value{&api.Value_DoubleVal{58.7}}))
}

func TestJsonNumberParsing(t *testing.T) {
var data []string
data = append(data, `{"uid": "1", "key": 9223372036854775299}`)
data = append(data, `{"uid": "1", "key": 9223372036854775299.0}`)
data = append(data, `{"uid": "1", "key": 27670116110564327426}`)

var vals []*api.Value
vals = append(vals, &api.Value{&api.Value_IntVal{9223372036854775299}})
vals = append(vals, &api.Value{&api.Value_DoubleVal{9223372036854775299.0}})
vals = append(vals, nil)

for i, d := range data {
v := vals[i]
nqs, err := nquadsFromJson([]byte(d), set)
if v != nil {
require.NoError(t, err)
require.Equal(t, makeNquad("1", "key", v), nqs[0])
} else {
require.Error(t, err)
}
}
}

func TestNquadsFromJson_UidOutofRangeError(t *testing.T) {
Expand Down

0 comments on commit 9d0022e

Please sign in to comment.