package vql import ( "encoding/json" "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"` 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 } 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) } 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 { return "", fmt.Errorf("目前仅支持数组或者字符串") } // 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() { 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 { ws = append(ws, w.String()) } } else { newExp, err := toWhereSql(w.Value()) if err != nil { return "", err } ws = append(ws, newExp) } whereSql = strings.Join(ws, fmt.Sprintf(" %s ", operator)) } } else { 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() { newValue := []interface{}{ "and", } ops := []string{"=", ">", ">=", "<", "<=", "<>", "!="} 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() } 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语句") }