Add group builder

This commit is contained in:
Jinzhu 2018-03-03 13:36:42 +08:00
parent 23457d28ce
commit 1f501c36d7
5 changed files with 151 additions and 112 deletions

2
api.go
View File

@ -40,7 +40,7 @@ func (s *DB) Joins(query string, args ...interface{}) *DB {
// Group specify the group method on the find
func (s *DB) Group(column string) *DB {
tx := s.init()
tx.Statement.GroupBy.GroupByColumns = append(tx.Statement.GroupBy.GroupByColumns, column)
tx.Statement.GroupBy.Columns = append(tx.Statement.GroupBy.Columns, column)
return tx
}

View File

@ -0,0 +1,110 @@
package sqlbuilder
import (
"fmt"
"github.com/jinzhu/gorm"
)
// ConditionInterface condition interface
type ConditionInterface interface {
ToSQL(*gorm.DB) (string, []interface{})
}
// BuildConditions build conditions
func BuildConditions(tx *gorm.DB) chan *Builder {
queryChan := make(chan *Builder)
go func() {
builder := &Builder{}
for i, c := range tx.Statement.Conditions {
if i > 0 {
builder.SQL.WriteString(" AND ")
}
buildCondition(tx, c, builder)
}
queryChan <- builder
}()
return queryChan
}
func buildCondition(tx *gorm.DB, c gorm.ConditionInterface, builder *Builder) {
switch cond := c.(type) {
case gorm.And:
builder.SQL.WriteString("(")
for i, v := range cond {
if i > 0 {
builder.SQL.WriteString(" AND ")
}
buildCondition(tx, v, builder)
}
builder.SQL.WriteString(")")
case gorm.Or:
builder.SQL.WriteString("(")
for i, v := range cond {
if i > 0 {
builder.SQL.WriteString(" OR ")
}
buildCondition(tx, v, builder)
}
builder.SQL.WriteString(")")
case gorm.Not:
builder.SQL.WriteString("NOT (")
for i, v := range cond {
if i > 0 {
builder.SQL.WriteString(" AND ")
}
buildCondition(tx, v, builder)
}
builder.SQL.WriteString(")")
case gorm.Raw:
builder.SQL.WriteString(cond.SQL)
builder.Args = append(builder.Args, cond.Args...)
case gorm.Eq:
if cond.Value == nil {
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" IS NULL")
} else {
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" = ?")
builder.Args = append(builder.Args, cond.Value)
}
case gorm.Neq:
if cond.Value == nil {
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" IS NOT NULL")
} else {
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" <> ?")
builder.Args = append(builder.Args, cond.Value)
}
case gorm.Gt:
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" > ?")
builder.Args = append(builder.Args, cond.Value)
case gorm.Gte:
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" >= ?")
builder.Args = append(builder.Args, cond.Value)
case gorm.Lt:
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" < ?")
builder.Args = append(builder.Args, cond.Value)
case gorm.Lte:
builder.SQL.WriteString(tx.Dialect().Quote(cond.Column))
builder.SQL.WriteString(" <= ?")
builder.Args = append(builder.Args, cond.Value)
default:
if sqlCond, ok := cond.(ConditionInterface); ok {
sql, as := sqlCond.ToSQL(tx)
builder.SQL.WriteString(sql)
builder.Args = append(builder.Args, as...)
} else {
tx.AddError(fmt.Errorf("unsupported condition: %#v", cond))
}
}
return
}

View File

@ -0,0 +1,32 @@
package sqlbuilder
import (
"strings"
"github.com/jinzhu/gorm"
)
// BuildGroupCondition build group condition
func BuildGroupCondition(tx *gorm.DB) chan *Builder {
groupChan := make(chan *Builder)
go func() {
builder := &Builder{}
if groupBy := tx.Statement.GroupBy; len(groupBy.Columns) > 0 {
builder.SQL.WriteString(strings.Join(tx.Statement.GroupBy.Columns, ", "))
if len(groupBy.Having) > 0 {
builder.SQL.WriteString(" HAVING ")
for i, having := range groupBy.Having {
if i > 0 {
builder.SQL.WriteString(" AND ")
}
buildCondition(tx, having, builder)
}
}
}
groupChan <- builder
}()
return groupChan
}

View File

@ -1,112 +1,9 @@
package sqlbuilder
import (
"bytes"
"fmt"
import "bytes"
"github.com/jinzhu/gorm"
)
func buildCondition(tx *gorm.DB, c gorm.ConditionInterface, s *bytes.Buffer) []interface{} {
args := []interface{}{}
switch cond := c.(type) {
case gorm.And:
s.WriteString("(")
for i, v := range cond {
if i > 0 {
s.WriteString(" AND ")
}
args = append(args, buildCondition(tx, v, s)...)
}
s.WriteString(")")
case gorm.Or:
s.WriteString("(")
for i, v := range cond {
if i > 0 {
s.WriteString(" OR ")
}
args = append(args, buildCondition(tx, v, s)...)
}
s.WriteString(")")
case gorm.Not:
s.WriteString("NOT (")
for i, v := range cond {
if i > 0 {
s.WriteString(" AND ")
}
args = append(args, buildCondition(tx, v, s)...)
}
s.WriteString(")")
case gorm.Raw:
s.WriteString(cond.SQL)
args = append(args, cond.Args...)
case gorm.Eq:
if cond.Value == nil {
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" IS NULL")
} else {
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" = ?")
args = append(args, cond.Value)
}
case gorm.Neq:
if cond.Value == nil {
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" IS NOT NULL")
} else {
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" <> ?")
args = append(args, cond.Value)
}
case gorm.Gt:
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" > ?")
args = append(args, cond.Value)
case gorm.Gte:
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" >= ?")
args = append(args, cond.Value)
case gorm.Lt:
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" < ?")
args = append(args, cond.Value)
case gorm.Lte:
s.WriteString(tx.Dialect().Quote(cond.Column))
s.WriteString(" <= ?")
args = append(args, cond.Value)
default:
if sqlCond, ok := cond.(ConditionInterface); ok {
sql, as := sqlCond.ToSQL(tx)
s.WriteString(sql)
args = append(args, as)
} else {
tx.AddError(fmt.Errorf("unsupported condition: %#v", cond))
}
}
return args
}
// ConditionInterface condition interface
type ConditionInterface interface {
ToSQL(*gorm.DB) (string, []interface{})
}
// BuildConditions build conditions
func BuildConditions(tx *gorm.DB) chan string {
queryChan := make(chan string)
go func() {
s := bytes.NewBufferString("")
args := []interface{}{}
for i, c := range tx.Statement.Conditions {
if i > 0 {
s.WriteString(" AND ")
}
args = append(args, buildCondition(tx, c, s)...)
}
}()
return queryChan
// Builder sql builder
type Builder struct {
SQL bytes.Buffer
Args []interface{}
}

View File

@ -47,8 +47,8 @@ type Join struct {
// GroupBy group by statement
type GroupBy struct {
GroupByColumns []string
Having []ConditionInterface
Columns []string
Having []ConditionInterface
}
// OrderCondition order condition, could be string or sql expr
@ -84,7 +84,7 @@ func (stmt *Statement) Clone() *Statement {
// BuildCondition build condition
func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) ConditionInterface {
if sql, ok := query.(string); ok {
return Raw{Value: sql, Args: args}
return Raw{SQL: sql, Args: args}
}
andConds := And([]ConditionInterface{ConditionInterface(query)})