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.
362 lines
7.3 KiB
362 lines
7.3 KiB
package vql
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
type Builder2 struct {
|
|
As string `json:"as"`
|
|
Select interface{} `json:"select"`
|
|
From interface{} `json:"from"`
|
|
Join interface{} `json:"join"`
|
|
Where interface{} `json:"where"`
|
|
Filter interface{} `json:"filter"` //同where,区别是作为做外层条件
|
|
Group interface{} `json:"group"`
|
|
Having interface{} `json:"having"`
|
|
Order interface{} `json:"order"`
|
|
}
|
|
|
|
func NewBuilder2() *Builder2 {
|
|
return &Builder2{}
|
|
}
|
|
|
|
func (b *Builder2) Select2(selects ...interface{}) *Builder2 {
|
|
b.Select = selects
|
|
return b
|
|
}
|
|
|
|
func (b *Builder2) Sql() (string, error) {
|
|
selectSql, err := toSelectSql(b.Select)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
fromSql, err := toFromSql(b.From)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
joinSql, err := toJoinSql(b.Join)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
whereSql, err := toWhereSql(b.Where)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
groupSql, err := toGroupSql(b.Group)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
havingSql, err := toHavingSql(b.Having)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
orderSql, err := toOrderSql(b.Order)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
filterSql, err := toWhereSql(b.Filter)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
sql := fmt.Sprintf("select %s from %s ", selectSql, fromSql)
|
|
if joinSql != "" {
|
|
sql += fmt.Sprintf(" %s ", joinSql)
|
|
}
|
|
if whereSql != "" {
|
|
sql += fmt.Sprintf(" where %s ", whereSql)
|
|
}
|
|
if groupSql != "" {
|
|
sql += fmt.Sprintf(" group by %s ", groupSql)
|
|
}
|
|
if havingSql != "" {
|
|
sql += fmt.Sprintf(" having %s ", havingSql)
|
|
}
|
|
if orderSql != "" {
|
|
sql += fmt.Sprintf(" order by %s ", orderSql)
|
|
}
|
|
|
|
if filterSql != "" {
|
|
as := b.As
|
|
if as == "" {
|
|
as = "____tmp"
|
|
}
|
|
sql = fmt.Sprintf("select * from (%s) as %s where %s", sql, as, filterSql)
|
|
}
|
|
|
|
return sql, nil
|
|
|
|
}
|
|
|
|
func toSelectSql(selects interface{}) (string, error) {
|
|
|
|
selectSql := ""
|
|
if selectSql, ok := selects.(string); ok {
|
|
return selectSql, nil
|
|
}
|
|
|
|
selectGjson := gjson.Parse(jsonEncode(selects))
|
|
if selectGjson.IsArray() {
|
|
ses := []string{}
|
|
for _, se := range selectGjson.Array() {
|
|
ses = append(ses, se.String())
|
|
}
|
|
selectSql = strings.Join(ses, ",")
|
|
} else {
|
|
selectSql = selectGjson.String()
|
|
}
|
|
return selectSql, nil
|
|
}
|
|
|
|
func toFromSql(from interface{}) (string, error) {
|
|
fromSql := ""
|
|
if fromSql, ok := from.(string); ok {
|
|
return fromSql, nil
|
|
}
|
|
|
|
fromGjson := gjson.Parse(jsonEncode(from))
|
|
if fromGjson.IsObject() {
|
|
nb := NewBuilder2()
|
|
json.Unmarshal([]byte(fromGjson.Raw), &nb)
|
|
ns, err := nb.Sql()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if nb.As != "" {
|
|
fromSql = fmt.Sprintf("( %s ) as %s", ns, nb.As)
|
|
} else {
|
|
fromSql = fmt.Sprintf("( %s )", ns)
|
|
}
|
|
} else {
|
|
fromSql = fromGjson.String()
|
|
}
|
|
return fromSql, nil
|
|
}
|
|
|
|
func toJoinSql(join interface{}) (string, error) {
|
|
if join == nil {
|
|
return "", nil
|
|
}
|
|
// joinSql := ""
|
|
if joinSql, ok := join.(string); ok {
|
|
return joinSql, nil
|
|
}
|
|
|
|
joinGjson := gjson.Parse(jsonEncode(join))
|
|
if joinGjson.IsArray() {
|
|
js := []string{}
|
|
for _, j := range joinGjson.Array() {
|
|
nj, err := toJoinSql(j.Value())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
js = append(js, nj)
|
|
}
|
|
return strings.Join(js, " "), nil
|
|
} else if joinGjson.IsObject() {
|
|
types := joinGjson.Get("type").String()
|
|
if types == "" {
|
|
types = "left"
|
|
}
|
|
as := joinGjson.Get("as").String()
|
|
if as == "" {
|
|
return "", errors.New("join 中必须赋予as(别名)")
|
|
}
|
|
|
|
objGjson := joinGjson.Get("obj")
|
|
obj := ""
|
|
if objGjson.IsObject() {
|
|
nb := NewBuilder2()
|
|
json.Unmarshal([]byte(objGjson.Raw), &nb)
|
|
ns, err := nb.Sql()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
obj = ns
|
|
} else {
|
|
obj = objGjson.String()
|
|
}
|
|
|
|
on := joinGjson.Get("on").String()
|
|
if on == "" {
|
|
return "", errors.New("join 中必须赋予on(条件)")
|
|
}
|
|
|
|
return fmt.Sprintf("%s join ( %s ) as %s on %s", types, obj, as, on), nil
|
|
} else {
|
|
return joinGjson.String(), nil
|
|
}
|
|
|
|
// joinGjson := gjson.Parse(jsonEncode(join))
|
|
// if joinGjson.IsArray() {
|
|
// js := []string{}
|
|
// for _, j := range joinGjson.Array() {
|
|
// if j.IsObject() {
|
|
// return
|
|
// } else {
|
|
// js = append(js, j.String())
|
|
// }
|
|
// }
|
|
// joinSql = strings.Join(js, " ")
|
|
// } else {
|
|
// joinSql = joinGjson.String()
|
|
// }
|
|
// return joinSql
|
|
}
|
|
|
|
func toWhereSql(where interface{}) (string, error) {
|
|
if where == nil {
|
|
return "", nil
|
|
}
|
|
whereSql := ""
|
|
if whereSql, ok := where.(string); ok {
|
|
return whereSql, nil
|
|
}
|
|
|
|
whereGjson := gjson.Parse(jsonEncode(where))
|
|
|
|
//[ "a=","1","and",[["c=","3"],"and",["d=","4"]],"or",["b=","2"]]
|
|
if whereGjson.IsArray() {
|
|
if len(whereGjson.Array()) == 0 {
|
|
return "", nil
|
|
}
|
|
ws := []string{}
|
|
expression := whereGjson.Array()
|
|
|
|
if len(expression) == 0 {
|
|
return "", nil
|
|
}
|
|
|
|
if expression[0].String() == "and" || expression[0].String() == "or" {
|
|
|
|
operator := "and"
|
|
|
|
for _, w := range expression {
|
|
if w.Type == gjson.String {
|
|
if whereSql == "" && (w.String() == "and" || w.String() == "or") {
|
|
operator = w.String()
|
|
} else {
|
|
if w.String() == "" {
|
|
continue
|
|
}
|
|
ws = append(ws, w.String())
|
|
}
|
|
} else {
|
|
newExp, err := toWhereSql(w.Value())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if newExp == "" {
|
|
continue
|
|
}
|
|
ws = append(ws, newExp)
|
|
}
|
|
|
|
whereSql = strings.Join(ws, fmt.Sprintf(" %s ", operator))
|
|
}
|
|
} else {
|
|
|
|
// ["and",["a","=","1"],"or",["b",">","2"]]
|
|
//三段式
|
|
if len(expression) == 3 {
|
|
ws = append(ws, expression[0].String(), expression[1].String(), expression[2].Raw)
|
|
}
|
|
|
|
// for _, w := range expression {
|
|
// if w.Type == gjson.String {
|
|
// ws = append(ws, w.String())
|
|
// } else {
|
|
// newExp, err := toWhereSql(w.Value())
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// ws = append(ws, newExp)
|
|
// }
|
|
|
|
whereSql = strings.Join(ws, " ")
|
|
// }
|
|
}
|
|
} else if whereGjson.IsObject() {
|
|
if len(whereGjson.Map()) == 0 {
|
|
return "", nil
|
|
}
|
|
|
|
newValue := []interface{}{
|
|
"and",
|
|
}
|
|
|
|
ops := []string{"=", ">", ">=", "<", "<=", "<>", "!=", "like", "not like", "in", "not in", "between", "not between"}
|
|
|
|
for k, v := range whereGjson.Map() {
|
|
if v.Value() == nil {
|
|
continue
|
|
}
|
|
|
|
prefix := k
|
|
mop := "="
|
|
|
|
for _, op := range ops {
|
|
if strings.HasSuffix(k, op) {
|
|
prefix = strings.TrimSuffix(k, op)
|
|
mop = op
|
|
break
|
|
}
|
|
}
|
|
|
|
newValue = append(newValue, []string{prefix, mop, v.String()})
|
|
}
|
|
|
|
return toWhereSql(newValue)
|
|
} else {
|
|
whereSql = whereGjson.String()
|
|
}
|
|
if strings.TrimSpace(whereSql) == "" {
|
|
return "", nil
|
|
}
|
|
return fmt.Sprintf("( %s )", whereSql), nil
|
|
}
|
|
|
|
func toGroupSql(group interface{}) (string, error) {
|
|
if group == nil {
|
|
return "", nil
|
|
}
|
|
// groupSql := ""
|
|
if groupSql, ok := group.(string); ok {
|
|
return groupSql, nil
|
|
}
|
|
return "", fmt.Errorf("暂时不支持非字符串类型的group语句")
|
|
}
|
|
|
|
func toHavingSql(having interface{}) (string, error) {
|
|
if having == nil {
|
|
return "", nil
|
|
}
|
|
// havingSql := ""
|
|
if havingSql, ok := having.(string); ok {
|
|
return havingSql, nil
|
|
}
|
|
return "", fmt.Errorf("暂时不支持非字符串类型的having语句")
|
|
}
|
|
|
|
func toOrderSql(order interface{}) (string, error) {
|
|
if order == nil {
|
|
return "", nil
|
|
}
|
|
// orderSql := ""
|
|
if orderSql, ok := order.(string); ok {
|
|
return orderSql, nil
|
|
}
|
|
return "", fmt.Errorf("暂时不支持非字符串类型的order语句")
|
|
}
|