From a60f3324c587826a5c470b6b985c527aed3474a8 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Wed, 26 Apr 2023 17:10:26 +0200 Subject: [PATCH] feat(logic): json_prolog/2 handle integer number --- x/logic/predicate/json.go | 18 +++++++++++++++++- x/logic/predicate/json_test.go | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/x/logic/predicate/json.go b/x/logic/predicate/json.go index bd3af008..245f281f 100644 --- a/x/logic/predicate/json.go +++ b/x/logic/predicate/json.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" "sort" + "strings" + "cosmossdk.io/math" "github.com/ichiban/prolog/engine" "github.com/okp4/okp4d/x/logic/util" "github.com/samber/lo" @@ -39,7 +41,12 @@ func JsonProlog(vm *engine.VM, j, term engine.Term, cont engine.Cont, env *engin func jsonStringToTerms(j string) (engine.Term, error) { var values any - json.Unmarshal([]byte(j), &values) + decoder := json.NewDecoder(strings.NewReader(j)) + decoder.UseNumber() // unmarshal a number into an interface{} as a Number instead of as a float64 + + if err := decoder.Decode(&values); err != nil { + return nil, err + } return jsonToTerms(values) } @@ -48,6 +55,15 @@ func jsonToTerms(value any) (engine.Term, error) { switch v := value.(type) { case string: return util.StringToTerm(v), nil + case json.Number: + r, ok := math.NewIntFromString(string(v)) + if !ok { + return nil, fmt.Errorf("could not convert number '%s' into integer term, decimal number is not handled yet", v) + } + if !r.IsInt64() { + return nil, fmt.Errorf("could not convert number '%s' into integer term, overflow", v) + } + return engine.Integer(r.Int64()), nil case map[string]any: keys := lo.Keys(v) sort.Strings(keys) diff --git a/x/logic/predicate/json_test.go b/x/logic/predicate/json_test.go index 39343a73..7e03cd84 100644 --- a/x/logic/predicate/json_test.go +++ b/x/logic/predicate/json_test.go @@ -78,6 +78,28 @@ func TestJsonProlog(t *testing.T) { }}, wantSuccess: true, }, + // ** JSON -> Prolog ** + // Number + { + description: "convert json number into prolog", + query: `json_prolog('10', Term).`, + wantResult: []types.TermResults{{ + "Term": "10", + }}, + wantSuccess: true, + }, + { + description: "convert large json number into prolog", + query: `json_prolog('100000000000000000000', Term).`, + wantSuccess: false, + wantError: fmt.Errorf("json_prolog/2: could not convert number '100000000000000000000' into integer term, overflow"), + }, + { + description: "decimal number not compatible yet", + query: `json_prolog('10.4', Term).`, + wantSuccess: false, + wantError: fmt.Errorf("json_prolog/2: could not convert number '10.4' into integer term, decimal number is not handled yet"), + }, } for nc, tc := range cases { Convey(fmt.Sprintf("Given the query #%d: %s", nc, tc.query), func() {