From 82b63fc87d73e50326d74ff944eed6ec7017ea08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net> Date: Thu, 7 Aug 2014 11:32:50 -0500 Subject: [PATCH] MySQL: Adding support for db.Result.Group(). --- mysql/_dumps/structs.sql | 9 +++++++ mysql/database.go | 1 + mysql/database_test.go | 55 ++++++++++++++++++++++++++++++++++++++++ mysql/layout.go | 8 ++++++ mysql/result.go | 22 ++++++++++++++++ 5 files changed, 95 insertions(+) diff --git a/mysql/_dumps/structs.sql b/mysql/_dumps/structs.sql index 42240f4b..de205b43 100644 --- a/mysql/_dumps/structs.sql +++ b/mysql/_dumps/structs.sql @@ -50,3 +50,12 @@ CREATE TABLE data_types ( _date DATETIME NOT NULL, _time TIME NOT NULL ); + +DROP TABLE IF EXISTS stats_test; + +CREATE TABLE stats_test ( + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + PRIMARY KEY(id), + `numeric` INT(10), + `value` INT(10) +); diff --git a/mysql/database.go b/mysql/database.go index 4eb19052..1ac42dc5 100644 --- a/mysql/database.go +++ b/mysql/database.go @@ -106,6 +106,7 @@ func init() { mysqlDropDatabaseLayout, mysqlDropTableLayout, mysqlSelectCountLayout, + mysqlGroupByLayout, } db.Register(Adapter, &Source{}) diff --git a/mysql/database_test.go b/mysql/database_test.go index b2baadb3..f76ff00c 100644 --- a/mysql/database_test.go +++ b/mysql/database_test.go @@ -31,6 +31,7 @@ package mysql import ( "database/sql" "flag" + "math/rand" "os" "reflect" "strings" @@ -315,7 +316,61 @@ func TestNullableFields(t *testing.T) { if test.NullStringTest.Valid == false { t.Fatalf(`Expecting valid value.`) } +} + +func TestGroup(t *testing.T) { + + var err error + var sess db.Database + var stats db.Collection + + if sess, err = db.Open(Adapter, settings); err != nil { + t.Fatal(err) + } + + type stats_t struct { + Numeric int `db:"numeric"` + Value int `db:"value"` + } + + defer sess.Close() + + if stats, err = sess.Collection("stats_test"); err != nil { + t.Fatal(err) + } + + // Truncating table. + if err = stats.Truncate(); err != nil { + t.Fatal(err) + } + + // Adding row append. + for i := 0; i < 1000; i++ { + numeric, value := rand.Intn(10), rand.Intn(100) + if _, err = stats.Append(stats_t{numeric, value}); err != nil { + t.Fatal(err) + } + } + // db.Func{"COUNT", 1}, + // db.Func{"SUM", `value`}, + + // Testing GROUP BY + res := stats.Find().Select( + `numeric`, + db.Raw{`COUNT(1) AS counter`}, + db.Raw{`SUM(value) AS total`}, + ).Group(`numeric`) + + var results []map[string]interface{} + + if err = res.All(&results); err != nil { + t.Fatal(err) + } + + if len(results) != 10 { + t.Fatalf(`Expecting exactly 10 results, this could fail, but it's very unlikely to happen.`) + } } // Attempts to count all rows in our newly defined set. diff --git a/mysql/layout.go b/mysql/layout.go index 21ac5e06..b63c3a41 100644 --- a/mysql/layout.go +++ b/mysql/layout.go @@ -65,6 +65,8 @@ const ( {{.Where}} + {{.GroupBy}} + {{.OrderBy}} {{if .Limit}} @@ -122,5 +124,11 @@ const ( DROP TABLE {{.Table}} ` + mysqlGroupByLayout = ` + {{if .GroupColumns}} + GROUP BY {{.GroupColumns}} + {{end}} + ` + mysqlNull = `NULL` ) diff --git a/mysql/result.go b/mysql/result.go index afe77ec2..a67d5f85 100644 --- a/mysql/result.go +++ b/mysql/result.go @@ -43,6 +43,7 @@ type Result struct { columns sqlgen.Columns where sqlgen.Where orderBy sqlgen.OrderBy + groupBy sqlgen.GroupBy arguments []interface{} } @@ -59,6 +60,7 @@ func (self *Result) setCursor() error { Offset: self.offset, Where: self.where, OrderBy: self.orderBy, + GroupBy: self.groupBy, }, self.arguments...) } return err @@ -83,6 +85,26 @@ func (self *Result) Skip(n uint) db.Result { return self } +// Used to group results that have the same value in the same column or +// columns. +func (self *Result) Group(fields ...interface{}) db.Result { + + groupByColumns := make(sqlgen.GroupBy, 0, len(fields)) + + l := len(fields) + for i := 0; i < l; i++ { + switch value := fields[i].(type) { + // Maybe other types? + default: + groupByColumns = append(groupByColumns, sqlgen.Column{value}) + } + } + + self.groupBy = groupByColumns + + return self +} + // Determines sorting of results according to the provided names. Fields may be // prefixed by - (minus) which means descending order, ascending order would be // used otherwise. -- GitLab