Skip to content

Commit

Permalink
## 0.2.0-beta9 增加错误返回而不是直接panic+action的事务开关
Browse files Browse the repository at this point in the history
  • Loading branch information
glennliao committed Jul 3, 2023
1 parent 8476aff commit decda6d
Show file tree
Hide file tree
Showing 23 changed files with 422 additions and 228 deletions.
35 changes: 26 additions & 9 deletions action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import (
"github.com/glennliao/apijson-go/config"
"github.com/glennliao/apijson-go/consts"
"github.com/glennliao/apijson-go/model"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/glennliao/apijson-go/query"
"github.com/glennliao/apijson-go/util"
"github.com/gogf/gf/v2/util/gconv"
)

Expand Down Expand Up @@ -40,6 +39,9 @@ type Action struct {
JsonFieldStyle config.FieldStyle

ActionConfig *config.ActionConfig

NewQuery func(ctx context.Context, req model.Map) *query.Query
NewAction func(ctx context.Context, method string, req model.Map) *Action
}

func New(ctx context.Context, actionConfig *config.ActionConfig, method string, req model.Map) *Action {
Expand All @@ -50,7 +52,7 @@ func New(ctx context.Context, actionConfig *config.ActionConfig, method string,
}

delete(req, consts.Tag)
delete(req, "version")
delete(req, consts.Version)

a := &Action{
ctx: ctx,
Expand All @@ -72,12 +74,13 @@ func (a *Action) parse() error {

structuresKey := key
if strings.HasSuffix(key, consts.ListKeySuffix) {
structuresKey = structuresKey[0 : len(structuresKey)-2]
structuresKey = util.RemoveSuffix(key, consts.ListKeySuffix)
}

structure, ok := structures[key]
if !ok {
if structure, ok = structures[structuresKey]; !ok { // User[]可读取User或者User[]
return gerror.New("structure错误: 400, 缺少" + key)
return consts.NewStructureKeyNoFoundErr(key)
}
}

Expand Down Expand Up @@ -133,7 +136,21 @@ func (a *Action) Result() (model.Map, error) {
}
}

err = g.DB().Transaction(a.ctx, func(ctx context.Context, tx gdb.TX) error {
transactionHandler := noTransactionHandler

if *a.tagRequest.Transaction == true {
transactionResolver = GetTransactionHandler
h := transactionResolver(a.ctx, a)
if h != nil {
err = consts.NewSysErr("transaction handler is nil")
return nil, 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)
Expand Down Expand Up @@ -162,11 +179,11 @@ func (a *Action) Result() (model.Map, error) {
func checkTag(req model.Map, method string, requestCfg *config.ActionConfig) (*config.RequestConfig, error) {
_tag, ok := req[consts.Tag]
if !ok {
return nil, gerror.New("tag 缺失")
return nil, consts.ErrNoTag
}

tag := gconv.String(_tag)
version := req["version"]
version := req[consts.Version]

request, err := requestCfg.GetRequest(tag, method, gconv.String(version))
if err != nil {
Expand Down
65 changes: 65 additions & 0 deletions action/executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package action

import (
"context"

"github.com/glennliao/apijson-go/config"
"github.com/glennliao/apijson-go/consts"
"github.com/glennliao/apijson-go/model"
"github.com/glennliao/apijson-go/query"
"github.com/samber/lo"
)

type ActionExecutorReq struct {
Method string
Table string
Data []model.Map
Where []model.Map
Access *config.AccessConfig
Config *config.ActionConfig
NewQuery func(ctx context.Context, req model.Map) *query.Query
}

var actionExecutorMap = map[string]ActionExecutor{}

func RegExecutor(name string, e ActionExecutor) {
actionExecutorMap[name] = e
}

func GetActionExecutor(name string) (ActionExecutor, error) {
if name == "" {
name = "default"
}
if v, exists := actionExecutorMap[name]; exists {
return v, nil
}
return nil, consts.NewSysErr("action executor not found: " + name)
}

func ActionExecutorList() []string {
return lo.Keys(actionExecutorMap)
}

type ActionExecutor interface {
Do(ctx context.Context, req ActionExecutorReq) (ret model.Map, err error)
}

// TransactionHandler 事务处理函数

type TransactionHandler func(ctx context.Context, action func(ctx context.Context) error) error

type TransactionResolver func(ctx context.Context, req *Action) TransactionHandler

var noTransactionHandler = func(ctx context.Context, action func(ctx context.Context) error) error {
return action(ctx)
}

var transactionResolver TransactionResolver

func RegTransactionResolver(r TransactionResolver) {
transactionResolver = r
}

func GetTransactionHandler(ctx context.Context, req *Action) TransactionHandler {
return transactionResolver(ctx, req)
}
47 changes: 23 additions & 24 deletions action/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ import (
"strings"

"github.com/glennliao/apijson-go/config"
"github.com/glennliao/apijson-go/config/executor"
"github.com/glennliao/apijson-go/consts"
"github.com/glennliao/apijson-go/model"
"github.com/glennliao/apijson-go/util"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/samber/lo"
)

Expand Down Expand Up @@ -45,7 +43,6 @@ func newNode(key string, req []model.Map, structure *config.Structure, executor
n.Data = []model.Map{}
n.Where = []model.Map{}

// ?
for _ = range n.req {

n.Data = append(n.Data, model.Map{})
Expand All @@ -54,7 +51,7 @@ func newNode(key string, req []model.Map, structure *config.Structure, executor
}

if strings.HasSuffix(key, consts.ListKeySuffix) {
n.Key = key[0 : len(key)-len(consts.ListKeySuffix)]
n.Key = util.RemoveSuffix(key, consts.ListKeySuffix)
n.IsList = true
}

Expand All @@ -65,10 +62,6 @@ func newNode(key string, req []model.Map, structure *config.Structure, executor
func (n *Node) parseReq(method string) {

for i, item := range n.req {

// n.Data = append(n.Data, model.Map{})
// n.Where = append(n.Where, model.Map{})

for key, val := range item {

if key == consts.Role {
Expand All @@ -84,7 +77,7 @@ func (n *Node) parseReq(method string) {
case http.MethodDelete:
n.Where[i][key] = val
case http.MethodPut:
if key == n.RowKey || key == n.RowKey+"{}" {
if key == n.RowKey || key == n.RowKey+consts.OpIn {
n.Where[i][key] = val
} else {
n.Data[i][key] = val
Expand All @@ -100,7 +93,7 @@ func (n *Node) parse(ctx context.Context, method string) error {

key := n.Key
if strings.HasSuffix(key, consts.ListKeySuffix) {
key = key[0 : len(key)-2]
key = util.RemoveSuffix(key, consts.ListKeySuffix)
}
access, err := n.Action.ActionConfig.GetAccessConfig(key, true)

Expand Down Expand Up @@ -179,13 +172,13 @@ func (n *Node) checkAccess(ctx context.Context, method string, accessRoles []str
}

if role == consts.DENY {
return gerror.Newf("deny node: %s with %s", n.Key, n.Role)
return consts.NewDenyErr(n.Key, n.Role)
}

n.Role = role

if !lo.Contains(accessRoles, role) {
return gerror.Newf("node not access: %s with %s", n.Key, n.Role)
return consts.NewNoAccessErr(n.Key, n.Role)
}

return nil
Expand Down Expand Up @@ -231,26 +224,26 @@ func (n *Node) checkReq() error {
// must
for _, key := range n.structure.Must {
if _, exists := item[key]; !exists {
return gerror.New("structure错误: 400, 缺少" + n.Key + "." + key)
return consts.NewStructureKeyNoFoundErr(n.Key + "." + key)
}
}

// refuse
if len(n.structure.Refuse) > 0 && n.structure.Refuse[0] == "!" {
if len(n.structure.Must) == 0 {
return gerror.New("structure错误: 400, REFUSE为!时必须指定MUST" + n.Key)
return consts.NewValidStructureErr("REFUSE为!时必须指定MUST:" + n.Key)
}

for key, _ := range item {
if !lo.Contains(n.structure.Must, key) {
return gerror.New("structure错误: 400, 不能包含" + n.Key + "." + key)
return consts.NewValidStructureErr("不能包含:" + n.Key + "." + key)
}
}

} else {
for _, key := range n.structure.Refuse {
if _, exists := item[key]; exists {
return gerror.New("structure错误: 400, 不能包含" + n.Key + "." + key)
return consts.NewValidStructureErr("不能包含:" + n.Key + "." + key)
}
}
}
Expand Down Expand Up @@ -375,16 +368,22 @@ func (n *Node) do(ctx context.Context, method string) (ret model.Map, err error)
case http.MethodDelete:

default:
return nil, gerror.New("undefined method:" + method)
return nil, consts.NewMethodNotSupportErr(method)
}

executor, err := GetActionExecutor(n.executor)
if err != nil {
return nil, err
}

ret, err = executor.GetActionExecutor(n.executor).Do(ctx, executor.ActionExecutorReq{
Method: method,
Table: n.tableName,
Data: n.Data,
Where: n.Where,
Access: access,
Config: n.Action.ActionConfig,
ret, err = executor.Do(ctx, ActionExecutorReq{
Method: method,
Table: n.tableName,
Data: n.Data,
Where: n.Where,
Access: access,
Config: n.Action.ActionConfig,
NewQuery: n.Action.NewQuery,
})

if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions apijson.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package apijson

import (
"context"

"github.com/glennliao/apijson-go/action"
"github.com/glennliao/apijson-go/config"
"github.com/glennliao/apijson-go/model"
Expand All @@ -20,9 +21,6 @@ type ApiJson struct {

var DefaultApiJson = New()

type App struct {
}

func New() *ApiJson {
a := &ApiJson{}
a.config = config.New()
Expand Down Expand Up @@ -76,5 +74,7 @@ func (a *ApiJson) NewAction(ctx context.Context, method string, req model.Map) *
act.DbFieldStyle = a.config.DbFieldStyle
act.JsonFieldStyle = a.config.JsonFieldStyle

act.NewQuery = a.NewQuery

return act
}
21 changes: 11 additions & 10 deletions config/access_config.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package config

import (
"github.com/gogf/gf/v2/errors/gerror"
"net/http"

"github.com/glennliao/apijson-go/consts"
"github.com/gogf/gf/v2/os/gtime"
"github.com/samber/lo"
"net/http"
)

type FieldsGetValue struct {
Expand Down Expand Up @@ -56,28 +57,28 @@ func (a *AccessConfig) GetFieldsGetInByRole(role string) map[string][]string {
return inFieldsMap
}

func (a *Access) GetAccess(tableAlias string, noVerify bool) (*AccessConfig, error) {
access, ok := a.accessConfigMap[tableAlias]
func (a *Access) GetAccess(accessName string, noVerify bool) (*AccessConfig, error) {
access, ok := a.accessConfigMap[accessName]

if !ok {
if noVerify {
return &AccessConfig{
Debug: 0,
Name: tableAlias,
Alias: tableAlias,
Name: accessName,
Alias: accessName,
}, nil
}
return nil, gerror.Newf("access[%s]: 404", tableAlias)
return nil, consts.NewAccessNoFoundErr(accessName)
}

return &access, nil
}

func (a *Access) GetAccessRole(table string, method string) ([]string, string, error) {
access, ok := a.accessConfigMap[table]
func (a *Access) GetAccessRole(accessName string, method string) ([]string, string, error) {
access, ok := a.accessConfigMap[accessName]

if !ok {
return nil, "", gerror.Newf("access[%s]: 404", table)
return nil, "", consts.NewAccessNoFoundErr(accessName)
}

switch method {
Expand Down
Loading

0 comments on commit decda6d

Please sign in to comment.