+ Table Hook SearchBefore & SearchAfter ( pre )

This commit is contained in:
Max 2022-01-06 18:24:18 +08:00
parent 0c07b6ea2b
commit b1b21a527b
16 changed files with 241 additions and 9 deletions

View file

@ -20,5 +20,5 @@ func check(t *testing.T) {
for key := range gou.Flows {
keys = append(keys, key)
}
assert.Equal(t, 10, len(keys))
assert.Equal(t, 12, len(keys))
}

View file

@ -25,3 +25,9 @@ func MapGet(record map[string]interface{}, key string) interface{} {
data := maps.MapOf(record).Dot()
return data.Get(key)
}
// MapSet xiang.helper.MapSet 设定数值并返回新映射表
func MapSet(record map[string]interface{}, key string, value interface{}) map[string]interface{} {
record[key] = value
return record
}

View file

@ -16,10 +16,19 @@ func ProcessMapKeys(process *gou.Process) interface{} {
return MapKeys(record)
}
// ProcessMapGet xiang.helper.MapKey 返回映射表给定键的值
// ProcessMapGet xiang.helper.MapGet 返回映射表给定键的值
func ProcessMapGet(process *gou.Process) interface{} {
process.ValidateArgNums(2)
record := process.ArgsMap(0)
key := process.ArgsString(1)
return MapGet(record, key)
}
// ProcessMapSet xiang.helper.MapSet 返回映射表给定键的值
func ProcessMapSet(process *gou.Process) interface{} {
process.ValidateArgNums(3)
record := process.ArgsMap(0)
key := process.ArgsString(1)
value := process.Args[2]
return MapSet(record, key, value)
}

View file

@ -17,6 +17,7 @@ func init() {
gou.RegisterProcessHandler("xiang.helper.MapKeys", ProcessMapKeys)
gou.RegisterProcessHandler("xiang.helper.MapValues", ProcessMapValues)
gou.RegisterProcessHandler("xiang.helper.MapGet", ProcessMapGet)
gou.RegisterProcessHandler("xiang.helper.MapSet", ProcessMapSet)
gou.RegisterProcessHandler("xiang.helper.Captcha", ProcessCaptcha)
gou.RegisterProcessHandler("xiang.helper.CaptchaValidate", ProcessCaptchaValidate)

View file

@ -71,7 +71,7 @@ func (api API) DefaultInt(i int, defaults ...int) int {
value = defaults[0]
}
if api.Default[i] == nil || len(api.Default) <= i {
if len(api.Default) <= i || api.Default[i] == nil {
return value
}

42
table/json.go Normal file
View file

@ -0,0 +1,42 @@
package table
// // UnmarshalJSON for json marshalJSON
// func (table *Table) UnmarshalJSON(data []byte) error {
// var v interface{}
// err := jsoniter.Unmarshal(data, &v)
// if err != nil {
// return err
// }
// // values := []interface{}{}
// // switch v.(type) {
// // case string: // "kind rollup 所有类型, city"
// // strarr := strings.Split(v.(string), ",")
// // for _, str := range strarr {
// // groups.PushString(str)
// // }
// // break
// // case []interface{}: // ["name", {"field":"foo"}, "id rollup 所有类型"]
// // values = v.([]interface{})
// // break
// // }
// // for _, value := range values {
// // switch value.(type) {
// // case string: // "kind rollup 所有类型"
// // groups.PushString(value.(string))
// // break
// // case map[string]interface{}: // {"field":"foo"}
// // groups.PushMap(value.(map[string]interface{}))
// // break
// // }
// // }
// return nil
// }
// // MarshalJSON for json marshalJSON
// func (table Table) MarshalJSON() ([]byte, error) {
// return jsoniter.Marshal(nil)
// }

View file

@ -28,20 +28,30 @@ func init() {
// 按条件查询数据记录, 请求成功返回符合查询条件带有分页信息的数据对象
func ProcessSearch(process *gou.Process) interface{} {
process.ValidateArgNums(4)
// 读取表格名称
process.ValidateArgNums(1)
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["search"].ValidateLoop("xiang.table.search")
if process.NumOfArgsIs(5) && api.IsAllow(process.Args[4]) {
return nil
}
// Before Hook
process.Args = table.Before(table.Hooks.BeforeSearch, process.Args)
// 参数表
process.ValidateArgNums(4)
param := api.MergeDefaultQueryParam(process.ArgsQueryParams(1), 0)
page := process.ArgsInt(2, api.DefaultInt(1))
pagesize := process.ArgsInt(3, api.DefaultInt(2))
return gou.NewProcess(api.Process, param, page, pagesize).Run()
// 查询数据
response := gou.NewProcess(api.Process, param, page, pagesize).Run()
// After Hook
return table.After(table.Hooks.AfterSearch, response)
}
// ProcessFind xiang.table.Find

View file

@ -1,6 +1,8 @@
package table
import (
"fmt"
"path/filepath"
"testing"
"github.com/gin-gonic/gin"
@ -8,8 +10,12 @@ import (
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/kun/utils"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/flow"
_ "github.com/yaoapp/xiang/helper"
"github.com/yaoapp/xiang/model"
"github.com/yaoapp/xiang/query"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xun/capsule"
)
@ -18,7 +24,14 @@ func init() {
share.DBConnect(config.Conf.Database)
model.Load(config.Conf)
share.Load(config.Conf)
query.Load(config.Conf)
flow.LoadFrom(filepath.Join(config.Conf.Root, "flows", "hooks"), "hooks.")
Load(config.Conf)
for name := range gou.Flows {
fmt.Println(name)
}
fmt.Println(filepath.Join(config.Conf.Root, "tables", "hooks"))
}
func TestTableProcessSearch(t *testing.T) {
@ -33,8 +46,7 @@ func TestTableProcessSearch(t *testing.T) {
2,
&gin.Context{},
}
process := gou.NewProcess("xiang.table.Search", args...)
response := ProcessSearch(process)
response := gou.NewProcess("xiang.table.Search", args...).Run()
assert.NotNil(t, response)
res := any.Of(response).Map()
assert.True(t, res.Has("data"))
@ -48,6 +60,26 @@ func TestTableProcessSearch(t *testing.T) {
assert.Equal(t, 2, res.Get("pagesize"))
}
func TestTableProcessSearchWithHook(t *testing.T) {
args := []interface{}{"hooks.search"}
response := gou.NewProcess("xiang.table.Search", args...).Run()
utils.Dump(response)
assert.NotNil(t, response)
res := any.Of(response).Map()
assert.True(t, res.Has("data"))
assert.True(t, res.Has("next"))
assert.True(t, res.Has("page"))
assert.True(t, res.Has("pagecnt"))
assert.True(t, res.Has("pagesize"))
assert.True(t, res.Has("prev"))
assert.True(t, res.Has("total"))
assert.Equal(t, 1, res.Get("page"))
assert.Equal(t, 2, res.Get("pagesize"))
assert.Equal(t, float64(100), res.Get("after"))
}
func TestTableProcessFind(t *testing.T) {
args := []interface{}{
"service",

View file

@ -9,8 +9,10 @@ import (
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/helper"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/xlog"
)
// Tables 已载入模型
@ -147,6 +149,38 @@ func getDefaultAPIs(bind Bind) map[string]share.API {
return apis
}
// Before 运行 Before hook
func (table *Table) Before(process string, processArgs []interface{}) []interface{} {
if process == "" {
return processArgs
}
args := []interface{}{}
res := []interface{}{}
if len(processArgs) > 0 {
args = processArgs[1:]
res = append(res, processArgs[0])
}
response := gou.NewProcess(process, args...).Run()
if fixedArgs, ok := response.([]interface{}); ok {
res = append(res, fixedArgs...)
return res
}
xlog.Println("无效的处理器", maps.StrAny{"process": process, "response": response})
return processArgs
}
// After 运行 After hook
func (table *Table) After(process string, data interface{}) interface{} {
if process == "" {
return data
}
fmt.Println("After", process)
return gou.NewProcess(process, data).Run()
}
// loadFilters 加载查询过滤器
func (table *Table) loadFilters() {
if table.Bind.Model == "" {

View file

@ -48,5 +48,5 @@ func check(t *testing.T) {
for key := range Tables {
keys = append(keys, key)
}
assert.Equal(t, 4, len(keys))
assert.Equal(t, 5, len(keys))
}

View file

@ -14,6 +14,7 @@ type Table struct {
Title string `json:"title,omitempty"`
Decription string `json:"decription,omitempty"`
Bind Bind `json:"bind,omitempty"`
Hooks Hooks `json:"hooks,omitempty"`
APIs map[string]share.API `json:"apis,omitempty"`
Columns map[string]share.Column `json:"columns,omitempty"`
Filters map[string]share.Filter `json:"filters,omitempty"`
@ -28,3 +29,29 @@ type Bind struct {
Model string `json:"model"`
Withs map[string]gou.With `json:"withs,omitempty"`
}
// Hooks 表格数据模型
type Hooks struct {
BeforeFind string `json:"before:find,omitempty"`
AfterFind string `json:"after:find,omitempty"`
BeforeSearch string `json:"before:search,omitempty"`
AfterSearch string `json:"after:search,omitempty"`
BeforeSave string `json:"before:save,omitempty"`
AfterSave string `json:"after:save,omitempty"`
BeforeDelete string `json:"before:delete,omitempty"`
AfterDelete string `json:"after:delete,omitempty"`
BeforeInsert string `json:"before:insert,omitempty"`
AfterInsert string `json:"after:insert,omitempty"`
BeforeDeleteIn string `json:"before:delete-in,omitempty"`
AfterDeleteIn string `json:"after:delete-in,omitempty"`
BeforeDeleteWhere string `json:"before:delete-where,omitempty"`
AfterDeleteWhere string `json:"after:delete-where,omitempty"`
BeforeUpdateIn string `json:"before:update-in,omitempty"`
AfterUpdateIn string `json:"after:update-in,omitempty"`
BeforeUpdateWhere string `json:"before:update-where,omitempty"`
AfterUpdateWhere string `json:"after:update-where,omitempty"`
BeforeQuicksave string `json:"before:quicksave,omitempty"`
AfterQuicksave string `json:"after:quicksave,omitempty"`
BeforeSelect string `json:"before:select,omitempty"`
AfterSelect string `json:"after:select,omitempty"`
}

6
table/validate.go Normal file
View file

@ -0,0 +1,6 @@
package table
// Validate 校验表格格式
// func (table Table) Validate() error {
// return nil
// }

View file

@ -0,0 +1,13 @@
{
"label": "After:Search",
"version": "1.0.0",
"description": "After:Search",
"nodes": [
{
"name": "结果",
"process": "xiang.helper.MapSet",
"args": ["{{$in.0}}", "after", 100]
}
],
"output": "{{$res.结果}}"
}

View file

@ -0,0 +1,7 @@
{
"label": "Before:Search",
"version": "1.0.0",
"description": "Before:Search",
"nodes": [],
"output": [{ "wheres": [{ "column": "status", "value": "enabled" }] }, 1, 2]
}

View file

@ -0,0 +1,39 @@
{
"name": "云服务库",
"version": "1.0.0",
"decription": "云服务库",
"bind": {
"model": "service",
"withs": {}
},
"hooks": {
"before:search": "flows.hooks.before_search",
"after:search": "flows.hooks.after_search"
},
"apis": {
"search": {
"process": "models.service.Paginate",
"guard": "-",
"default": [null, null, 15]
}
},
"columns": {},
"filters": {},
"list": {
"primary": "id",
"layout": {
"columns": [{ "name": "ID", "width": 6 }],
"filters": []
},
"actions": {}
},
"edit": {
"primary": "id",
"layout": {
"fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
},
"actions": { "cancel": {} }
},
"insert": {},
"view": {}
}

View file

@ -3,6 +3,8 @@ package xlog
import (
"fmt"
"log"
jsoniter "github.com/json-iterator/go"
)
// XLog 日志接口
@ -25,7 +27,11 @@ func Printf(format string, v ...interface{}) {
// Println calls Output to print to the standard logger.
// Arguments are handled in the manner of fmt.Println.
func Println(v ...interface{}) {
log.Output(2, fmt.Sprintln(v...))
content, err := jsoniter.Marshal(v)
if err != nil {
log.Output(2, fmt.Sprintln(v...))
}
log.Output(2, string(content))
}
// Fatalf is equivalent to Printf() followed by a call to os.Exit(1).