From 2bbcb25be6a955d1a373ea8040fd36c6d68017ee Mon Sep 17 00:00:00 2001 From: glennliao Date: Wed, 12 Jul 2023 13:51:06 +0800 Subject: [PATCH] =?UTF-8?q?##=200.2.0-beta12=20->=20=E8=B0=83=E6=95=B4acti?= =?UTF-8?q?on.Hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action/action.go | 74 ++++++------- action/hook.go | 162 +++++++++++++++++++++-------- action/node.go | 18 +--- apijson.go | 14 +++ config/access.go | 9 +- config/action_config.go | 37 ++++++- config/config.go | 33 +++--- config/functions.go | 28 +++-- config/query_config.go | 6 ++ config/rowkeygen.go | 47 +++++---- drivers/goframe/all.go | 8 +- drivers/goframe/executor/action.go | 9 +- drivers/goframe/executor/query.go | 17 ++- drivers/goframe/web/gf.go | 32 +++--- model/model.go | 9 ++ model/var.go | 7 ++ query/node_func.go | 2 +- query/node_query.go | 9 +- test/z_app_test.go | 6 +- test/z_main_test.go | 5 + 20 files changed, 361 insertions(+), 171 deletions(-) create mode 100644 model/var.go diff --git a/action/action.go b/action/action.go index 468f9df..83f474f 100755 --- a/action/action.go +++ b/action/action.go @@ -42,6 +42,8 @@ type Action struct { NewQuery func(ctx context.Context, req model.Map) *query.Query NewAction func(ctx context.Context, method string, req model.Map) *Action + + HooksMap map[string][]*Hook } func New(ctx context.Context, actionConfig *config.ActionConfig, method string, req model.Map) *Action { @@ -127,58 +129,56 @@ func (a *Action) Result() (model.Map, error) { for _, k := range a.tagRequest.ExecQueue { node := a.children[k] - err = EmitHook(a.ctx, BeforeNodeExec, node, a.method) - if err != nil { - return nil, err - } - } - - for _, k := range a.tagRequest.ExecQueue { - node := a.children[k] - err = node.reqUpdate() - if err != nil { - return nil, err + actionHookReq := &HookReq{ + Node: node, + Method: a.method, + ctx: a.ctx, + nextIdx: -1, + isInTransaction: false, + hooks: getHooksByAccessName(a.HooksMap, k), } - } - - transactionHandler := noTransactionHandler - if a.tagRequest.Transaction != nil && *a.tagRequest.Transaction == true { - h := GetTransactionHandler(a.ctx, a) - if h == nil { - err = consts.NewSysErr("transaction handler is nil") - return nil, err - } + actionHookReq.handler = func(ctx context.Context, n *Node, method string) error { + transactionHandler := noTransactionHandler - transactionHandler = h + if a.tagRequest.Transaction != nil && *a.tagRequest.Transaction == true { + h := GetTransactionHandler(a.ctx, a) + if h == nil { + err = consts.NewSysErr("transaction handler is nil") + return err + } - } + transactionHandler = h - err = transactionHandler(a.ctx, func(ctx context.Context) error { - for _, k := range a.tagRequest.ExecQueue { - node := a.children[k] - ret[k], err = node.execute(ctx, a.method) - if err != nil { - return err } + + err = transactionHandler(a.ctx, func(ctx context.Context) error { + for _, k := range a.tagRequest.ExecQueue { + node := a.children[k] + ret[k], err = node.execute(ctx, a.method) + if err != nil { + return err + } + } + return nil + }) + + return err } - return nil - }) - if err != nil { - return nil, err - } + err = node.reqUpdate() + if err != nil { + return nil, err + } - for _, k := range a.tagRequest.ExecQueue { - node := a.children[k] - err = EmitHook(a.ctx, AfterNodeExec, node, a.method) + err := actionHookReq.Next() if err != nil { return nil, err } } - return ret, err + return ret, nil } func checkTag(req model.Map, method string, requestCfg *config.ActionConfig) (*config.RequestConfig, error) { diff --git a/action/hook.go b/action/hook.go index c443654..04bbd39 100755 --- a/action/hook.go +++ b/action/hook.go @@ -1,56 +1,136 @@ package action -import "context" - -const ( - BeforeNodeExec = iota - AfterNodeExec - BeforeExecutorDo - AfterExecutorDo +import ( + "context" + "net/http" ) -type Hook struct { - For []string // - // Exec 事务外 - BeforeNodeExec func(ctx context.Context, n *Node, method string) error - AfterNodeExec func(ctx context.Context, n *Node, method string) error - - // Do 事务内 - BeforeExecutorDo func(ctx context.Context, n *Node, method string) error - AfterExecutorDo func(ctx context.Context, n *Node, method string) error +// const ( +// BeforeNodeExec = iota +// AfterNodeExec +// BeforeExecutorDo +// AfterExecutorDo +// ) + +type HookReq struct { + Node *Node + Method string + ctx context.Context + hooks []*Hook + nextIdx int + isInTransaction bool + handler finishHandler } -var hooksMap = map[string][]Hook{} +func (r *HookReq) IsPost() bool { + return r.Method == http.MethodPost +} -func RegHook(h Hook) { - for _, item := range h.For { - hooksMap[item] = append(hooksMap[item], h) - } +func (r *HookReq) IsPut() bool { + return r.Method == http.MethodPut +} + +func (r *HookReq) IsDelete() bool { + return r.Method == http.MethodDelete } -func EmitHook(ctx context.Context, hookAt int, node *Node, method string) error { - - hooks := append(hooksMap["*"], hooksMap[node.Key]...) - for _, hook := range hooks { - - var handler func(ctx context.Context, n *Node, method string) error - switch hookAt { - case BeforeNodeExec: - handler = hook.BeforeNodeExec - case AfterNodeExec: - handler = hook.AfterNodeExec - case BeforeExecutorDo: - handler = hook.BeforeExecutorDo - case AfterExecutorDo: - handler = hook.AfterExecutorDo +func (r *HookReq) Next() error { + + for { + + var h *Hook + + for r.nextIdx < len(r.hooks) && h == nil { + + if r.nextIdx+1 >= len(r.hooks) { + if r.isInTransaction { + // finish all + return r.handler(r.ctx, r.Node, r.Method) + } else { + r.nextIdx = -1 + r.isInTransaction = true + } + } + + r.nextIdx++ + + _h := r.hooks[r.nextIdx] + + if r.isInTransaction { + if _h.HandlerInTransaction == nil { + continue + } + h = _h + } else { + if _h.Handler == nil { + continue + } + h = _h + } + } - if handler != nil { - err := handler(ctx, node, method) - if err != nil { - return err + if r.nextIdx < len(r.hooks) { + if r.isInTransaction { + return h.HandlerInTransaction(r.ctx, r) } + + return h.Handler(r.ctx, r) } } - return nil + } + +type Hook struct { + For []string + // 事务外 , 可执行参数校验,io等耗时操作 + Handler func(ctx context.Context, req *HookReq) error + // 事务内,尽量少执行耗时操作 (无论request配置中是否开启事务, 都会先执行handler 然后 在范围内执行HandlerInTransaction) + HandlerInTransaction func(ctx context.Context, req *HookReq) error +} + +type finishHandler func(ctx context.Context, n *Node, method string) error + +func getHooksByAccessName(hooksMap map[string][]*Hook, accessName string) []*Hook { + hooks := append(hooksMap["*"], hooksMap[accessName]...) + return hooks +} + +// +// type Hook2 struct { +// For []string // +// // Exec 事务外 +// BeforeNodeExec func(ctx context.Context, n *Node, method string) error +// AfterNodeExec func(ctx context.Context, n *Node, method string) error +// +// // Do 事务内 +// BeforeExecutorDo func(ctx context.Context, n *Node, method string) error +// AfterExecutorDo func(ctx context.Context, n *Node, method string) error +// } +// +// func emitHook(ctx context.Context, hooksMap map[string][]Hook, hookAt int, node *Node, method string) error { +// +// hooks := append(hooksMap["*"], hooksMap[node.Key]...) +// for _, hook := range hooks { +// +// var handler func(ctx context.Context, n *Node, method string) error +// switch hookAt { +// case BeforeNodeExec: +// handler = hook.BeforeNodeExec +// case AfterNodeExec: +// handler = hook.AfterNodeExec +// case BeforeExecutorDo: +// handler = hook.BeforeExecutorDo +// case AfterExecutorDo: +// handler = hook.AfterExecutorDo +// } +// +// if handler != nil { +// err := handler(ctx, node, method) +// if err != nil { +// return err +// } +// } +// } +// return nil +// } diff --git a/action/node.go b/action/node.go index 60348c1..4eadbef 100755 --- a/action/node.go +++ b/action/node.go @@ -264,11 +264,11 @@ func (n *Node) reqUpdate() error { // call functions { - queryConfig := n.Action.ActionConfig + actionConfig := n.Action.ActionConfig functionName, paramKeys := util.ParseFunctionsStr(updateVal.(string)) - _func := queryConfig.Func(functionName) + _func := actionConfig.Func(functionName) param := model.Map{} for paramI, item := range _func.ParamList { @@ -279,7 +279,7 @@ func (n *Node) reqUpdate() error { } } - val, err := _func.Handler(n.ctx, param) + val, err := actionConfig.CallFunc(n.ctx, functionName, param) if err != nil { return err } @@ -327,11 +327,6 @@ func (n *Node) reqUpdateBeforeDo() error { func (n *Node) do(ctx context.Context, method string) (ret model.Map, err error) { - err = EmitHook(ctx, BeforeExecutorDo, n, method) - if err != nil { - return nil, err - } - var rowKeyVal model.Map var rowKey string @@ -346,7 +341,7 @@ func (n *Node) do(ctx context.Context, method string) (ret model.Map, err error) if access.RowKeyGen != "" { for i, _ := range n.Data { - rowKeyVal, err = n.Action.ActionConfig.RowKeyGen(ctx, access.RowKeyGen, n.Key, n.Data[i]) + rowKeyVal, err = n.Action.ActionConfig.RowKeyGen(ctx, access.RowKeyGen, n.Key, n.tableName, n.Data[i]) if err != nil { return nil, err } @@ -406,11 +401,6 @@ func (n *Node) do(ctx context.Context, method string) (ret model.Map, err error) n.Ret = ret - err = EmitHook(ctx, AfterExecutorDo, n, method) - if err != nil { - return nil, err - } - return } diff --git a/apijson.go b/apijson.go index 308037a..1aa6216 100755 --- a/apijson.go +++ b/apijson.go @@ -17,6 +17,9 @@ type ApiJson struct { config *config.Config Debug bool // 是否开启debug模式, 显示每步骤 ctx context.Context + + actionHooks []action.Hook + actionHookMap map[string][]*action.Hook } var DefaultApiJson = New() @@ -76,5 +79,16 @@ func (a *ApiJson) NewAction(ctx context.Context, method string, req model.Map) * act.NewQuery = a.NewQuery + act.HooksMap = a.actionHookMap + return act } + +func (a *ApiJson) RegActionHook(hook action.Hook) { + if a.actionHookMap == nil { + a.actionHookMap = make(map[string][]*action.Hook) + } + for _, item := range hook.For { + a.actionHookMap[item] = append(a.actionHookMap[item], &hook) + } +} diff --git a/config/access.go b/config/access.go index af5cb37..efa8938 100755 --- a/config/access.go +++ b/config/access.go @@ -2,6 +2,7 @@ package config import ( "context" + "github.com/glennliao/apijson-go/consts" "github.com/gogf/gf/v2/frame/g" "github.com/samber/lo" @@ -11,19 +12,19 @@ type ConditionReq struct { AccessName string // _access 中的alias TableAccessRoleList []string Method string - NodeReq g.Map //节点的请求数据 + NodeReq g.Map // 节点的请求数据 NodeRole string // 节点的角色 } type ConditionRet struct { condition map[string]any - rawCondition map[string]any + rawCondition map[string][]any } func NewConditionRet() *ConditionRet { c := ConditionRet{ condition: map[string]any{}, - rawCondition: map[string]any{}, + rawCondition: map[string][]any{}, } return &c } @@ -32,7 +33,7 @@ func (c *ConditionRet) Add(k string, v any) { c.condition[k] = v } -func (c *ConditionRet) AddRaw(k string, v any) { +func (c *ConditionRet) AddRaw(k string, v ...any) { c.rawCondition[k] = v } diff --git a/config/action_config.go b/config/action_config.go index 82d6c80..e04db1d 100755 --- a/config/action_config.go +++ b/config/action_config.go @@ -2,15 +2,19 @@ package config import ( "context" + "strings" + "github.com/glennliao/apijson-go/consts" "github.com/glennliao/apijson-go/model" + "github.com/glennliao/apijson-go/util" + "github.com/gogf/gf/v2/container/gvar" ) type ActionConfig struct { requestConfig *RequestConfigs access *Access functions *functions - rowKeyGenFuncMap map[string]RowKeyGenFuncHandler + rowKeyGenFuncMap map[string]RowKeyGenerator defaultRoleFunc DefaultRole } @@ -29,6 +33,9 @@ func (c *ActionConfig) GetAccessConfig(key string, noVerify bool) (*AccessConfig func (c *ActionConfig) Func(name string) *Func { return c.functions.funcMap[name] } +func (c *ActionConfig) CallFunc(ctx context.Context, name string, param model.Map) (res any, err error) { + return c.functions.Call(ctx, name, param) +} func (c *ActionConfig) GetRequest(tag string, method string, version string) (*RequestConfig, error) { return c.requestConfig.GetRequest(tag, method, version) @@ -38,16 +45,38 @@ func (c *ActionConfig) ConditionFunc(ctx context.Context, req ConditionReq, cond return c.access.ConditionFunc(ctx, req, condition) } -func (c *ActionConfig) RowKeyGen(ctx context.Context, genFuncName string, accessName string, data model.Map) (model.Map, error) { +func (c *ActionConfig) RowKeyGen(ctx context.Context, genFuncName string, accessName string, tableName string, data model.Map) (model.Map, error) { + + var paramKeys []string + + if strings.Contains(genFuncName, "(") { + genFuncName, paramKeys = util.ParseFunctionsStr(genFuncName) + } + if f, exists := c.rowKeyGenFuncMap[genFuncName]; exists { + req := &RowKeyGenReq{ AccessName: accessName, + TableName: tableName, Data: data, } + + if len(paramKeys) > 0 { + var param = model.FuncParam{} + for i, item := range f.ParamList { + if len(paramKeys) >= i { + param[item.Name] = gvar.New(paramKeys[i]) + } else { + param[item.Name] = gvar.New(item.Default) + } + } + req.GenParam = param + } + ret := NewRowKeyGenRet() - err := f(ctx, req, ret) + err := f.Handler(ctx, req, ret) return ret.data, err } - return nil, nil + return nil, consts.NewSysErr("rowKey RowKeyGenerator not found:" + genFuncName) } diff --git a/config/config.go b/config/config.go index 3b8f098..f8722eb 100755 --- a/config/config.go +++ b/config/config.go @@ -1,6 +1,8 @@ package config -import "context" +import ( + "context" +) type AccessListProvider func(ctx context.Context) []AccessConfig @@ -34,7 +36,7 @@ type Config struct { MaxTreeWidth int MaxTreeDeep int - rowKeyGenFuncMap map[string]RowKeyGenFuncHandler + rowKeyGenFuncMap map[string]RowKeyGenerator // dbFieldStyle 数据库字段命名风格 请求传递到数据库中 DbFieldStyle FieldStyle @@ -56,24 +58,24 @@ type Config struct { } func New() *Config { - a := &Config{} - a.Access = NewAccess() - a.AccessListProvider = "db" - a.RequestListProvider = "db" - a.DbMetaProvider = "db" + c := &Config{} + c.Access = NewAccess() + c.AccessListProvider = "db" + c.RequestListProvider = "db" + c.DbMetaProvider = "db" - a.MaxTreeWidth = 5 - a.MaxTreeDeep = 5 + c.MaxTreeWidth = 5 + c.MaxTreeDeep = 5 - a.rowKeyGenFuncMap = make(map[string]RowKeyGenFuncHandler) + c.rowKeyGenFuncMap = make(map[string]RowKeyGenerator) - a.DbFieldStyle = CaseSnake - a.JsonFieldStyle = CaseCamel + c.DbFieldStyle = CaseSnake + c.JsonFieldStyle = CaseCamel - a.Functions = &functions{} - a.Functions.funcMap = make(map[string]*Func) + c.Functions = &functions{} + c.Functions.funcMap = make(map[string]*Func) - return a + return c } func (c *Config) ReLoad() { @@ -140,6 +142,7 @@ func (c *Config) ReLoad() { rowKeyGenFuncMap: c.rowKeyGenFuncMap, defaultRoleFunc: c.Access.DefaultRoleFunc, } + } func (c *Config) QueryConfig() *QueryConfig { diff --git a/config/functions.go b/config/functions.go index 794a828..5beb788 100755 --- a/config/functions.go +++ b/config/functions.go @@ -5,19 +5,27 @@ import ( "fmt" "github.com/glennliao/apijson-go/model" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/frame/g" ) +const ( + ParamTypeInt = "int" + ParamTypeString = "string" +) + type ParamItem struct { - Type string - Name string - Desc string + Type string + Name string + Desc string + Default any } type Func struct { - ParamList []ParamItem - Batch bool // 是否为批量处理, 例如在获取列表后一次性将id传入, 然后按照传入的参数数组返回结果数组 - Handler func(ctx context.Context, param model.Map) (res any, err error) + Desc string // 描述 + ParamList []ParamItem // 参数列表 + Batch bool // 是否为批量处理, 例如在获取列表后一次性将id传入, 然后按照传入的参数数组返回结果数组 + Handler func(ctx context.Context, param model.FuncParam) (res any, err error) } type functions struct { @@ -32,7 +40,13 @@ func (f *functions) Bind(name string, _func Func) { } func (f *functions) Call(ctx context.Context, name string, param g.Map) (any, error) { - return f.funcMap[name].Handler(ctx, param) + + params := map[string]model.Var{} + for k, v := range param { + params[k] = gvar.New(v) + } + + return f.funcMap[name].Handler(ctx, params) } // functions 提供的功能 diff --git a/config/query_config.go b/config/query_config.go index 1509182..e5798c0 100755 --- a/config/query_config.go +++ b/config/query_config.go @@ -1,8 +1,10 @@ package config import ( + "context" "net/http" + "github.com/glennliao/apijson-go/model" "github.com/samber/lo" ) @@ -30,6 +32,10 @@ func (c *QueryConfig) Func(name string) *Func { return c.functions.funcMap[name] } +func (c *QueryConfig) CallFunc(ctx context.Context, name string, param model.Map) (res any, err error) { + return c.functions.Call(ctx, name, param) +} + func (c *QueryConfig) MaxTreeDeep() int { return c.maxTreeDeep } diff --git a/config/rowkeygen.go b/config/rowkeygen.go index 7619b47..4bfdd74 100755 --- a/config/rowkeygen.go +++ b/config/rowkeygen.go @@ -2,6 +2,7 @@ package config import ( "context" + "github.com/glennliao/apijson-go/consts" "github.com/glennliao/apijson-go/model" "github.com/samber/lo" @@ -9,7 +10,19 @@ import ( type RowKeyGenReq struct { AccessName string - Data model.Map + TableName string + + GenParam model.FuncParam + + Data model.Map +} + +type RowKeyGenFuncHandler func(ctx context.Context, req *RowKeyGenReq, ret *RowKeyGenRet) error + +type RowKeyGenerator struct { + Name string + ParamList []ParamItem + Handler RowKeyGenFuncHandler } type RowKeyGenRet struct { @@ -29,24 +42,22 @@ func (r *RowKeyGenRet) RowKeys(d model.Map) { } } -type RowKeyGenFuncHandler func(ctx context.Context, req *RowKeyGenReq, ret *RowKeyGenRet) error - -func (c *Config) RowKeyGen(ctx context.Context, genFuncName string, accessName string, data model.Map) (model.Map, error) { - if f, exists := c.rowKeyGenFuncMap[genFuncName]; exists { - req := &RowKeyGenReq{ - AccessName: accessName, - Data: data, - } - ret := NewRowKeyGenRet() - err := f(ctx, req, ret) - return ret.data, err - } - - return nil, nil -} +// func (c *Config) RowKeyGen(ctx context.Context, genFuncName string, accessName string, data model.Map) (model.Map, error) { +// if f, exists := c.rowKeyGenFuncMap[genFuncName]; exists { +// req := &RowKeyGenReq{ +// AccessName: accessName, +// Data: data, +// } +// ret := NewRowKeyGenRet() +// err := f.Handler(ctx, req, ret) +// return ret.data, err +// } +// +// return nil, nil +// } -func (c *Config) RowKeyGenFunc(name string, f RowKeyGenFuncHandler) { - c.rowKeyGenFuncMap[name] = f +func (c *Config) RowKeyGenFunc(f RowKeyGenerator) { + c.rowKeyGenFuncMap[f.Name] = f } func (c *Config) RowKeyGenList() []string { diff --git a/drivers/goframe/all.go b/drivers/goframe/all.go index 6a6bf95..4018af1 100644 --- a/drivers/goframe/all.go +++ b/drivers/goframe/all.go @@ -20,11 +20,15 @@ func init() { config.RegDbMetaProvider(gfConfig.ProviderName, gfConfig.DbMetaProvider) query.RegExecutor("default", gfExecutor.New) - action.RegExecutor("default", &gfExecutor.ActionExecutor{}) + + action.RegExecutor("default", &gfExecutor.ActionExecutor{ + DbResolver: func(ctx context.Context) gdb.DB { + return g.DB() + }, + }) action.RegTransactionResolver(func(ctx context.Context, req *action.Action) action.TransactionHandler { return func(ctx context.Context, action func(ctx context.Context) error) error { - // TODO g.DB() -> resolver return g.DB().Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { return action(ctx) }) diff --git a/drivers/goframe/executor/action.go b/drivers/goframe/executor/action.go index f3b8b09..328c299 100755 --- a/drivers/goframe/executor/action.go +++ b/drivers/goframe/executor/action.go @@ -10,12 +10,11 @@ import ( "github.com/glennliao/apijson-go/model" "github.com/glennliao/apijson-go/util" "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) type ActionExecutor struct { - DbName string + DbResolver DbResolver } func (a *ActionExecutor) Do(ctx context.Context, req action.ActionExecutorReq) (ret model.Map, err error) { @@ -56,7 +55,7 @@ func (a *ActionExecutor) Do(ctx context.Context, req action.ActionExecutorReq) ( } func (a *ActionExecutor) Insert(ctx context.Context, table string, data []model.Map) (ret model.Map, err error) { - result, err := g.DB(a.DbName).Insert(ctx, table, data) + result, err := a.DbResolver(ctx).Insert(ctx, table, data) if err != nil { return nil, err } @@ -77,7 +76,7 @@ func (a *ActionExecutor) Insert(ctx context.Context, table string, data []model. } func (a *ActionExecutor) Update(ctx context.Context, table string, data model.Map, where model.Map) (ret model.Map, err error) { - m := g.DB(a.DbName).Model(table).Ctx(ctx) + m := a.DbResolver(ctx).Model(table).Ctx(ctx) for k, v := range where { if strings.HasSuffix(k, consts.OpIn) { @@ -145,7 +144,7 @@ func (a *ActionExecutor) Delete(ctx context.Context, table string, where model.M return nil, consts.NewValidReqErr("where的值不能为空") } - m := g.DB(a.DbName).Model(table).Ctx(ctx) + m := a.DbResolver(ctx).Model(table).Ctx(ctx) for k, v := range where { diff --git a/drivers/goframe/executor/query.go b/drivers/goframe/executor/query.go index 1787d2a..6eb770f 100755 --- a/drivers/goframe/executor/query.go +++ b/drivers/goframe/executor/query.go @@ -16,6 +16,8 @@ import ( "github.com/samber/lo" ) +type DbResolver func(ctx context.Context) gdb.DB + type SqlExecutor struct { ctx context.Context @@ -23,7 +25,7 @@ type SqlExecutor struct { // 保存where条件 [ ["user_id",">", 123], ["user_id","<=",345] ] Where [][]any - accessCondition model.Map + accessCondition map[string][]any Columns []string Order string @@ -33,6 +35,8 @@ type SqlExecutor struct { WithEmptyResult bool config *config.ExecutorConfig + + DbResolver DbResolver } func New(ctx context.Context, config *config.ExecutorConfig) (query.QueryExecutor, error) { @@ -45,6 +49,9 @@ func New(ctx context.Context, config *config.ExecutorConfig) (query.QueryExecuto Group: "", WithEmptyResult: false, config: config, + DbResolver: func(ctx context.Context) gdb.DB { + return g.DB() + }, }, nil } @@ -64,7 +71,7 @@ func (e *SqlExecutor) ParseCondition(conditions model.MapStrAny, accessVerify bo e.Where = append(e.Where, []any{key[0 : len(key)-1], consts.SqlRegexp, gconv.String(condition)}) case key == consts.Raw && !accessVerify: - e.accessCondition = condition.(map[string]any) + e.accessCondition = condition.(map[string][]any) default: e.Where = append(e.Where, []any{key, consts.SqlEqual, condition}) @@ -203,7 +210,7 @@ func (e *SqlExecutor) ParseCtrl(ctrl model.Map) error { func (e *SqlExecutor) build() *gdb.Model { tableName := e.config.TableName() - m := g.DB().Model(tableName).Ctx(e.ctx) + m := e.DbResolver(e.ctx).Model(tableName).Ctx(e.ctx) if e.Order != "" { m = m.Order(e.Order) @@ -259,7 +266,9 @@ func (e *SqlExecutor) build() *gdb.Model { m = m.Where(whereBuild) if e.accessCondition != nil { - m = m.Where(e.accessCondition) + for k, v := range e.accessCondition { + m = m.Where(k, v...) + } } if e.Group != "" { diff --git a/drivers/goframe/web/gf.go b/drivers/goframe/web/gf.go index e318c26..95c021c 100755 --- a/drivers/goframe/web/gf.go +++ b/drivers/goframe/web/gf.go @@ -12,7 +12,6 @@ import ( "github.com/glennliao/apijson-go/consts" "github.com/glennliao/apijson-go/model" "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" @@ -160,27 +159,32 @@ func CommonResponse(handler func(ctx context.Context, req model.Map) (res model. code = 500 msg = "系统异常" } - } + } else { - if e, ok := err.(*gerror.Error); ok { - if e.Code() == gcode.CodeNil { - code = 400 - msg = e.Error() + if _, ok := err.(*gerror.Error); ok { + // if e.Code() == gcode.CodeNil { + // code = 400 + // msg = e.Error() + // } else { + // code = 500 + // msg = "系统异常" + // } + code = 500 + msg = "系统异常" } else { code = 500 msg = "系统异常" } - } else { - code = 500 - msg = "系统异常" } if code >= 500 { - if e, ok := err.(*gerror.Error); ok { - g.Log().Stack(false).Error(req.Context(), err, e.Stack()) - } else { - g.Log().Stack(false).Error(req.Context(), err) - } + g.Log().Stack(false).Errorf(req.Context(), "%+v", err) + + // if e, ok := err.(*gerror.Error); ok { + // g.Log().Stack(false).Error(req.Context(), err, e.Stack()) + // } else { + // g.Log().Stack(false).Error(req.Context(), err) + // } } } diff --git a/model/model.go b/model/model.go index 7c44853..f6aab7c 100755 --- a/model/model.go +++ b/model/model.go @@ -1,5 +1,14 @@ package model +import ( + "github.com/gogf/gf/v2/util/gconv" +) + type Map map[string]any type MapStrStr map[string]string type MapStrAny map[string]any +type FuncParam map[string]Var + +func (p *FuncParam) Scan(pointer interface{}, mapping ...map[string]string) error { + return gconv.Scan(p, pointer, mapping...) +} diff --git a/model/var.go b/model/var.go new file mode 100644 index 0000000..c9238ba --- /dev/null +++ b/model/var.go @@ -0,0 +1,7 @@ +package model + +type Var interface { + String() string + Int() int + Scan(pointer interface{}, mapping ...map[string]string) error +} diff --git a/query/node_func.go b/query/node_func.go index 7989688..d065d1c 100755 --- a/query/node_func.go +++ b/query/node_func.go @@ -81,7 +81,7 @@ func (h *funcNode) result() { } } - n.ret, n.err = _func.Handler(n.ctx, param) + n.ret, n.err = queryConfig.CallFunc(n.ctx, functionName, param) } func (h *funcNode) nodeType() int { diff --git a/query/node_query.go b/query/node_query.go index 749b54a..768e663 100755 --- a/query/node_query.go +++ b/query/node_query.go @@ -263,6 +263,11 @@ func (q *queryNode) fetch() { functionName, paramKeys := util.ParseFunctionsStr(v.(string)) _func := queryConfig.Func(functionName) + if _func == nil { + n.err = consts.NewValidReqErr("func not exists:" + functionName) + return + } + if n.isList { for i, item := range n.ret.([]model.Map) { @@ -276,7 +281,7 @@ func (q *queryNode) fetch() { } } - val, err := _func.Handler(n.ctx, param) + val, err := queryConfig.CallFunc(n.ctx, functionName, param) if err != nil { n.err = err return @@ -293,7 +298,7 @@ func (q *queryNode) fetch() { } } - val, err := _func.Handler(n.ctx, param) + val, err := queryConfig.CallFunc(n.ctx, functionName, param) if err != nil { n.err = err return diff --git a/test/z_app_test.go b/test/z_app_test.go index 706f6fd..6401c16 100755 --- a/test/z_app_test.go +++ b/test/z_app_test.go @@ -70,7 +70,7 @@ func App(ctx context.Context, a *apijson.ApiJson) { } a.Config().Functions.Bind("test", config.Func{ - Handler: func(ctx context.Context, param model.Map) (res any, err error) { + Handler: func(ctx context.Context, param model.FuncParam) (res any, err error) { return "你好", nil }, }) @@ -86,8 +86,8 @@ func App(ctx context.Context, a *apijson.ApiJson) { Type: "string", }, }, - Handler: func(ctx context.Context, param model.Map) (res any, err error) { - return param["a"].(string) + param["b"].(string), nil + Handler: func(ctx context.Context, param model.FuncParam) (res any, err error) { + return param["a"].String() + param["b"].String(), nil }, }) diff --git a/test/z_main_test.go b/test/z_main_test.go index be7c5f4..3279493 100755 --- a/test/z_main_test.go +++ b/test/z_main_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/glennliao/apijson-go" + "github.com/glennliao/apijson-go/action" _ "github.com/glennliao/apijson-go/drivers/goframe" "github.com/glennliao/apijson-go/drivers/goframe/web" "github.com/glennliao/apijson-go/model" @@ -18,6 +19,10 @@ var a *apijson.ApiJson func init() { a = apijson.Load(App) + + a.RegActionHook(action.Hook{ + For: []string{"asd"}, + }) } // notice: import section