diff --git a/apijson/query_context.go b/apijson/query_context.go deleted file mode 100644 index fb807f8..0000000 --- a/apijson/query_context.go +++ /dev/null @@ -1,113 +0,0 @@ -package apijson - -import ( - "fmt" - "net/http" - "strings" -) - -type QueryContext struct { - req map[string]interface{} - code int - nodeTree map[string]*QueryNode - nodePathMap map[string]*QueryNode - Data interface{} - ExtensionValue map[string]string - err error - explain bool -} - -func NewQueryContext(req map[string]interface{}) *QueryContext { - return &QueryContext{ - req: req, - code: 0, - nodeTree: make(map[string]*QueryNode), - nodePathMap: make(map[string]*QueryNode), - } -} - -func (c *QueryContext) Response() map[string]interface{} { - c.doParse() - if c.err == nil { - c.doQuery() - } - resultMap := make(map[string]interface{}) - resultMap["ok"] = c.code == http.StatusOK - resultMap["code"] = c.code - if c.err != nil { - resultMap["msg"] = c.err.Error() - } else { - for k, v := range c.nodeTree { - //logger.Debugf("response.nodeMap K: %s, V: %v", k, v) - resultMap[k] = v.Result() - } - } - return resultMap -} - -func (c *QueryContext) doParse() { - //startTime := time.Now().Nanosecond() - for key := range c.req { - if c.err != nil { - return - } - if key == "@explain" { - c.explain = c.req[key].(bool) - } else if c.nodeTree[key] == nil { - c.parseByKey(key) - } - } -} - -func (c *QueryContext) doQuery() { - for _, n := range c.nodeTree { - if c.err != nil { - return - } - n.doQueryData(c) - } -} - -func (c *QueryContext) parseByKey(key string) { - queryObject := c.req[key] - if queryObject == nil { - c.err = fmt.Errorf("值不能为空, key: %s, value: %v", key, queryObject) - return - } - if queryMap, ok := queryObject.(map[string]interface{}); !ok { - c.err = fmt.Errorf("值类型不对, key: %s, value: %v", key, queryObject) - } else { - node := NewQueryNode(c, key, key, queryMap) - // logger.Debugf("parse %s: %+v", key, node) - c.nodeTree[key] = node - } -} - -func (c *QueryContext) End(code int, msg string) { - c.code = code - // logger.Errorf("发生错误,终止处理, code: %d, msg: %s", code, msg) -} - -func (c *QueryContext) findResult(value string) interface{} { - i := strings.LastIndex(value, "/") - path := value[0:i] - node := c.nodePathMap[path] - if node == nil { - c.err = fmt.Errorf("关联查询参数有误: %s", value) - return nil - } - if node.running { - c.err = fmt.Errorf("有循环依赖") - return nil - } - node.doQueryData(c) - if c.err != nil { - return nil - } - if node.CurrentData == nil { - // logger.Info("查询结果为空,queryPath: " + value) - return nil - } - key := value[i+1:] - return node.CurrentData[key] -} diff --git a/apijson/query_node.go b/apijson/query_node.go deleted file mode 100644 index cef2cd3..0000000 --- a/apijson/query_node.go +++ /dev/null @@ -1,195 +0,0 @@ -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() - } - } - } - } -} diff --git a/apijson/sqlparser.go b/apijson/sqlparser.go deleted file mode 100644 index 0d63072..0000000 --- a/apijson/sqlparser.go +++ /dev/null @@ -1,129 +0,0 @@ -package apijson - -import ( - "bytes" - "encoding/json" - "strconv" - "strings" -) - -const DefaultLimit = 1000 - -type MysqlExecutor struct { - table string - columns []string - where []string - params []interface{} - order string - group string - limit int - page int -} - -func (e *MysqlExecutor) Table() string { - return e.table -} - -func (e *MysqlExecutor) ParseTable(t string) error { - if strings.HasSuffix(t, "[]") { - t = t[0 : len(t)-2] - } - e.table = t - return nil -} - -func (e *MysqlExecutor) ToSQL() string { - var buf bytes.Buffer - buf.WriteString("SELECT ") - if e.columns == nil { - buf.WriteString("*") - } else { - buf.WriteString(strings.Join(e.columns, ",")) - } - buf.WriteString(" FROM ") - buf.WriteString(e.table) - if len(e.where) > 0 { - buf.WriteString(" WHERE ") - buf.WriteString(strings.Join(e.where, " and ")) - } - if e.order != "" { - buf.WriteString(" ORDER BY ") - buf.WriteString(e.order) - } - buf.WriteString(" LIMIT ") - buf.WriteString(strconv.Itoa(e.limit)) - if e.limit > 1 { - buf.WriteString(" OFFSET ") - buf.WriteString(strconv.Itoa(e.limit * e.page)) - } - return buf.String() -} - -func jsonEncode(v interface{}) string { - raw, _ := json.Marshal(v) - return string(raw) -} - -func (e *MysqlExecutor) ParseCondition(field string, value interface{}) { - if values, ok := value.([]interface{}); ok { - // 数组使用 IN 条件 - condition := field + " in (" - for i, v := range values { - if i == 0 { - // condition += "?" - condition += jsonEncode(v) - } else { - // condition += ",?" - condition += "," + jsonEncode(v) - } - // e.params = append(e.params, v) - } - e.where = append(e.where, condition+")") - } else if valueStr, ok := value.(string); ok { - if strings.HasPrefix(field, "@") { - switch field[1:] { - case "order": - e.order = valueStr - case "column": - e.columns = strings.Split(valueStr, ",") - } - } else { - // e.where = append(e.where, field+"=?") - e.where = append(e.where, field+"="+jsonEncode(valueStr)) - // e.params = append(e.params, valueStr) - } - } else { - // e.where = append(e.where, field+"=?") - - e.where = append(e.where, field+"="+jsonEncode(value)) - // e.params = append(e.params, value) - } -} - -func (e *MysqlExecutor) Exec(c *QueryContext) ([]map[string]interface{}, error) { - sql := e.ToSQL() - return QueryAll(c, sql, e.params...) -} - -var QueryAll = func(c *QueryContext, sql string, args ...interface{}) ([]map[string]interface{}, error) { - return nil, nil -} - -func SetQueryAll(f func(c *QueryContext, sql string, args ...interface{}) ([]map[string]interface{}, error)) { - QueryAll = f -} - -func (e *MysqlExecutor) PageSize(page interface{}, count interface{}) { - e.page = parseNum(page, 0) - e.limit = parseNum(count, 10) -} - -func parseNum(value interface{}, defaultVal int) int { - if n, ok := value.(float64); ok { - return int(n) - } - if n, ok := value.(int); ok { - return n - } - return defaultVal -}