Skip to content

Commit

Permalink
feat(logic): convert basic json object into prolog
Browse files Browse the repository at this point in the history
  • Loading branch information
bdeneux committed Apr 26, 2023
1 parent e43010d commit 310459a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 3 deletions.
16 changes: 16 additions & 0 deletions x/logic/predicate/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package predicate
import (
"encoding/json"
"fmt"
"sort"

"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/util"
"github.com/samber/lo"
)

// AtomJSON is a term which represents a json as a compound term `json([Pair])`.
Expand Down Expand Up @@ -46,6 +48,20 @@ func jsonToTerms(value any) (engine.Term, error) {
switch v := value.(type) {
case string:
return util.StringToTerm(v), nil
case map[string]any:
keys := lo.Keys(v)
sort.Strings(keys)

attributes := make([]engine.Term, 0, len(v))
for _, key := range keys {
attributeValue, err := jsonToTerms(v[key])
if err != nil {
return nil, err
}
attributes = append(attributes, AtomPair.Apply(engine.NewAtom(key), attributeValue))
}

return AtomJSON.Apply(engine.List(attributes...)), nil
default:
return nil, fmt.Errorf("could not convert %s (%T) to a prolog term", v, v)
}
Expand Down
45 changes: 42 additions & 3 deletions x/logic/predicate/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,62 @@ import (
func TestJsonProlog(t *testing.T) {
Convey("Given a test cases", t, func() {
cases := []struct {
description string
program string
query string
wantResult []types.TermResults
wantError error
wantSuccess bool
}{
// ** JSON -> Prolog **
// String
{
query: `json_prolog('"foo"', Term).`,
description: "convert direct string (valid json) into prolog",
query: `json_prolog('"foo"', Term).`,
wantResult: []types.TermResults{{
"Term": "foo",
}},
wantSuccess: true,
},
{
query: `json_prolog('{"foo": "bar"}', Term).`,
description: "convert direct string with space (valid json) into prolog",
query: `json_prolog('"a string with space"', Term).`,
wantResult: []types.TermResults{{
"Term": "json([-(foo, 'bar')])",
"Term": "'a string with space'",
}},
wantSuccess: true,
},
// ** JSON -> Prolog **
// Object
{
description: "convert json object into prolog",
query: `json_prolog('{"foo": "bar"}', Term).`,
wantResult: []types.TermResults{{
"Term": "json([foo-bar])",
}},
wantSuccess: true,
},
{
description: "convert json object with multiple attribute into prolog",
query: `json_prolog('{"foo": "bar", "foobar": "bar foo"}', Term).`,
wantResult: []types.TermResults{{
"Term": "json([foo-bar,foobar-'bar foo'])",
}},
wantSuccess: true,
},
{
description: "convert json object with attribute with a space into prolog",
query: `json_prolog('{"string with space": "bar"}', Term).`,
wantResult: []types.TermResults{{
"Term": "json(['string with space'-bar])",
}},
wantSuccess: true,
},
{
description: "ensure determinism on object attribute key sorted alphabetically",
query: `json_prolog('{"b": "a", "a": "b"}', Term).`,
wantResult: []types.TermResults{{
"Term": "json([a-b,b-a])",
}},
wantSuccess: true,
},
Expand Down

0 comments on commit 310459a

Please sign in to comment.