Skip to content

Commit

Permalink
feat(logic): json_prolog/2 handle json term to json object
Browse files Browse the repository at this point in the history
  • Loading branch information
bdeneux committed Apr 28, 2023
1 parent 9b58497 commit 4bb3f9a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
26 changes: 23 additions & 3 deletions x/logic/predicate/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/util"
"github.com/samber/lo"
Expand Down Expand Up @@ -37,7 +38,12 @@ func JsonProlog(vm *engine.VM, j, term engine.Term, cont engine.Cont, env *engin
case engine.Variable:
return engine.Error(fmt.Errorf("json_prolog/2: could not unify two variable"))
default:
b, err := termsToJson(t2)
b, err := termsToJson(t2, env)
if err != nil {
return engine.Error(fmt.Errorf("json_prolog/2: %w", err))
}

b, err = sdk.SortJSON(b)
if err != nil {
return engine.Error(fmt.Errorf("json_prolog/2: %w", err))
}
Expand All @@ -57,14 +63,28 @@ func jsonStringToTerms(j string) (engine.Term, error) {
return jsonToTerms(values)
}

func termsToJson(term engine.Term) ([]byte, error) {
func termsToJson(term engine.Term, env *engine.Env) ([]byte, error) {
switch t := term.(type) {
case engine.Atom:
return json.Marshal(t.String())
case engine.Compound:
terms, err := ExtractJsonTerm(t, env)
if err != nil {
return nil, err
}

attributes := make(map[string]json.RawMessage, len(terms))
for key, term := range terms {
raw, err := termsToJson(env.Resolve(term), env)
if err != nil {
return nil, err
}
attributes[key] = raw
}
return json.Marshal(attributes)
default:
return nil, fmt.Errorf("could not convert %s {%T} to json", t, t)
}

}

func jsonToTerms(value any) (engine.Term, error) {
Expand Down
40 changes: 40 additions & 0 deletions x/logic/predicate/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,46 @@ func TestJsonProlog(t *testing.T) {
}},
wantSuccess: true,
},
// ** Prolog -> JSON **
// Object
{
description: "convert json object from prolog",
query: `json_prolog(Json, json([foo-bar])).`,
wantResult: []types.TermResults{{
"Json": "'{\"foo\":\"bar\"}'",
}},
wantSuccess: true,
},
{
description: "convert json object with multiple attribute from prolog",
query: `json_prolog(Json, json([foo-bar,foobar-'bar foo'])).`,
wantResult: []types.TermResults{{
"Json": "'{\"foo\":\"bar\",\"foobar\":\"bar foo\"}'",
}},
wantSuccess: true,
},
{
description: "convert json object with attribute with a space into prolog",
query: `json_prolog(Json, json(['string with space'-bar])).`,
wantResult: []types.TermResults{{
"Json": "'{\"string with space\":\"bar\"}'",
}},
wantSuccess: true,
},
{
description: "ensure determinism on object attribute key sorted alphabetically",
query: `json_prolog(Json, json([b-a,a-b])).`,
wantResult: []types.TermResults{{
"Json": "'{\"a\":\"b\",\"b\":\"a\"}'",
}},
wantSuccess: true,
},
{
description: "invalid json term compound",
query: `json_prolog(Json, foo([a-b])).`,
wantSuccess: false,
wantError: fmt.Errorf("json_prolog/2: invalid functor foo. Expected json"),
},
}
for nc, tc := range cases {
Convey(fmt.Sprintf("Given the query #%d: %s", nc, tc.query), func() {
Expand Down

0 comments on commit 4bb3f9a

Please sign in to comment.