forked from mirror/gorm
Add method Group, Having
This commit is contained in:
parent
282b5d872c
commit
b41f2957fb
22
README.md
22
README.md
|
@ -12,8 +12,8 @@ Yet Another ORM library for Go, aims for developer friendly
|
|||
* Transaction
|
||||
* Logger Support
|
||||
* Bind struct with tag
|
||||
* Iteration Support via sql.Rows
|
||||
* sql.Scanner
|
||||
* Iteration Support via [Rows](#row--rows)
|
||||
* sql.Scanner support
|
||||
* Every feature comes with tests
|
||||
* Convention Over Configuration
|
||||
* Developer Friendly
|
||||
|
@ -695,6 +695,20 @@ for rows.Next() {
|
|||
}
|
||||
```
|
||||
|
||||
## Group & Having
|
||||
|
||||
```go
|
||||
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
|
||||
for rows.Next() {
|
||||
...
|
||||
}
|
||||
|
||||
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
|
||||
for rows.Next() {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Run Raw SQl
|
||||
|
||||
```go
|
||||
|
@ -762,9 +776,7 @@ db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111
|
|||
```
|
||||
|
||||
## TODO
|
||||
* Cache Stmt for performance
|
||||
* Join, Having, Group, Includes
|
||||
* Scopes, Valiations
|
||||
* Scopes, Valiations, Includes, Joins, UpdateColumn/Columns
|
||||
* AlertColumn, DropColumn, AddIndex, RemoveIndex
|
||||
|
||||
# Author
|
||||
|
|
27
do.go
27
do.go
|
@ -342,11 +342,13 @@ func (s *Do) related(value interface{}, foreign_keys ...string) *Do {
|
|||
}
|
||||
|
||||
func (s *Do) row() *sql.Row {
|
||||
defer s.trace(time.Now())
|
||||
s.prepareQuerySql()
|
||||
return s.db.db.QueryRow(s.sql, s.sqlVars...)
|
||||
}
|
||||
|
||||
func (s *Do) rows() (*sql.Rows, error) {
|
||||
defer s.trace(time.Now())
|
||||
s.prepareQuerySql()
|
||||
return s.db.db.Query(s.sql, s.sqlVars...)
|
||||
}
|
||||
|
@ -409,15 +411,12 @@ func (s *Do) query() *Do {
|
|||
}
|
||||
|
||||
func (s *Do) count(value interface{}) *Do {
|
||||
defer s.trace(time.Now())
|
||||
s.search = s.search.clone().selects("count(*)")
|
||||
s.err(s.row().Scan(value))
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Do) pluck(column string, value interface{}) *Do {
|
||||
defer s.trace(time.Now())
|
||||
|
||||
dest_out := reflect.Indirect(reflect.ValueOf(value))
|
||||
s.search = s.search.clone().selects(column)
|
||||
if dest_out.Kind() != reflect.Slice {
|
||||
|
@ -634,8 +633,28 @@ func (s *Do) offsetSql() string {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Do) groupSql() string {
|
||||
if len(s.search.groupStr) == 0 {
|
||||
return ""
|
||||
} else {
|
||||
return " GROUP BY " + s.search.groupStr
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Do) havingSql() string {
|
||||
if s.search.havingClause == nil {
|
||||
return ""
|
||||
} else {
|
||||
return " HAVING " + s.buildWhereCondition(s.search.havingClause)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Do) joinsSql() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *Do) combinedSql() string {
|
||||
return s.whereSql() + s.orderSql() + s.limitSql() + s.offsetSql()
|
||||
return s.whereSql() + s.orderSql() + s.limitSql() + s.offsetSql() + s.groupSql() + s.havingSql()
|
||||
}
|
||||
|
||||
func (s *Do) createTable() *Do {
|
||||
|
|
36
gorm_test.go
36
gorm_test.go
|
@ -1391,6 +1391,42 @@ func TestRows(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGroup(t *testing.T) {
|
||||
rows, err := db.Select("name").Table("users").Group("name").Rows()
|
||||
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var name string
|
||||
rows.Scan(&name)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Should not raise any error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHaving(t *testing.T) {
|
||||
rows, err := db.Debug().Select("name, count(*) as total").Table("users").Group("name").Having("name IN (?)", []string{"2", "3"}).Rows()
|
||||
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var name string
|
||||
var total int64
|
||||
rows.Scan(&name, &total)
|
||||
|
||||
if name == "2" && total != 1 {
|
||||
t.Errorf("Should have one user having name 2", total)
|
||||
}
|
||||
if name == "3" && total != 2 {
|
||||
t.Errorf("Should have two users having name 3", total)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Should not raise any error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGorm(b *testing.B) {
|
||||
b.N = 2000
|
||||
for x := 0; x < b.N; x++ {
|
||||
|
|
16
main.go
16
main.go
|
@ -77,6 +77,22 @@ func (s *DB) Select(value interface{}) *DB {
|
|||
return s.clone().search.selects(value).db
|
||||
}
|
||||
|
||||
func (s *DB) Group(query string) *DB {
|
||||
return s.clone().search.group(query).db
|
||||
}
|
||||
|
||||
func (s *DB) Having(query string, values ...interface{}) *DB {
|
||||
return s.clone().search.having(query, values...).db
|
||||
}
|
||||
|
||||
func (s *DB) Joins(query string) *DB {
|
||||
return s.clone().search.joins(query).db
|
||||
}
|
||||
|
||||
func (s *DB) Includes(value interface{}) *DB {
|
||||
return s.clone().search.includes(value).db
|
||||
}
|
||||
|
||||
func (s *DB) Unscoped() *DB {
|
||||
return s.clone().search.unscoped().db
|
||||
}
|
||||
|
|
71
search.go
71
search.go
|
@ -7,33 +7,39 @@ import (
|
|||
)
|
||||
|
||||
type search struct {
|
||||
db *DB
|
||||
whereClause []map[string]interface{}
|
||||
orClause []map[string]interface{}
|
||||
notClause []map[string]interface{}
|
||||
initAttrs []interface{}
|
||||
assignAttrs []interface{}
|
||||
orders []string
|
||||
selectStr string
|
||||
offsetStr string
|
||||
limitStr string
|
||||
tableName string
|
||||
unscope bool
|
||||
db *DB
|
||||
whereClause []map[string]interface{}
|
||||
orClause []map[string]interface{}
|
||||
notClause []map[string]interface{}
|
||||
initAttrs []interface{}
|
||||
assignAttrs []interface{}
|
||||
havingClause map[string]interface{}
|
||||
orders []string
|
||||
joinsStr string
|
||||
selectStr string
|
||||
offsetStr string
|
||||
limitStr string
|
||||
groupStr string
|
||||
tableName string
|
||||
unscope bool
|
||||
}
|
||||
|
||||
func (s *search) clone() *search {
|
||||
return &search{
|
||||
whereClause: s.whereClause,
|
||||
orClause: s.orClause,
|
||||
notClause: s.notClause,
|
||||
initAttrs: s.initAttrs,
|
||||
assignAttrs: s.assignAttrs,
|
||||
orders: s.orders,
|
||||
selectStr: s.selectStr,
|
||||
offsetStr: s.offsetStr,
|
||||
limitStr: s.limitStr,
|
||||
unscope: s.unscope,
|
||||
tableName: s.tableName,
|
||||
whereClause: s.whereClause,
|
||||
orClause: s.orClause,
|
||||
notClause: s.notClause,
|
||||
initAttrs: s.initAttrs,
|
||||
assignAttrs: s.assignAttrs,
|
||||
havingClause: s.havingClause,
|
||||
orders: s.orders,
|
||||
selectStr: s.selectStr,
|
||||
offsetStr: s.offsetStr,
|
||||
limitStr: s.limitStr,
|
||||
unscope: s.unscope,
|
||||
groupStr: s.groupStr,
|
||||
joinsStr: s.joinsStr,
|
||||
tableName: s.tableName,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +92,25 @@ func (s *search) offset(value interface{}) *search {
|
|||
return s
|
||||
}
|
||||
|
||||
func (s *search) group(query string) *search {
|
||||
s.groupStr = s.getInterfaceAsSql(query)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *search) having(query string, values ...interface{}) *search {
|
||||
s.havingClause = map[string]interface{}{"query": query, "args": values}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *search) includes(value interface{}) *search {
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *search) joins(query string) *search {
|
||||
s.joinsStr = query
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *search) unscoped() *search {
|
||||
s.unscope = true
|
||||
return s
|
||||
|
|
Loading…
Reference in New Issue