diff --git a/orm/db.go b/orm/db.go index cefd5dfc..1803db4f 100644 --- a/orm/db.go +++ b/orm/db.go @@ -802,6 +802,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi tables.parseRelated(qs.related, qs.relDepth) where, args := tables.getCondSql(cond, false, tz) + groupBy := tables.getGroupSql(qs.groups) orderBy := tables.getOrderSql(qs.orders) limit := tables.getLimitSql(mi, offset, rlimit) join := tables.getJoinSql() @@ -818,7 +819,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi if qs.distinct { sqlSelect += " DISTINCT" } - query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s", sqlSelect, sels, Q, mi.table, Q, join, where, orderBy, limit) + query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s%s", sqlSelect, sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit) d.ins.ReplaceMarks(&query) @@ -1448,13 +1449,14 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond } where, args := tables.getCondSql(cond, false, tz) + groupBy := tables.getGroupSql(qs.groups) orderBy := tables.getOrderSql(qs.orders) limit := tables.getLimitSql(mi, qs.offset, qs.limit) join := tables.getJoinSql() sels := strings.Join(cols, ", ") - query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit) + 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) d.ins.ReplaceMarks(&query) diff --git a/orm/db_tables.go b/orm/db_tables.go index a9aa10ab..245be891 100644 --- a/orm/db_tables.go +++ b/orm/db_tables.go @@ -390,6 +390,30 @@ func (t *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe return } +// generate group sql. +func (t *dbTables) getGroupSql(groups []string) (groupSql string) { + if len(groups) == 0 { + return + } + + Q := t.base.TableQuote() + + groupSqls := make([]string, 0, len(groups)) + for _, group := range groups { + exprs := strings.Split(group, ExprSep) + + index, _, fi, suc := t.parseExprs(t.mi, exprs) + if suc == false { + panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep))) + } + + groupSqls = append(groupSqls, fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q)) + } + + groupSql = fmt.Sprintf("GROUP BY %s ", strings.Join(groupSqls, ", ")) + return +} + // generate order sql. func (t *dbTables) getOrderSql(orders []string) (orderSql string) { if len(orders) == 0 { diff --git a/orm/orm_queryset.go b/orm/orm_queryset.go index ea236964..af16b694 100644 --- a/orm/orm_queryset.go +++ b/orm/orm_queryset.go @@ -60,6 +60,7 @@ type querySet struct { relDepth int limit int64 offset int64 + groups []string orders []string distinct bool orm *orm @@ -106,6 +107,12 @@ func (o querySet) Offset(offset interface{}) QuerySeter { return &o } +// add GROUP expression +func (o querySet) GroupBy(exprs ...string) QuerySeter { + o.groups = exprs + return &o +} + // add ORDER expression. // "column" means ASC, "-column" means DESC. func (o querySet) OrderBy(exprs ...string) QuerySeter { diff --git a/orm/types.go b/orm/types.go index 4347e46f..95a3fee3 100644 --- a/orm/types.go +++ b/orm/types.go @@ -66,6 +66,7 @@ type QuerySeter interface { SetCond(*Condition) QuerySeter Limit(interface{}, ...interface{}) QuerySeter Offset(interface{}) QuerySeter + GroupBy(...string) QuerySeter OrderBy(...string) QuerySeter Distinct() QuerySeter RelatedSel(...interface{}) QuerySeter