dialect/sql/sqlgraph: ignore ORDER BY clauses in COUNT queries (#3226)

This commit is contained in:
Ariel Mashraki
2023-01-10 14:03:29 +02:00
committed by GitHub
parent 27a9db528b
commit fa1cf83fdd
4 changed files with 105 additions and 83 deletions

View File

@@ -2744,6 +2744,12 @@ func (s *Selector) OrderExpr(exprs ...Querier) *Selector {
return s
}
// ClearOrder clears the ORDER BY clause to be empty.
func (s *Selector) ClearOrder() *Selector {
s.order = nil
return s
}
// GroupBy appends the `GROUP BY` clause to the `SELECT` statement.
func (s *Selector) GroupBy(columns ...string) *Selector {
s.group = append(s.group, columns...)

View File

@@ -1681,6 +1681,17 @@ func TestSelector_OrderByExpr(t *testing.T) {
require.Equal(t, []any{28, 1, 2}, args)
}
func TestSelector_ClearOrder(t *testing.T) {
query, args := Select("*").
From(Table("users")).
OrderBy("name").
ClearOrder().
OrderBy("id").
Query()
require.Equal(t, "SELECT * FROM `users` ORDER BY `id`", query)
require.Empty(t, args)
}
func TestSelector_SelectExpr(t *testing.T) {
query, args := SelectExpr(
Expr("?", "a"),
@@ -1716,93 +1727,93 @@ func TestSelector_SelectExpr(t *testing.T) {
}
func TestSelector_Union(t *testing.T) {
query, args := Dialect(dialect.Postgres).
Select("*").
From(Table("users")).
Where(EQ("active", true)).
Union(
Select("*").
From(Table("old_users1")).
Where(
And(
EQ("is_active", true),
GT("age", 20),
),
),
).
UnionAll(
Select("*").
From(Table("old_users2")).
Where(
And(
EQ("is_active", "true"),
LT("age", 18),
),
),
).
Query()
require.Equal(t, `SELECT * FROM "users" WHERE "active" UNION SELECT * FROM "old_users1" WHERE "is_active" AND "age" > $1 UNION ALL SELECT * FROM "old_users2" WHERE "is_active" = $2 AND "age" < $3`, query)
require.Equal(t, []any{20, "true", 18}, args)
query, args := Dialect(dialect.Postgres).
Select("*").
From(Table("users")).
Where(EQ("active", true)).
Union(
Select("*").
From(Table("old_users1")).
Where(
And(
EQ("is_active", true),
GT("age", 20),
),
),
).
UnionAll(
Select("*").
From(Table("old_users2")).
Where(
And(
EQ("is_active", "true"),
LT("age", 18),
),
),
).
Query()
require.Equal(t, `SELECT * FROM "users" WHERE "active" UNION SELECT * FROM "old_users1" WHERE "is_active" AND "age" > $1 UNION ALL SELECT * FROM "old_users2" WHERE "is_active" = $2 AND "age" < $3`, query)
require.Equal(t, []any{20, "true", 18}, args)
}
func TestSelector_Except(t *testing.T) {
query, args := Dialect(dialect.Postgres).
Select("*").
From(Table("users")).
Where(EQ("active", true)).
Except(
Select("*").
From(Table("old_users1")).
Where(
And(
EQ("is_active", true),
GT("age", 20),
),
),
).
ExceptAll(
Select("*").
From(Table("old_users2")).
Where(
And(
EQ("is_active", "true"),
LT("age", 18),
),
),
).
Query()
require.Equal(t, `SELECT * FROM "users" WHERE "active" EXCEPT SELECT * FROM "old_users1" WHERE "is_active" AND "age" > $1 EXCEPT ALL SELECT * FROM "old_users2" WHERE "is_active" = $2 AND "age" < $3`, query)
require.Equal(t, []any{20, "true", 18}, args)
query, args := Dialect(dialect.Postgres).
Select("*").
From(Table("users")).
Where(EQ("active", true)).
Except(
Select("*").
From(Table("old_users1")).
Where(
And(
EQ("is_active", true),
GT("age", 20),
),
),
).
ExceptAll(
Select("*").
From(Table("old_users2")).
Where(
And(
EQ("is_active", "true"),
LT("age", 18),
),
),
).
Query()
require.Equal(t, `SELECT * FROM "users" WHERE "active" EXCEPT SELECT * FROM "old_users1" WHERE "is_active" AND "age" > $1 EXCEPT ALL SELECT * FROM "old_users2" WHERE "is_active" = $2 AND "age" < $3`, query)
require.Equal(t, []any{20, "true", 18}, args)
}
func TestSelector_Intersect(t *testing.T) {
query, args := Dialect(dialect.Postgres).
Select("*").
From(Table("users")).
Where(EQ("active", true)).
Intersect(
Select("*").
From(Table("old_users1")).
Where(
And(
EQ("is_active", true),
GT("age", 20),
),
),
).
IntersectAll(
Select("*").
From(Table("old_users2")).
Where(
And(
EQ("is_active", "true"),
LT("age", 18),
),
),
).
Query()
require.Equal(t, `SELECT * FROM "users" WHERE "active" INTERSECT SELECT * FROM "old_users1" WHERE "is_active" AND "age" > $1 INTERSECT ALL SELECT * FROM "old_users2" WHERE "is_active" = $2 AND "age" < $3`, query)
require.Equal(t, []any{20, "true", 18}, args)
query, args := Dialect(dialect.Postgres).
Select("*").
From(Table("users")).
Where(EQ("active", true)).
Intersect(
Select("*").
From(Table("old_users1")).
Where(
And(
EQ("is_active", true),
GT("age", 20),
),
),
).
IntersectAll(
Select("*").
From(Table("old_users2")).
Where(
And(
EQ("is_active", "true"),
LT("age", 18),
),
),
).
Query()
require.Equal(t, `SELECT * FROM "users" WHERE "active" INTERSECT SELECT * FROM "old_users1" WHERE "is_active" AND "age" > $1 INTERSECT ALL SELECT * FROM "old_users2" WHERE "is_active" = $2 AND "age" < $3`, query)
require.Equal(t, []any{20, "true", 18}, args)
}
func TestSelector_SetOperatorWithRecursive(t *testing.T) {

View File

@@ -645,6 +645,11 @@ func (q *query) count(ctx context.Context, drv dialect.Driver) (int, error) {
if err != nil {
return 0, err
}
// Remove any ORDER BY clauses present in the COUNT query as
// they are not allowed in some databases, such as PostgreSQL.
if q.Order != nil {
selector.ClearOrder()
}
// If no columns were selected in count,
// the default selection is by node ids.
columns := q.Node.Columns

View File

@@ -2198,11 +2198,11 @@ func TestQueryNodes(t *testing.T) {
AddRow(1, 10, nil, nil, nil).
AddRow(2, 20, "", 0, 0).
AddRow(3, 30, "a8m", 1, 1))
mock.ExpectQuery(escape("SELECT COUNT(DISTINCT `users`.`id`) FROM `users` WHERE `age` < ? ORDER BY `id` LIMIT 3 OFFSET 4 FOR UPDATE NOWAIT")).
mock.ExpectQuery(escape("SELECT COUNT(DISTINCT `users`.`id`) FROM `users` WHERE `age` < ? LIMIT 3 OFFSET 4 FOR UPDATE NOWAIT")).
WithArgs(40).
WillReturnRows(sqlmock.NewRows([]string{"COUNT"}).
AddRow(3))
mock.ExpectQuery(escape("SELECT COUNT(DISTINCT `users`.`name`) FROM `users` WHERE `age` < ? ORDER BY `id` LIMIT 3 OFFSET 4 FOR UPDATE NOWAIT")).
mock.ExpectQuery(escape("SELECT COUNT(DISTINCT `users`.`name`) FROM `users` WHERE `age` < ? LIMIT 3 OFFSET 4 FOR UPDATE NOWAIT")).
WithArgs(40).
WillReturnRows(sqlmock.NewRows([]string{"COUNT"}).
AddRow(3))