package apijson import ( "fmt" "net/http" "strings" "time" ) func NewQueryNode(c *QueryContext, path, key string, queryMap map[string]interface{}) *QueryNode { n := &QueryNode{ ctx: c, Key: strings.ToLower(key), Path: path, RequestMap: queryMap, start: time.Now().UnixNano(), sqlExecutor: &MysqlExecutor{}, isList: strings.HasSuffix(key, "[]"), } c.nodePathMap[path] = n if n.isList { n.parseList() } else { n.parseOne() } return n } type QueryNode struct { ctx *QueryContext start int64 depth int8 running bool completed bool isList bool page interface{} count interface{} sqlExecutor *MysqlExecutor primaryKey string relateKV map[string]string Key string Path string RequestMap map[string]interface{} CurrentData map[string]interface{} ResultList []map[string]interface{} children map[string]*QueryNode } func (n *QueryNode) parseList() { root := n.ctx if root.err != nil { return } if value, exists := n.RequestMap[n.Key[0:len(n.Key)-2]]; exists { if kvs, ok := value.(map[string]interface{}); ok { root.err = n.sqlExecutor.ParseTable(n.Key) n.parseKVs(kvs) } else { root.err = fmt.Errorf("列表同名参数展开出错,listKey: %s, object: %v", n.Key, value) root.code = http.StatusBadRequest } return } for field, value := range n.RequestMap { if value == nil { root.err = fmt.Errorf("field of [%s] value error, %s is nil", n.Key, field) return } switch field { case "page": n.page = value case "count": n.count = value default: if kvs, ok := value.(map[string]interface{}); ok { child := NewQueryNode(root, n.Path+"/"+field, field, kvs) if root.err != nil { return } if n.children == nil { n.children = make(map[string]*QueryNode) } n.children[field] = child if nonDepend(n, child) && len(n.primaryKey) == 0 { n.primaryKey = field } } } } } func nonDepend(parent, child *QueryNode) bool { if len(child.relateKV) == 0 { return true } for _, v := range child.relateKV { if strings.HasPrefix(v, parent.Path) { return false } } return true } func (n *QueryNode) parseOne() { root := n.ctx root.err = n.sqlExecutor.ParseTable(n.Key) if root.err != nil { root.code = http.StatusBadRequest return } n.sqlExecutor.PageSize(0, 1) n.parseKVs(n.RequestMap) } func (n *QueryNode) parseKVs(kvs map[string]interface{}) { root := n.ctx for field, value := range kvs { if value == nil { root.err = fmt.Errorf("field value error, %s is nil", field) root.code = http.StatusBadRequest return } if queryPath, ok := value.(string); ok && strings.HasSuffix(field, "@") { // @ 结尾表示有关联查询 if n.relateKV == nil { n.relateKV = make(map[string]string) } fullPath := queryPath if strings.HasPrefix(queryPath, "/") { fullPath = n.Path + queryPath } n.relateKV[field[0:len(field)-1]] = fullPath } else { n.sqlExecutor.ParseCondition(field, value) } } } func (n *QueryNode) Result() interface{} { if n.isList { return n.ResultList } if len(n.ResultList) > 0 { return n.ResultList[0] } return nil } func (n *QueryNode) doQueryData() { if n.completed { return } n.running = true defer func() { n.running, n.completed = false, true }() root := n.ctx if len(n.relateKV) > 0 { for field, queryPath := range n.relateKV { value := root.findResult(queryPath) if root.err != nil { return } n.sqlExecutor.ParseCondition(field, value) } } if !n.isList { n.ResultList, root.err = n.sqlExecutor.Exec() if len(n.ResultList) > 0 { n.CurrentData = n.ResultList[0] return } return } primary := n.children[n.primaryKey] primary.sqlExecutor.PageSize(n.page, n.count) primary.doQueryData() if root.err != nil { return } listData := primary.ResultList n.ResultList = make([]map[string]interface{}, len(listData)) for i, x := range listData { n.ResultList[i] = make(map[string]interface{}) n.ResultList[i][n.primaryKey] = x primary.CurrentData = x if len(n.children) > 0 { for _, child := range n.children { if child != primary { child.doQueryData() n.ResultList[i][child.Key] = child.Result() } } } } }