dialect/sql: support for order by expressions in window functions (#2442)

This commit is contained in:
Ariel Mashraki
2022-04-01 21:31:00 +03:00
committed by GitHub
parent 110d0d138a
commit 345d3d1783
20 changed files with 39 additions and 31 deletions

View File

@@ -2711,7 +2711,7 @@ func (s *Selector) Query() (string, []interface{}) {
s.joinUnion(&b)
}
if len(s.order) > 0 {
s.joinOrder(&b)
joinOrder(s.order, &b)
}
if s.limit != nil {
b.WriteString(" LIMIT ")
@@ -2773,17 +2773,17 @@ func (s *Selector) joinUnion(b *Builder) {
}
}
func (s *Selector) joinOrder(b *Builder) {
func joinOrder(order []interface{}, b *Builder) {
b.WriteString(" ORDER BY ")
for i := range s.order {
for i := range order {
if i > 0 {
b.Comma()
}
switch order := s.order[i].(type) {
switch r := order[i].(type) {
case string:
b.Ident(order)
b.Ident(r)
case Querier:
b.Join(order)
b.Join(r)
}
}
}
@@ -2908,7 +2908,7 @@ type WindowBuilder struct {
Builder
fn string // e.g. ROW_NUMBER(), RANK().
partition func(*Builder)
order func(*Builder)
order []interface{}
}
// RowNumber returns a new window clause with the ROW_NUMBER() as a function.
@@ -2938,8 +2938,17 @@ func (w *WindowBuilder) PartitionExpr(x Querier) *WindowBuilder {
// OrderBy indicates how to sort rows in each partition.
func (w *WindowBuilder) OrderBy(columns ...string) *WindowBuilder {
w.order = func(b *Builder) {
b.IdentComma(columns...)
for i := range columns {
w.order = append(w.order, columns[i])
}
return w
}
// OrderExpr appends the `ORDER BY` clause to the window
// partition with custom list of expressions.
func (w *WindowBuilder) OrderExpr(exprs ...Querier) *WindowBuilder {
for i := range exprs {
w.order = append(w.order, exprs[i])
}
return w
}
@@ -2954,8 +2963,7 @@ func (w *WindowBuilder) Query() (string, []interface{}) {
w.partition(b)
}
if w.order != nil {
b.WriteString(" ORDER BY ")
w.order(b)
joinOrder(w.order, b)
}
})
return w.Builder.String(), w.args

View File

@@ -2039,13 +2039,13 @@ func TestWindowFunction(t *testing.T) {
Select().
AppendSelect("*").
AppendSelectExprAs(
RowNumber().PartitionBy("author_id").OrderBy("id"),
RowNumber().PartitionBy("author_id").OrderBy("id").OrderExpr(Expr("f(`s`)")),
"row_number",
).
From(Table("active_posts")),
)
query, args := Select("*").From(Table("selected_posts")).Where(LTE("row_number", 2)).Prefix(with).Query()
require.Equal(t, "WITH `active_posts` AS (SELECT `posts`.`id`, `posts`.`content`, `posts`.`author_id` FROM `posts` WHERE `active`), `selected_posts` AS (SELECT *, (ROW_NUMBER() OVER (PARTITION BY `author_id` ORDER BY `id`)) AS `row_number` FROM `active_posts`) SELECT * FROM `selected_posts` WHERE `row_number` <= ?", query)
require.Equal(t, "WITH `active_posts` AS (SELECT `posts`.`id`, `posts`.`content`, `posts`.`author_id` FROM `posts` WHERE `active`), `selected_posts` AS (SELECT *, (ROW_NUMBER() OVER (PARTITION BY `author_id` ORDER BY `id`, f(`s`))) AS `row_number` FROM `active_posts`) SELECT * FROM `selected_posts` WHERE `row_number` <= ?", query)
require.Equal(t, []interface{}{2}, args)
}