You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
4.2 KiB
195 lines
4.2 KiB
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(ctx *QueryContext) {
|
|
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(ctx)
|
|
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(ctx)
|
|
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(ctx)
|
|
n.ResultList[i][child.Key] = child.Result()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|