22ba7fdc by astaxie

Merge pull request #1000 from pdf/group_by_queryseter

Add GroupBy to QuerySeter
2 parents 2a0f87e8 3731088b
...@@ -800,6 +800,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi ...@@ -800,6 +800,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
800 tables.parseRelated(qs.related, qs.relDepth) 800 tables.parseRelated(qs.related, qs.relDepth)
801 801
802 where, args := tables.getCondSql(cond, false, tz) 802 where, args := tables.getCondSql(cond, false, tz)
803 groupBy := tables.getGroupSql(qs.groups)
803 orderBy := tables.getOrderSql(qs.orders) 804 orderBy := tables.getOrderSql(qs.orders)
804 limit := tables.getLimitSql(mi, offset, rlimit) 805 limit := tables.getLimitSql(mi, offset, rlimit)
805 join := tables.getJoinSql() 806 join := tables.getJoinSql()
...@@ -812,7 +813,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi ...@@ -812,7 +813,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
812 } 813 }
813 } 814 }
814 815
815 query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit) 816 query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s%s", sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit)
816 817
817 d.ins.ReplaceMarks(&query) 818 d.ins.ReplaceMarks(&query)
818 819
...@@ -936,12 +937,13 @@ func (d *dbBase) Count(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition ...@@ -936,12 +937,13 @@ func (d *dbBase) Count(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition
936 tables.parseRelated(qs.related, qs.relDepth) 937 tables.parseRelated(qs.related, qs.relDepth)
937 938
938 where, args := tables.getCondSql(cond, false, tz) 939 where, args := tables.getCondSql(cond, false, tz)
940 groupBy := tables.getGroupSql(qs.groups)
939 tables.getOrderSql(qs.orders) 941 tables.getOrderSql(qs.orders)
940 join := tables.getJoinSql() 942 join := tables.getJoinSql()
941 943
942 Q := d.ins.TableQuote() 944 Q := d.ins.TableQuote()
943 945
944 query := fmt.Sprintf("SELECT COUNT(*) FROM %s%s%s T0 %s%s", Q, mi.table, Q, join, where) 946 query := fmt.Sprintf("SELECT COUNT(*) FROM %s%s%s T0 %s%s%s", Q, mi.table, Q, join, where, groupBy)
945 947
946 d.ins.ReplaceMarks(&query) 948 d.ins.ReplaceMarks(&query)
947 949
...@@ -1442,13 +1444,14 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond ...@@ -1442,13 +1444,14 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
1442 } 1444 }
1443 1445
1444 where, args := tables.getCondSql(cond, false, tz) 1446 where, args := tables.getCondSql(cond, false, tz)
1447 groupBy := tables.getGroupSql(qs.groups)
1445 orderBy := tables.getOrderSql(qs.orders) 1448 orderBy := tables.getOrderSql(qs.orders)
1446 limit := tables.getLimitSql(mi, qs.offset, qs.limit) 1449 limit := tables.getLimitSql(mi, qs.offset, qs.limit)
1447 join := tables.getJoinSql() 1450 join := tables.getJoinSql()
1448 1451
1449 sels := strings.Join(cols, ", ") 1452 sels := strings.Join(cols, ", ")
1450 1453
1451 query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit) 1454 query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s%s", sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit)
1452 1455
1453 d.ins.ReplaceMarks(&query) 1456 d.ins.ReplaceMarks(&query)
1454 1457
......
...@@ -390,6 +390,30 @@ func (t *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe ...@@ -390,6 +390,30 @@ func (t *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
390 return 390 return
391 } 391 }
392 392
393 // generate group sql.
394 func (t *dbTables) getGroupSql(groups []string) (groupSql string) {
395 if len(groups) == 0 {
396 return
397 }
398
399 Q := t.base.TableQuote()
400
401 groupSqls := make([]string, 0, len(groups))
402 for _, group := range groups {
403 exprs := strings.Split(group, ExprSep)
404
405 index, _, fi, suc := t.parseExprs(t.mi, exprs)
406 if suc == false {
407 panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
408 }
409
410 groupSqls = append(groupSqls, fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q))
411 }
412
413 groupSql = fmt.Sprintf("GROUP BY %s ", strings.Join(groupSqls, ", "))
414 return
415 }
416
393 // generate order sql. 417 // generate order sql.
394 func (t *dbTables) getOrderSql(orders []string) (orderSql string) { 418 func (t *dbTables) getOrderSql(orders []string) (orderSql string) {
395 if len(orders) == 0 { 419 if len(orders) == 0 {
......
...@@ -60,6 +60,7 @@ type querySet struct { ...@@ -60,6 +60,7 @@ type querySet struct {
60 relDepth int 60 relDepth int
61 limit int64 61 limit int64
62 offset int64 62 offset int64
63 groups []string
63 orders []string 64 orders []string
64 orm *orm 65 orm *orm
65 } 66 }
...@@ -105,6 +106,12 @@ func (o querySet) Offset(offset interface{}) QuerySeter { ...@@ -105,6 +106,12 @@ func (o querySet) Offset(offset interface{}) QuerySeter {
105 return &o 106 return &o
106 } 107 }
107 108
109 // add GROUP expression.
110 func (o querySet) GroupBy(exprs ...string) QuerySeter {
111 o.groups = exprs
112 return &o
113 }
114
108 // add ORDER expression. 115 // add ORDER expression.
109 // "column" means ASC, "-column" means DESC. 116 // "column" means ASC, "-column" means DESC.
110 func (o querySet) OrderBy(exprs ...string) QuerySeter { 117 func (o querySet) OrderBy(exprs ...string) QuerySeter {
......
...@@ -845,6 +845,27 @@ func TestOffset(t *testing.T) { ...@@ -845,6 +845,27 @@ func TestOffset(t *testing.T) {
845 throwFail(t, AssertIs(num, 2)) 845 throwFail(t, AssertIs(num, 2))
846 } 846 }
847 847
848 func TestGroupBy(t *testing.T) {
849 var users []*User
850 var maps []Params
851 qs := dORM.QueryTable("user")
852 num, err := qs.GroupBy("is_staff").Filter("user_name", "nobody").Count()
853 throwFail(t, err)
854 throwFail(t, AssertIs(num, 1))
855
856 num, err = qs.GroupBy("is_staff").Count()
857 throwFail(t, err)
858 throwFail(t, AssertIs(num, 2))
859
860 num, err = qs.GroupBy("is_staff").Values(&maps)
861 throwFail(t, err)
862 throwFail(t, AssertIs(num, 2))
863
864 num, err = qs.GroupBy("profile__age").Filter("user_name", "astaxie").All(&users)
865 throwFail(t, err)
866 throwFail(t, AssertIs(num, 1))
867 }
868
848 func TestOrderBy(t *testing.T) { 869 func TestOrderBy(t *testing.T) {
849 qs := dORM.QueryTable("user") 870 qs := dORM.QueryTable("user")
850 num, err := qs.OrderBy("-status").Filter("user_name", "nobody").Count() 871 num, err := qs.OrderBy("-status").Filter("user_name", "nobody").Count()
......
...@@ -67,6 +67,7 @@ type QuerySeter interface { ...@@ -67,6 +67,7 @@ type QuerySeter interface {
67 SetCond(*Condition) QuerySeter 67 SetCond(*Condition) QuerySeter
68 Limit(interface{}, ...interface{}) QuerySeter 68 Limit(interface{}, ...interface{}) QuerySeter
69 Offset(interface{}) QuerySeter 69 Offset(interface{}) QuerySeter
70 GroupBy(...string) QuerySeter
70 OrderBy(...string) QuerySeter 71 OrderBy(...string) QuerySeter
71 RelatedSel(...interface{}) QuerySeter 72 RelatedSel(...interface{}) QuerySeter
72 Count() (int64, error) 73 Count() (int64, error)
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!