From c50f87cb9b9c252ffc85449780dce7996fe4035e 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:24:37 -0500 Subject: [PATCH] PostgreSQL: Adding support for db.Result.Group(). --- postgresql/_dumps/structs.sql | 8 +++++ postgresql/database.go | 1 + postgresql/database_test.go | 55 +++++++++++++++++++++++++++++++++++ postgresql/layout.go | 8 +++++ postgresql/result.go | 23 ++++++++++++++- 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/postgresql/_dumps/structs.sql b/postgresql/_dumps/structs.sql index 6da53ad6..8e0f0551 100644 --- a/postgresql/_dumps/structs.sql +++ b/postgresql/_dumps/structs.sql @@ -44,3 +44,11 @@ CREATE TABLE data_types ( _date timestamp without time zone, _time time without time zone ); + +DROP TABLE IF EXISTS stats_test; + +CREATE TABLE stats_test ( + id serial primary key, + numeric integer, + value integer +); diff --git a/postgresql/database.go b/postgresql/database.go index 77231477..7e56921a 100644 --- a/postgresql/database.go +++ b/postgresql/database.go @@ -108,6 +108,7 @@ func init() { pgsqlDropDatabaseLayout, pgsqlDropTableLayout, pgsqlSelectCountLayout, + pgsqlGroupByLayout, } db.Register(Adapter, &source{}) diff --git a/postgresql/database_test.go b/postgresql/database_test.go index 09e6a740..578fb222 100644 --- a/postgresql/database_test.go +++ b/postgresql/database_test.go @@ -31,6 +31,7 @@ package postgresql import ( "database/sql" "flag" + "math/rand" "os" "reflect" "strings" @@ -678,7 +679,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 delete previously added rows. diff --git a/postgresql/layout.go b/postgresql/layout.go index a0c326b5..7f4d62ff 100644 --- a/postgresql/layout.go +++ b/postgresql/layout.go @@ -65,6 +65,8 @@ const ( {{.Where}} + {{.GroupBy}} + {{.OrderBy}} {{if .Limit}} @@ -122,5 +124,11 @@ const ( DROP TABLE {{.Table}} ` + pgsqlGroupByLayout = ` + {{if .GroupColumns}} + GROUP BY {{.GroupColumns}} + {{end}} + ` + psqlNull = `NULL` ) diff --git a/postgresql/result.go b/postgresql/result.go index 24b3f16b..37f1523a 100644 --- a/postgresql/result.go +++ b/postgresql/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,25 @@ 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. @@ -243,7 +264,7 @@ func (self *result) Close() error { return err } -// Counting the elements that will be returned. +// Counts the elements within the main conditions of the set. func (self *result) Count() (uint64, error) { var count counter_t -- GitLab