Skip to content

Commit 409cb7c

Browse files
committed
Fix findandcount or count with groupby (#1915)
Fix #1022, #1221, #1726, #1836, #1910. Reviewed-on: https://gitea.com/xorm/xorm/pulls/1915 Co-authored-by: Lunny Xiao <[email protected]> Co-committed-by: Lunny Xiao <[email protected]>
1 parent 136cf1a commit 409cb7c

File tree

4 files changed

+214
-142
lines changed

4 files changed

+214
-142
lines changed

integrations/session_count_test.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright 2021 The Xorm Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package integrations
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"xorm.io/builder"
12+
)
13+
14+
func TestCount(t *testing.T) {
15+
assert.NoError(t, PrepareEngine())
16+
17+
type UserinfoCount struct {
18+
Departname string
19+
}
20+
assert.NoError(t, testEngine.Sync2(new(UserinfoCount)))
21+
22+
colName := testEngine.GetColumnMapper().Obj2Table("Departname")
23+
var cond builder.Cond = builder.Eq{
24+
"`" + colName + "`": "dev",
25+
}
26+
27+
total, err := testEngine.Where(cond).Count(new(UserinfoCount))
28+
assert.NoError(t, err)
29+
assert.EqualValues(t, 0, total)
30+
31+
cnt, err := testEngine.Insert(&UserinfoCount{
32+
Departname: "dev",
33+
})
34+
assert.NoError(t, err)
35+
assert.EqualValues(t, 1, cnt)
36+
37+
total, err = testEngine.Where(cond).Count(new(UserinfoCount))
38+
assert.NoError(t, err)
39+
assert.EqualValues(t, 1, total)
40+
41+
total, err = testEngine.Where(cond).Table("userinfo_count").Count()
42+
assert.NoError(t, err)
43+
assert.EqualValues(t, 1, total)
44+
45+
total, err = testEngine.Table("userinfo_count").Count()
46+
assert.NoError(t, err)
47+
assert.EqualValues(t, 1, total)
48+
}
49+
50+
func TestSQLCount(t *testing.T) {
51+
assert.NoError(t, PrepareEngine())
52+
53+
type UserinfoCount2 struct {
54+
Id int64
55+
Departname string
56+
}
57+
58+
type UserinfoBooks struct {
59+
Id int64
60+
Pid int64
61+
IsOpen bool
62+
}
63+
64+
assertSync(t, new(UserinfoCount2), new(UserinfoBooks))
65+
66+
total, err := testEngine.SQL("SELECT count(id) FROM " + testEngine.TableName("userinfo_count2", true)).
67+
Count()
68+
assert.NoError(t, err)
69+
assert.EqualValues(t, 0, total)
70+
}
71+
72+
func TestCountWithOthers(t *testing.T) {
73+
assert.NoError(t, PrepareEngine())
74+
75+
type CountWithOthers struct {
76+
Id int64
77+
Name string
78+
}
79+
80+
assertSync(t, new(CountWithOthers))
81+
82+
_, err := testEngine.Insert(&CountWithOthers{
83+
Name: "orderby",
84+
})
85+
assert.NoError(t, err)
86+
87+
_, err = testEngine.Insert(&CountWithOthers{
88+
Name: "limit",
89+
})
90+
assert.NoError(t, err)
91+
92+
total, err := testEngine.OrderBy("id desc").Limit(1).Count(new(CountWithOthers))
93+
assert.NoError(t, err)
94+
assert.EqualValues(t, 2, total)
95+
}
96+
97+
type CountWithTableName struct {
98+
Id int64
99+
Name string
100+
}
101+
102+
func (CountWithTableName) TableName() string {
103+
return "count_with_table_name1"
104+
}
105+
106+
func TestWithTableName(t *testing.T) {
107+
assert.NoError(t, PrepareEngine())
108+
109+
assertSync(t, new(CountWithTableName))
110+
111+
_, err := testEngine.Insert(&CountWithTableName{
112+
Name: "orderby",
113+
})
114+
assert.NoError(t, err)
115+
116+
_, err = testEngine.Insert(CountWithTableName{
117+
Name: "limit",
118+
})
119+
assert.NoError(t, err)
120+
121+
total, err := testEngine.OrderBy("id desc").Count(new(CountWithTableName))
122+
assert.NoError(t, err)
123+
assert.EqualValues(t, 2, total)
124+
125+
total, err = testEngine.OrderBy("id desc").Count(CountWithTableName{})
126+
assert.NoError(t, err)
127+
assert.EqualValues(t, 2, total)
128+
}
129+
130+
func TestCountWithSelectCols(t *testing.T) {
131+
assert.NoError(t, PrepareEngine())
132+
133+
assertSync(t, new(CountWithTableName))
134+
135+
_, err := testEngine.Insert(&CountWithTableName{
136+
Name: "orderby",
137+
})
138+
assert.NoError(t, err)
139+
140+
_, err = testEngine.Insert(CountWithTableName{
141+
Name: "limit",
142+
})
143+
assert.NoError(t, err)
144+
145+
total, err := testEngine.Cols("id").Count(new(CountWithTableName))
146+
assert.NoError(t, err)
147+
assert.EqualValues(t, 2, total)
148+
149+
total, err = testEngine.Select("count(id)").Count(CountWithTableName{})
150+
assert.NoError(t, err)
151+
assert.EqualValues(t, 2, total)
152+
}
153+
154+
func TestCountWithGroupBy(t *testing.T) {
155+
assert.NoError(t, PrepareEngine())
156+
157+
assertSync(t, new(CountWithTableName))
158+
159+
_, err := testEngine.Insert(&CountWithTableName{
160+
Name: "1",
161+
})
162+
assert.NoError(t, err)
163+
164+
_, err = testEngine.Insert(CountWithTableName{
165+
Name: "2",
166+
})
167+
assert.NoError(t, err)
168+
169+
cnt, err := testEngine.GroupBy("name").Count(new(CountWithTableName))
170+
assert.NoError(t, err)
171+
assert.EqualValues(t, 2, cnt)
172+
}

integrations/session_find_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,36 @@ func TestFindAndCountWithTableName(t *testing.T) {
678678
assert.EqualValues(t, 1, cnt)
679679
}
680680

681+
func TestFindAndCountWithGroupBy(t *testing.T) {
682+
assert.NoError(t, PrepareEngine())
683+
684+
type FindAndCountWithGroupBy struct {
685+
Id int64
686+
Age int `xorm:"index"`
687+
Name string
688+
}
689+
690+
assert.NoError(t, testEngine.Sync2(new(FindAndCountWithGroupBy)))
691+
692+
_, err := testEngine.Insert([]FindAndCountWithGroupBy{
693+
{
694+
Name: "test1",
695+
Age: 10,
696+
},
697+
{
698+
Name: "test2",
699+
Age: 20,
700+
},
701+
})
702+
assert.NoError(t, err)
703+
704+
var results []FindAndCountWithGroupBy
705+
cnt, err := testEngine.GroupBy("age").FindAndCount(&results)
706+
assert.NoError(t, err)
707+
assert.EqualValues(t, 2, cnt)
708+
assert.EqualValues(t, 2, len(results))
709+
}
710+
681711
type FindMapDevice struct {
682712
Deviceid string `xorm:"pk"`
683713
Status int
Lines changed: 0 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"testing"
1111

1212
"github.com/stretchr/testify/assert"
13-
"xorm.io/builder"
1413
)
1514

1615
func isFloatEq(i, j float64, precision int) bool {
@@ -158,143 +157,3 @@ func TestSumCustomColumn(t *testing.T) {
158157
assert.NoError(t, err)
159158
assert.EqualValues(t, 3, int(sumInt))
160159
}
161-
162-
func TestCount(t *testing.T) {
163-
assert.NoError(t, PrepareEngine())
164-
165-
type UserinfoCount struct {
166-
Departname string
167-
}
168-
assert.NoError(t, testEngine.Sync2(new(UserinfoCount)))
169-
170-
colName := testEngine.GetColumnMapper().Obj2Table("Departname")
171-
var cond builder.Cond = builder.Eq{
172-
"`" + colName + "`": "dev",
173-
}
174-
175-
total, err := testEngine.Where(cond).Count(new(UserinfoCount))
176-
assert.NoError(t, err)
177-
assert.EqualValues(t, 0, total)
178-
179-
cnt, err := testEngine.Insert(&UserinfoCount{
180-
Departname: "dev",
181-
})
182-
assert.NoError(t, err)
183-
assert.EqualValues(t, 1, cnt)
184-
185-
total, err = testEngine.Where(cond).Count(new(UserinfoCount))
186-
assert.NoError(t, err)
187-
assert.EqualValues(t, 1, total)
188-
189-
total, err = testEngine.Where(cond).Table("userinfo_count").Count()
190-
assert.NoError(t, err)
191-
assert.EqualValues(t, 1, total)
192-
193-
total, err = testEngine.Table("userinfo_count").Count()
194-
assert.NoError(t, err)
195-
assert.EqualValues(t, 1, total)
196-
}
197-
198-
func TestSQLCount(t *testing.T) {
199-
assert.NoError(t, PrepareEngine())
200-
201-
type UserinfoCount2 struct {
202-
Id int64
203-
Departname string
204-
}
205-
206-
type UserinfoBooks struct {
207-
Id int64
208-
Pid int64
209-
IsOpen bool
210-
}
211-
212-
assertSync(t, new(UserinfoCount2), new(UserinfoBooks))
213-
214-
total, err := testEngine.SQL("SELECT count(id) FROM " + testEngine.TableName("userinfo_count2", true)).
215-
Count()
216-
assert.NoError(t, err)
217-
assert.EqualValues(t, 0, total)
218-
}
219-
220-
func TestCountWithOthers(t *testing.T) {
221-
assert.NoError(t, PrepareEngine())
222-
223-
type CountWithOthers struct {
224-
Id int64
225-
Name string
226-
}
227-
228-
assertSync(t, new(CountWithOthers))
229-
230-
_, err := testEngine.Insert(&CountWithOthers{
231-
Name: "orderby",
232-
})
233-
assert.NoError(t, err)
234-
235-
_, err = testEngine.Insert(&CountWithOthers{
236-
Name: "limit",
237-
})
238-
assert.NoError(t, err)
239-
240-
total, err := testEngine.OrderBy("id desc").Limit(1).Count(new(CountWithOthers))
241-
assert.NoError(t, err)
242-
assert.EqualValues(t, 2, total)
243-
}
244-
245-
type CountWithTableName struct {
246-
Id int64
247-
Name string
248-
}
249-
250-
func (CountWithTableName) TableName() string {
251-
return "count_with_table_name1"
252-
}
253-
254-
func TestWithTableName(t *testing.T) {
255-
assert.NoError(t, PrepareEngine())
256-
257-
assertSync(t, new(CountWithTableName))
258-
259-
_, err := testEngine.Insert(&CountWithTableName{
260-
Name: "orderby",
261-
})
262-
assert.NoError(t, err)
263-
264-
_, err = testEngine.Insert(CountWithTableName{
265-
Name: "limit",
266-
})
267-
assert.NoError(t, err)
268-
269-
total, err := testEngine.OrderBy("id desc").Count(new(CountWithTableName))
270-
assert.NoError(t, err)
271-
assert.EqualValues(t, 2, total)
272-
273-
total, err = testEngine.OrderBy("id desc").Count(CountWithTableName{})
274-
assert.NoError(t, err)
275-
assert.EqualValues(t, 2, total)
276-
}
277-
278-
func TestCountWithSelectCols(t *testing.T) {
279-
assert.NoError(t, PrepareEngine())
280-
281-
assertSync(t, new(CountWithTableName))
282-
283-
_, err := testEngine.Insert(&CountWithTableName{
284-
Name: "orderby",
285-
})
286-
assert.NoError(t, err)
287-
288-
_, err = testEngine.Insert(CountWithTableName{
289-
Name: "limit",
290-
})
291-
assert.NoError(t, err)
292-
293-
total, err := testEngine.Cols("id").Count(new(CountWithTableName))
294-
assert.NoError(t, err)
295-
assert.EqualValues(t, 2, total)
296-
297-
total, err = testEngine.Select("count(id)").Count(CountWithTableName{})
298-
assert.NoError(t, err)
299-
assert.EqualValues(t, 2, total)
300-
}

internal/statements/query.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,22 @@ func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interfa
181181
selectSQL = "count(*)"
182182
}
183183
}
184-
sqlStr, condArgs, err := statement.genSelectSQL(selectSQL, false, false)
184+
var subQuerySelect string
185+
if statement.GroupByStr != "" {
186+
subQuerySelect = statement.GroupByStr
187+
} else {
188+
subQuerySelect = selectSQL
189+
}
190+
191+
sqlStr, condArgs, err := statement.genSelectSQL(subQuerySelect, false, false)
185192
if err != nil {
186193
return "", nil, err
187194
}
188195

196+
if statement.GroupByStr != "" {
197+
sqlStr = fmt.Sprintf("SELECT %s FROM (%s) sub", selectSQL, sqlStr)
198+
}
199+
189200
return sqlStr, append(statement.joinArgs, condArgs...), nil
190201
}
191202

0 commit comments

Comments
 (0)