diff --git a/chainable_api.go b/chainable_api.go index 49f260d31..f0bf80180 100644 --- a/chainable_api.go +++ b/chainable_api.go @@ -135,14 +135,20 @@ func (db *DB) Joins(query string, args ...interface{}) (tx *DB) { } // Group specify the group method on the find -func (db *DB) Group(column string) (tx *DB) { +func (db *DB) Group(name string) (tx *DB) { tx = db.getInstance() + tx.Statement.AddClause(clause.GroupBy{ + Columns: []clause.Column{{Name: name}}, + }) return } // Having specify HAVING conditions for GROUP BY func (db *DB) Having(query interface{}, args ...interface{}) (tx *DB) { tx = db.getInstance() + tx.Statement.AddClause(clause.GroupBy{ + Having: tx.Statement.BuildCondtion(query, args...), + }) return } diff --git a/clause/benchmarks_test.go b/clause/benchmarks_test.go index 33d3430af..47001cd1f 100644 --- a/clause/benchmarks_test.go +++ b/clause/benchmarks_test.go @@ -41,7 +41,7 @@ func BenchmarkComplexSelect(b *testing.B) { clause.Where{Exprs: []clause.Expression{ clause.Or(clause.Gt{Column: "score", Value: 100}, clause.Like{Column: "name", Value: "%linus%"}), }}, - clause.GroupBy{Columns: []clause.Column{{Name: "role"}}, Having: clause.Where{[]clause.Expression{clause.Eq{"role", "admin"}}}}, + clause.GroupBy{Columns: []clause.Column{{Name: "role"}}, Having: []clause.Expression{clause.Eq{"role", "admin"}}}, clause.Limit{Limit: 10, Offset: 20}, clause.OrderBy{Columns: []clause.OrderByColumn{{Column: clause.PrimaryColumn, Desc: true}}}, } diff --git a/clause/group_by.go b/clause/group_by.go index 8d1647317..a245d50a3 100644 --- a/clause/group_by.go +++ b/clause/group_by.go @@ -3,7 +3,7 @@ package clause // GroupBy group by clause type GroupBy struct { Columns []Column - Having Where + Having []Expression } // Name from clause name @@ -21,9 +21,9 @@ func (groupBy GroupBy) Build(builder Builder) { builder.WriteQuoted(column) } - if len(groupBy.Having.Exprs) > 0 { + if len(groupBy.Having) > 0 { builder.Write(" HAVING ") - groupBy.Having.Build(builder) + Where{Exprs: groupBy.Having}.Build(builder) } } @@ -31,7 +31,7 @@ func (groupBy GroupBy) Build(builder Builder) { func (groupBy GroupBy) MergeClause(clause *Clause) { if v, ok := clause.Expression.(GroupBy); ok { groupBy.Columns = append(v.Columns, groupBy.Columns...) - groupBy.Having.Exprs = append(v.Having.Exprs, groupBy.Having.Exprs...) + groupBy.Having = append(v.Having, groupBy.Having...) } clause.Expression = groupBy } diff --git a/clause/group_by_test.go b/clause/group_by_test.go index 35be84a4e..98aad3eb9 100644 --- a/clause/group_by_test.go +++ b/clause/group_by_test.go @@ -16,17 +16,17 @@ func TestGroupBy(t *testing.T) { { []clause.Interface{clause.Select{}, clause.From{}, clause.GroupBy{ Columns: []clause.Column{{Name: "role"}}, - Having: clause.Where{[]clause.Expression{clause.Eq{"role", "admin"}}}, + Having: []clause.Expression{clause.Eq{"role", "admin"}}, }}, "SELECT * FROM `users` GROUP BY `role` HAVING `role` = ?", []interface{}{"admin"}, }, { []clause.Interface{clause.Select{}, clause.From{}, clause.GroupBy{ Columns: []clause.Column{{Name: "role"}}, - Having: clause.Where{[]clause.Expression{clause.Eq{"role", "admin"}}}, + Having: []clause.Expression{clause.Eq{"role", "admin"}}, }, clause.GroupBy{ Columns: []clause.Column{{Name: "gender"}}, - Having: clause.Where{[]clause.Expression{clause.Neq{"gender", "U"}}}, + Having: []clause.Expression{clause.Neq{"gender", "U"}}, }}, "SELECT * FROM `users` GROUP BY `role`,`gender` HAVING `role` = ? AND `gender` <> ?", []interface{}{"admin", "U"}, }, diff --git a/finisher_api.go b/finisher_api.go index 806c67237..51d9b4096 100644 --- a/finisher_api.go +++ b/finisher_api.go @@ -145,12 +145,6 @@ func (db *DB) Delete(value interface{}, conds ...interface{}) (tx *DB) { return } -//Preloads only preloads relations, don`t touch out -func (db *DB) Preloads(out interface{}) (tx *DB) { - tx = db.getInstance() - return -} - func (db *DB) Count(value interface{}) (tx *DB) { tx = db.getInstance() return diff --git a/tests/group_by.go b/tests/group_by.go new file mode 100644 index 000000000..b0bb41551 --- /dev/null +++ b/tests/group_by.go @@ -0,0 +1,62 @@ +package tests + +import ( + "testing" + + "github.com/jinzhu/gorm" +) + +func TestGroupBy(t *testing.T, db *gorm.DB) { + db.Migrator().DropTable(&User{}) + db.AutoMigrate(&User{}) + + t.Run("GroupBy", func(t *testing.T) { + var users = []User{{ + Name: "groupby", + Age: 10, + Birthday: Now(), + }, { + Name: "groupby", + Age: 20, + Birthday: Now(), + }, { + Name: "groupby", + Age: 30, + Birthday: Now(), + }, { + Name: "groupby1", + Age: 110, + Birthday: Now(), + }, { + Name: "groupby1", + Age: 220, + Birthday: Now(), + }, { + Name: "groupby1", + Age: 330, + Birthday: Now(), + }} + + if err := db.Create(&users).Error; err != nil { + t.Errorf("errors happened when create: %v", err) + } + + var name string + var total int + if err := db.Model(&User{}).Select("name, sum(age)").Where("name = ?", "groupby").Group("name").Row().Scan(&name, &total); err != nil { + t.Errorf("no error should happen, but got %v", err) + } + + if name != "groupby" || total != 60 { + t.Errorf("name should be groupby, but got %v, total should be 60, but got %v", name, total) + } + + if err := db.Model(&User{}).Select("name, sum(age) as total").Where("name LIKE ?", "groupby%").Group("name").Having("name = ?", "groupby1").Row().Scan(&name, &total); err != nil { + t.Errorf("no error should happen, but got %v", err) + } + + if name != "groupby1" || total != 660 { + t.Errorf("name should be groupby, but got %v, total should be 660, but got %v", name, total) + } + }) +} diff --git a/tests/tests.go b/tests/tests.go index a15a9d0d5..65c1ca964 100644 --- a/tests/tests.go +++ b/tests/tests.go @@ -20,6 +20,8 @@ func RunTestsSuit(t *testing.T, db *gorm.DB) { TestFind(t, db) TestUpdate(t, db) TestDelete(t, db) + + TestGroupBy(t, db) } func TestCreate(t *testing.T, db *gorm.DB) {