优化载入逻辑: Step 5/5

This commit is contained in:
Max 2021-10-19 00:17:22 +08:00
parent 36bfeb8aad
commit f4e0fee81f
8 changed files with 238 additions and 64 deletions

View file

@ -11,6 +11,7 @@ env:
XIANG_MODE: debug
XIANG_SOURCE: ${{ github.WORKSPACE }}
XIANG_ROOT: ${{ github.WORKSPACE }}/tests
XIANG_ROOT_PLUGIN: ${{ HOME }}/data/gou-unit/plugins
# 服务配置
XIANG_SERVICE_DEBUG: true

View file

@ -2,9 +2,6 @@ package engine
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/yaoapp/gou"
@ -25,23 +22,24 @@ func Load(cfg config.Config) {
share.DBConnect(cfg.Database) // 创建数据库连接
app.Load(cfg) // 加载应用信息
LoadEngine(cfg.Path)
model.Load(cfg) // 加载数据模型 model
api.Load(cfg) // 加载业务接口 API
flow.Load(cfg) // 加载业务逻辑 Flow
plugin.Load(cfg) // 加载业务插件 plugin
table.Load(cfg) // 加载数据表格 table
LoadApp(share.AppRoot{
APIs: cfg.RootAPI,
Flows: cfg.RootFLow,
Models: cfg.RootModel,
Plugins: cfg.RootPlugin,
Tables: cfg.RootTable,
Charts: cfg.RootChart,
Screens: cfg.RootScreen,
Data: cfg.RootData,
})
// LoadApp(share.AppRoot{
// APIs: cfg.RootAPI,
// Flows: cfg.RootFLow,
// Models: cfg.RootModel,
// Plugins: cfg.RootPlugin,
// Tables: cfg.RootTable,
// Charts: cfg.RootChart,
// Screens: cfg.RootScreen,
// Data: cfg.RootData,
// })
// 加密密钥函数
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.Database.AESKey), "AES")
@ -113,7 +111,7 @@ func LoadEngine(from string) {
for _, script := range scripts {
switch script.Type {
case "tables":
table.Load(string(script.Content), "xiang."+script.Name)
table.LoadTable(string(script.Content), "xiang."+script.Name)
break
}
}
@ -125,23 +123,23 @@ func LoadApp(app share.AppRoot) {
// api string, flow string, model string, plugin string
// 创建应用目录
// paths := []string{app.APIs, app.Flows, app.Models, app.Plugins, app.Charts, app.Tables, app.Screens, app.Data}
paths := []string{app.Flows, app.Models, app.Plugins, app.Charts, app.Tables, app.Screens, app.Data}
for _, p := range paths {
if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") {
continue
}
root, err := filepath.Abs(strings.TrimPrefix(p, "fs://"))
if err != nil {
log.Panicf("创建目录失败(%s) %s", root, err)
}
// paths := []string{app.Flows, app.Models, app.Plugins, app.Charts, app.Tables, app.Screens, app.Data}
// for _, p := range paths {
// if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") {
// continue
// }
// root, err := filepath.Abs(strings.TrimPrefix(p, "fs://"))
// if err != nil {
// log.Panicf("创建目录失败(%s) %s", root, err)
// }
if _, err := os.Stat(root); os.IsNotExist(err) {
err := os.MkdirAll(root, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", root, err)
}
}
}
// if _, err := os.Stat(root); os.IsNotExist(err) {
// err := os.MkdirAll(root, os.ModePerm)
// if err != nil {
// log.Panicf("创建目录失败(%s) %s", root, err)
// }
// }
// }
// // 加载API
// if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
@ -181,13 +179,13 @@ func LoadApp(app share.AppRoot) {
// }
// 加载Table
if strings.HasPrefix(app.Tables, "fs://") || !strings.Contains(app.Tables, "://") {
root := strings.TrimPrefix(app.Tables, "fs://")
scripts := share.GetAppFilesFS(root, ".json")
for _, script := range scripts {
// 验证API 加载逻辑
table.Load(string(script.Content), script.Name)
}
}
// if strings.HasPrefix(app.Tables, "fs://") || !strings.Contains(app.Tables, "://") {
// root := strings.TrimPrefix(app.Tables, "fs://")
// scripts := share.GetAppFilesFS(root, ".json")
// for _, script := range scripts {
// // 验证API 加载逻辑
// table.Load(string(script.Content), script.Name)
// }
// }
}

View file

@ -6,7 +6,7 @@ import (
"github.com/yaoapp/xiang/share"
)
// Load 加载数据模型
// Load 加载业务插件
func Load(cfg config.Config) {
LoadFrom(cfg.RootPlugin, "")
}

View file

@ -149,7 +149,7 @@ func watchEngine(from string) {
}
if op == "write" || op == "create" {
script := share.GetFile(root, file)
table.Load(string(script.Content), "xiang."+script.Name) // Reload
table.LoadTable(string(script.Content), "xiang."+script.Name) // Reload
api, has := gou.APIs["xiang.table"]
if has {
api.Reload()
@ -202,7 +202,7 @@ func watchAppTable(rootTable string) {
if op == "write" || op == "create" {
script := share.GetAppFile(root, file)
table.Load(string(script.Content), script.Name) // Reload
table.LoadTable(string(script.Content), script.Name) // Reload
api, has := gou.APIs["xiang.table"]
if has {
api.Reload()

View file

@ -1,4 +1,4 @@
package engine
package table
import (
"testing"
@ -7,10 +7,17 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/xiang/table"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/model"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xun/capsule"
)
func init() {
share.DBConnect(config.Conf.Database)
model.Load(config.Conf)
Load(config.Conf)
}
func TestTableProcessSearch(t *testing.T) {
args := []interface{}{
@ -25,7 +32,7 @@ func TestTableProcessSearch(t *testing.T) {
&gin.Context{},
}
process := gou.NewProcess("xiang.table.Search", args...)
response := table.ProcessSearch(process)
response := ProcessSearch(process)
assert.NotNil(t, response)
res := any.Of(response).Map()
assert.True(t, res.Has("data"))
@ -46,7 +53,7 @@ func TestTableProcessFind(t *testing.T) {
&gin.Context{},
}
process := gou.NewProcess("xiang.table.Find", args...)
response := table.ProcessFind(process)
response := ProcessFind(process)
assert.NotNil(t, response)
res := any.Of(response).Map()
assert.Equal(t, any.Of(res.Get("id")).CInt(), 1)
@ -64,7 +71,7 @@ func TestTableProcessSave(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Save", args...)
response := table.ProcessSave(process)
response := ProcessSave(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -86,7 +93,7 @@ func TestTableProcessDelete(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Save", args...)
response := table.ProcessSave(process)
response := ProcessSave(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -96,7 +103,7 @@ func TestTableProcessDelete(t *testing.T) {
id,
}
process = gou.NewProcess("xiang.table.Delete", args...)
response = table.ProcessDelete(process)
response = ProcessDelete(process)
assert.Nil(t, response)
// 清空数据
@ -113,7 +120,7 @@ func TestTableProcessInsert(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Insert", args...)
response := table.ProcessInsert(process)
response := ProcessInsert(process)
assert.Nil(t, response)
// 清空数据
@ -132,7 +139,7 @@ func TestTableProcessDeleteWhere(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Save", args...)
response := table.ProcessSave(process)
response := ProcessSave(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -146,7 +153,7 @@ func TestTableProcessDeleteWhere(t *testing.T) {
},
}
process = gou.NewProcess("xiang.table.DeleteWhere", args...)
response = table.ProcessDeleteWhere(process)
response = ProcessDeleteWhere(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -168,7 +175,7 @@ func TestTableProcessDeleteIn(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Save", args...)
response := table.ProcessSave(process)
response := ProcessSave(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -179,7 +186,7 @@ func TestTableProcessDeleteIn(t *testing.T) {
"id",
}
process = gou.NewProcess("xiang.table.DeleteIn", args...)
response = table.ProcessDeleteIn(process)
response = ProcessDeleteIn(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -201,7 +208,7 @@ func TestTableProcessUpdateWhere(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Save", args...)
response := table.ProcessSave(process)
response := ProcessSave(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -218,7 +225,7 @@ func TestTableProcessUpdateWhere(t *testing.T) {
},
}
process = gou.NewProcess("xiang.table.UpdateWhere", args...)
response = table.ProcessUpdateWhere(process)
response = ProcessUpdateWhere(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -240,7 +247,7 @@ func TestTableProcessUpdateIn(t *testing.T) {
},
}
process := gou.NewProcess("xiang.table.Save", args...)
response := table.ProcessSave(process)
response := ProcessSave(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -254,7 +261,7 @@ func TestTableProcessUpdateIn(t *testing.T) {
},
}
process = gou.NewProcess("xiang.table.UpdateIn", args...)
response = table.ProcessUpdateIn(process)
response = ProcessUpdateIn(process)
assert.NotNil(t, response)
assert.True(t, any.Of(response).IsInt())
@ -267,7 +274,7 @@ func TestTableProcessUpdateIn(t *testing.T) {
func TestTableProcessSetting(t *testing.T) {
args := []interface{}{"service", ""}
process := gou.NewProcess("xiang.table.Setting", args...)
response := table.ProcessSetting(process)
response := ProcessSetting(process)
assert.NotNil(t, response)
res := any.Of(response).Map()
assert.Equal(t, res.Get("name"), "云服务库")
@ -283,7 +290,7 @@ func TestTableProcessSetting(t *testing.T) {
func TestTableProcessSettingList(t *testing.T) {
args := []interface{}{"service", "list"}
process := gou.NewProcess("xiang.table.Setting", args...)
response := table.ProcessSetting(process)
response := ProcessSetting(process)
assert.NotNil(t, response)
res := any.Of(response).Map()
assert.True(t, res.Has("actions"))
@ -294,7 +301,7 @@ func TestTableProcessSettingList(t *testing.T) {
func TestTableProcessSettingListEdit(t *testing.T) {
args := []interface{}{"service", "list, edit"}
process := gou.NewProcess("xiang.table.Setting", args...)
response := table.ProcessSetting(process)
response := ProcessSetting(process)
assert.NotNil(t, response)
res := any.Of(response).MapStr().Dot()
assert.True(t, res.Has("list.actions"))

View file

@ -9,14 +9,34 @@ import (
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/helper"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)
// Tables 已载入模型
var Tables = map[string]*Table{}
// Load 载入数据表格
func Load(source string, name string) *Table {
// Load 加载数据表格
func Load(cfg config.Config) {
LoadFrom(cfg.RootTable, "")
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
if share.DirNotExists(dir) {
return
}
share.Walk(dir, ".json", func(root, filename string) {
name := share.SpecName(root, filename)
content := share.ReadFile(filename)
LoadTable(string(content), name)
})
}
// LoadTable 载入数据表格
func LoadTable(source string, name string) *Table {
var input io.Reader = nil
if strings.HasPrefix(source, "file://") || strings.HasPrefix(source, "fs://") {
filename := strings.TrimPrefix(source, "file://")
@ -61,7 +81,7 @@ func Select(name string) *Table {
// Reload 更新数据表格配置
func (table *Table) Reload() *Table {
*table = *Load(table.Source, table.Name)
*table = *LoadTable(table.Source, table.Name)
return table
}

29
table/table_test.go Normal file
View file

@ -0,0 +1,29 @@
package table
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/model"
"github.com/yaoapp/xiang/share"
)
func TestLoad(t *testing.T) {
share.DBConnect(config.Conf.Database)
model.Load(config.Conf)
Tables = make(map[string]*Table)
Load(config.Conf)
LoadFrom("not a path", "404.")
check(t)
}
func check(t *testing.T) {
keys := []string{}
for key := range Tables {
keys = append(keys, key)
}
assert.Equal(t, 2, len(keys))
}

View file

@ -0,0 +1,119 @@
{
"name": "菜单",
"version": "1.0.0",
"decription": "菜单设置",
"bind": {
"model": "service"
},
"apis": {},
"columns": {},
"filters": {},
"list": {
"primary": "id",
"layout": {
"columns": [
{
"name": "名称",
"width": "240px"
},
{
"name": "父节点"
},
{
"name": "图标"
},
{
"name": "状态"
},
{
"name": "路由"
},
{
"name": "排列"
},
{
"name": "block布局"
},
{
"name": "显示"
}
],
"filters": [
{
"name": "名称",
"width": 6
}
]
},
"actions": {
"create": {
"type": "button",
"props": {
"label": "新建菜单",
"icon": "fas fa-plus"
}
},
"view": {},
"edit": {},
"import": {},
"update": {},
"delete": {},
"insert": {},
"updateWhere": {},
"deleteWhere": {},
"updateSelect": {},
"deleteSelect": {},
"pagination": {},
"setting": {}
}
},
"edit": {
"primary": "id",
"layout": {
"fieldset": [
{
"title": "基础信息",
"description": "",
"columns": [
{
"name": "名称",
"width": 6
},
{
"name": "图标",
"width": 6
},
{
"name": "路由",
"width": 6
},
{
"name": "排列",
"width": 6
},
{
"name": "block布局",
"width": 6
},
{
"name": "显示",
"width": 6
}
]
}
]
},
"actions": {
"cancel": {},
"save": {
"type": "button",
"props": {
"label": "保存"
}
},
"delete": {}
}
},
"insert": {},
"view": {}
}