Skip to content

Commit

Permalink
[add] sui page fetch data
Browse files Browse the repository at this point in the history
  • Loading branch information
trheyi committed Nov 20, 2023
1 parent 1baaede commit eaf17e2
Show file tree
Hide file tree
Showing 4 changed files with 305 additions and 4 deletions.
188 changes: 185 additions & 3 deletions sui/core/data.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package core

import (
"fmt"
"strings"

jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/kun/any"
)

// Data get the data
Expand All @@ -22,7 +25,186 @@ func (page *Page) Data(request *Request) (map[string]interface{}, map[string]int
return nil, setting, nil
}

// Render render for the html
func (page *Page) Render(html string, data map[string]interface{}, warnings []string) (string, error) {
return html, nil
// Exec get the data
func (page *Page) Exec(request *Request) (map[string]interface{}, error) {

if page.Codes.DATA.Code == "" {
return map[string]interface{}{}, nil
}

data := map[string]interface{}{}
err := jsoniter.UnmarshalFromString(page.Codes.DATA.Code, &data)
if err != nil {
return nil, err
}

err = page.execMap(request, data)
if err != nil {
return nil, err
}

return data, nil
}

func (page *Page) execMap(r *Request, m map[string]interface{}) error {

for key, value := range m {

if strings.HasPrefix(key, "$") {
res, err := page.call(r, value)
if err != nil {
return err
}
newKey := key[1:]
m[newKey] = res
delete(m, key)
continue
}

res, err := page.execValue(r, value)
if err != nil {
return err
}
m[key] = res

}

return nil
}

func (page *Page) execValue(r *Request, value interface{}) (interface{}, error) {
switch v := value.(type) {
case string:
if strings.HasPrefix(v, "$") {
return page.call(r, strings.TrimLeft(v, "$"))
}
return v, nil

case []interface{}:
for i, item := range v {
res, err := page.execValue(r, item)
if err != nil {
return nil, err
}
v[i] = res
}
return v, nil

case []string:
interfaceSlice := make([]interface{}, len(v))
for i, item := range v {
interfaceSlice[i] = item
}
return page.execValue(r, interfaceSlice)

case map[string]interface{}:

if _, ok := v["process"].(string); ok {
if call, _ := v["__exec"].(bool); call {
res, err := page.call(r, v)
if err != nil {
return nil, err
}
return res, nil
}
}

err := page.execMap(r, v)
if err != nil {
return nil, err
}
return v, nil

default:
return v, nil
}
}

func (page *Page) call(r *Request, p interface{}) (interface{}, error) {

processName := ""
processArgs := []interface{}{r}
switch v := p.(type) {
case string:
processName = v
break

case map[string]interface{}:
if name, ok := v["process"].(string); ok {
processName = name
}

if args, ok := v["args"].([]interface{}); ok {
args, err := page.parseArgs(r, args)
if err != nil {
return nil, err
}
processArgs = append(args, processArgs...)
}
}

if processName == "" {
return nil, fmt.Errorf("process name is empty")
}

process, err := process.Of(processName, processArgs...)
if err != nil {
return nil, err
}

return process.Exec()
}

func (page *Page) parseArgs(r *Request, args []interface{}) ([]interface{}, error) {

data := any.MapOf(map[string]interface{}{
"param": r.Params,
"query": r.Query,
"payload": map[string]interface{}{},
"header": r.Headers,
"theme": r.Theme,
"locale": r.Locale,
}).Dot()

for i, arg := range args {
switch v := arg.(type) {

case string:
if strings.HasPrefix(v, "$") {
key := strings.TrimLeft(v, "$")
args[i] = key
if data.Has(key) {
v := data.Get(key)
if strings.HasPrefix(key, "query.") || strings.HasPrefix(key, "header.") {
switch arg := v.(type) {
case []interface{}:
if len(arg) == 1 {
args[i] = arg[0]
}
case []string:
if len(arg) == 1 {
args[i] = arg[0]
}
}
}
}
}

case []interface{}:
res, err := page.parseArgs(r, v)
if err != nil {
return nil, err
}
args[i] = res

case map[string]interface{}:
res, err := page.parseArgs(r, []interface{}{v})
if err != nil {
return nil, err
}
args[i] = res[0]
}
}

return args, nil
}
113 changes: 113 additions & 0 deletions sui/core/data_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package core

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/test"
)

func TestPageExec(t *testing.T) {
prepare(t)
defer clean()

page := testPage(t)
request := &Request{
Query: map[string][]string{"show": {"yes"}},
Locale: "zh-CN",
Theme: "dark",
}

data, err := page.Exec(request)
if err != nil {
t.Fatalf("Exec error: %v", err)
}

assert.NotEmpty(t, data)

res := any.Of(data).Map().Dot()
assert.Equal(t, "yes", res.Get("array[3][0].query"))
assert.Equal(t, "Article Search", res.Get("articles.data[0].description"))
}

func prepare(t *testing.T) {
test.Prepare(t, config.Conf, "YAO_TEST_BUILDER_APPLICATION")
}

func clean() {
test.Clean()
}

func testPage(t *testing.T) *Page {

page := &Page{
Name: "test",
Route: "test",
Codes: SourceCodes{
HTML: Source{
File: "test.html",
Code: `<div class="p-10">
<div>For</div>
<div s:for="articles" s:for-item="article" s:for-index="idx">
<div>{{ idx }} {{ article.title }}</div>
<div>{{ article.desc }}</div>
<div>{{ article.type == "article" ? "article" : "others"}}</div>
<div s:if="article.type == 'article'">article</div>
<div s:elif="article.type == 'image'">image</div>
<div s:else="">others</div>
</div>
<div class="mt-10">IF</div>
<div s:if="articles.length > 0">
<div>{{ articles.length > 0 }} articles.length 大于 0</div>
</div>
<div s:if="showImage == 'yes'">showImage</div>
<div s:elif="showImage == 'no'">noImage</div>
<div s:else="">others</div>
<div class="mt-10">Bind</div>
<div>
<div class="w-200">{{ input.data }}</div>
<div class="mt-5">
<input
class="w-200 p-2 bg-purple-900 text-white"
type="text"
s:bind="input.data"
placeholder="数据双向绑定"
/>
</div>
<div class="mt-5">
<input
type="button"
value="修改"
class="text-blue-600 p-2"
s:click="changeInput"
/>
</div>
</div>
</div>`,
},
DATA: Source{
File: "test.json",
Code: `{
"$articles": "scripts.article.Search",
"$showImage": {
"process": "scripts.article.ShowImage",
"args": ["$query.show"]
},
"array": [
"item-1",
"$scripts.article.Setting",
{"$images": "scripts.article.Images"},
{"process": "scripts.article.Thumbs", "args": ["$query.show"], "__exec": true }
],
"input": { "data": "hello world" }
}
`,
},
},
}

return page
}
6 changes: 6 additions & 0 deletions sui/core/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package core

// Render render for the html
func (page *Page) Render(html string, data map[string]interface{}, warnings []string) (string, error) {
return html, nil
}
2 changes: 1 addition & 1 deletion test/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func loadConnector(t *testing.T, cfg config.Config) {
}

func loadScript(t *testing.T, cfg config.Config) {
exts := []string{"*.js"}
exts := []string{"*.js", "*.ts"}
err := application.App.Walk("scripts", func(root, file string, isdir bool) error {
if isdir {
return nil
Expand Down

0 comments on commit eaf17e2

Please sign in to comment.