Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add a field 'result' to get the result whose type is not []KCLRe… #201

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions kclvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,48 @@ a2 = App {
defer os.Remove(testdata_main_k)
}

func TestWithSelectorsReturnString(t *testing.T) {
const code = `
schema Person:
labels: {str:str}

alice = Person {
"labels": {"skin": "yellow"}
}
`
const testdata_main_k = "testdata/main_selector.k"
kfile, err := os.Create(testdata_main_k)
if err != nil {
t.Fatal(err)
}
kfile.Close()

result, err := kcl.Run(testdata_main_k,
kcl.WithCode(code),
kcl.WithSelectors("alice.labels.skin"),
)
assert2.Equal(t, err, nil)
resInStr, err := result.ToString()
assert2.Equal(t, err, nil)
assert2.Equal(t, resInStr, "yellow")

resInBool, err := result.ToBool()
assert2.Equal(t, err.Error(), "failed to convert result to *bool: type mismatch")
assert2.Equal(t, resInBool, (*bool)(nil))
resInF64, err := result.ToFloat64()
assert2.Equal(t, err.Error(), "failed to convert result to *float64: type mismatch")
assert2.Equal(t, resInF64, (*float64)(nil))
resInList, err := result.ToList()
assert2.Equal(t, err.Error(), "failed to convert result to *[]interface {}: type mismatch")
assert2.Equal(t, resInList, []interface{}(nil))
resInMap, err := result.ToMap()
assert2.Equal(t, err.Error(), "failed to convert result to *map[string]interface {}: type mismatch")
assert2.Equal(t, resInMap, map[string]interface{}(map[string]interface{}(nil)))

os.Remove(testdata_main_k)
defer os.Remove(testdata_main_k)
}

func _BenchmarkRunFilesParallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Expand Down
107 changes: 101 additions & 6 deletions pkg/kcl/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"

"github.com/chai2010/jsonv"
Expand All @@ -20,11 +21,101 @@ import (
type KclType = gpyrpc.KclType

type KCLResultList struct {
list []KCLResult
// When the list is empty, the result is the raw result.
list []KCLResult
// The result is the raw result whose type is not []KCLResult.
result interface{}
raw_json_result string
raw_yaml_result string
}

// ToString returns the result as string.
func (p *KCLResultList) ToString() (string, error) {
if p == nil || p.result == nil {
return "", fmt.Errorf("result is nil")
}
var resS string
err := p.ToType(&resS)
if err != nil {
return "", err
}
return resS, nil
}

// ToBool returns the result as bool.
func (p *KCLResultList) ToBool() (*bool, error) {
if p == nil || p.result == nil {
return nil, fmt.Errorf("result is nil")
}
var resB bool
err := p.ToType(&resB)
if err != nil {
return nil, err
}
return &resB, nil
}

// ToMap returns the result as map[string]interface{}.
func (p *KCLResultList) ToMap() (map[string]interface{}, error) {
if p == nil || p.result == nil {
return nil, fmt.Errorf("result is nil")
}
var resMap map[string]interface{}
err := p.ToType(&resMap)
if err != nil {
return nil, err
}
return resMap, nil
}

// ToFloat64 returns the result as float64.
func (p *KCLResultList) ToFloat64() (*float64, error) {
if p == nil || p.result == nil {
return nil, fmt.Errorf("result is nil")
}
var resF float64
err := p.ToType(&resF)
if err != nil {
return nil, err
}
return &resF, nil
}

// ToList returns the result as []interface{}.
func (p *KCLResultList) ToList() ([]interface{}, error) {
if p == nil || p.result == nil {
return nil, fmt.Errorf("result is nil")
}
var resList []interface{}
err := p.ToType(&resList)
if err != nil {
return nil, err
}
return resList, nil
}

// ToType returns the result as target type.
func (p *KCLResultList) ToType(target interface{}) error {
if p == nil || p.result == nil {
return fmt.Errorf("result is nil")
}

srcVal := reflect.ValueOf(p.result)
targetVal := reflect.ValueOf(target)

if targetVal.Kind() != reflect.Ptr || targetVal.IsNil() {
return fmt.Errorf("failed to convert result to %T", target)
}

if srcVal.Type() != targetVal.Elem().Type() {
return fmt.Errorf("failed to convert result to %T: type mismatch", target)
}

targetVal.Elem().Set(srcVal)

return nil
}

func (p *KCLResultList) Len() int {
return len(p.list)
}
Expand Down Expand Up @@ -262,13 +353,17 @@ func run(pathList []string, opts ...Option) (*KCLResultList, error) {
}

var mList []map[string]interface{}

if err := json.Unmarshal([]byte(resp.JsonResult), &mList); err != nil {
return nil, err
}
if len(mList) == 0 {
return nil, fmt.Errorf("kcl.Run: invalid result: %s", resp.JsonResult)
err = nil
if err := json.Unmarshal([]byte(resp.JsonResult), &result.result); err != nil {
return nil, err
}
if err != nil {
return nil, err
}
}

result.list = make([]KCLResult, 0, len(mList))
for _, m := range mList {
if len(m) != 0 {
result.list = append(result.list, m)
Expand Down
Loading