Merge pull request #4294 from jianzhiyao/frt/supports_for_4144
Frt/supports for issue 4144
This commit is contained in:
commit
0139564cf0
@ -5,3 +5,4 @@
|
|||||||
- Fix `unknown escape sequence` in generated code. [4385](https://github.com/beego/beego/pull/4385)
|
- Fix `unknown escape sequence` in generated code. [4385](https://github.com/beego/beego/pull/4385)
|
||||||
- Using fixed name `commentRouter.go` as generated file name. [4385](https://github.com/beego/beego/pull/4385)
|
- Using fixed name `commentRouter.go` as generated file name. [4385](https://github.com/beego/beego/pull/4385)
|
||||||
- Fix 4383: ORM Adapter produces panic when using orm.RegisterModelWithPrefix. [4386](https://github.com/beego/beego/pull/4386)
|
- Fix 4383: ORM Adapter produces panic when using orm.RegisterModelWithPrefix. [4386](https://github.com/beego/beego/pull/4386)
|
||||||
|
- Support 4144: Add new api for order by for supporting multiple way to query [4294](https://github.com/beego/beego/pull/4294)
|
||||||
6
client/orm/clauses/const.go
Normal file
6
client/orm/clauses/const.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package clauses
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExprSep = "__"
|
||||||
|
ExprDot = "."
|
||||||
|
)
|
||||||
103
client/orm/clauses/order_clause/order.go
Normal file
103
client/orm/clauses/order_clause/order.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package order_clause
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Sort int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
None Sort = 0
|
||||||
|
Ascending Sort = 1
|
||||||
|
Descending Sort = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option func(order *Order)
|
||||||
|
|
||||||
|
type Order struct {
|
||||||
|
column string
|
||||||
|
sort Sort
|
||||||
|
isRaw bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clause(options ...Option) *Order {
|
||||||
|
o := &Order{}
|
||||||
|
for _, option := range options {
|
||||||
|
option(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Order) GetColumn() string {
|
||||||
|
return o.column
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Order) GetSort() Sort {
|
||||||
|
return o.sort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Order) SortString() string {
|
||||||
|
switch o.GetSort() {
|
||||||
|
case Ascending:
|
||||||
|
return "ASC"
|
||||||
|
case Descending:
|
||||||
|
return "DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ``
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Order) IsRaw() bool {
|
||||||
|
return o.isRaw
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseOrder(expressions ...string) []*Order {
|
||||||
|
var orders []*Order
|
||||||
|
for _, expression := range expressions {
|
||||||
|
sort := Ascending
|
||||||
|
column := strings.ReplaceAll(expression, clauses.ExprSep, clauses.ExprDot)
|
||||||
|
if column[0] == '-' {
|
||||||
|
sort = Descending
|
||||||
|
column = column[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
orders = append(orders, &Order{
|
||||||
|
column: column,
|
||||||
|
sort: sort,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return orders
|
||||||
|
}
|
||||||
|
|
||||||
|
func Column(column string) Option {
|
||||||
|
return func(order *Order) {
|
||||||
|
order.column = strings.ReplaceAll(column, clauses.ExprSep, clauses.ExprDot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sort(sort Sort) Option {
|
||||||
|
return func(order *Order) {
|
||||||
|
order.sort = sort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SortAscending() Option {
|
||||||
|
return sort(Ascending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SortDescending() Option {
|
||||||
|
return sort(Descending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SortNone() Option {
|
||||||
|
return sort(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Raw() Option {
|
||||||
|
return func(order *Order) {
|
||||||
|
order.isRaw = true
|
||||||
|
}
|
||||||
|
}
|
||||||
144
client/orm/clauses/order_clause/order_test.go
Normal file
144
client/orm/clauses/order_clause/order_test.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package order_clause
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClause(t *testing.T) {
|
||||||
|
var (
|
||||||
|
column = `a`
|
||||||
|
)
|
||||||
|
|
||||||
|
o := Clause(
|
||||||
|
Column(column),
|
||||||
|
)
|
||||||
|
|
||||||
|
if o.GetColumn() != column {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortAscending(t *testing.T) {
|
||||||
|
o := Clause(
|
||||||
|
SortAscending(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if o.GetSort() != Ascending {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortDescending(t *testing.T) {
|
||||||
|
o := Clause(
|
||||||
|
SortDescending(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if o.GetSort() != Descending {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortNone(t *testing.T) {
|
||||||
|
o1 := Clause(
|
||||||
|
SortNone(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if o1.GetSort() != None {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
o2 := Clause()
|
||||||
|
|
||||||
|
if o2.GetSort() != None {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRaw(t *testing.T) {
|
||||||
|
o1 := Clause()
|
||||||
|
|
||||||
|
if o1.IsRaw() {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
o2 := Clause(
|
||||||
|
Raw(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if !o2.IsRaw() {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestColumn(t *testing.T) {
|
||||||
|
o1 := Clause(
|
||||||
|
Column(`aaa`),
|
||||||
|
)
|
||||||
|
|
||||||
|
if o1.GetColumn() != `aaa` {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseOrder(t *testing.T) {
|
||||||
|
orders := ParseOrder(
|
||||||
|
`-user__status`,
|
||||||
|
`status`,
|
||||||
|
`user__status`,
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Log(orders)
|
||||||
|
|
||||||
|
if orders[0].GetSort() != Descending {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if orders[0].GetColumn() != `user.status` {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if orders[1].GetColumn() != `status` {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if orders[1].GetSort() != Ascending {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if orders[2].GetColumn() != `user.status` {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrder_GetColumn(t *testing.T) {
|
||||||
|
o := Clause(
|
||||||
|
Column(`user__id`),
|
||||||
|
)
|
||||||
|
if o.GetColumn() != `user.id` {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrder_GetSort(t *testing.T) {
|
||||||
|
o := Clause(
|
||||||
|
SortDescending(),
|
||||||
|
)
|
||||||
|
if o.GetSort() != Descending {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrder_IsRaw(t *testing.T) {
|
||||||
|
o1 := Clause()
|
||||||
|
if o1.IsRaw() {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
o2 := Clause(
|
||||||
|
Raw(),
|
||||||
|
)
|
||||||
|
if !o2.IsRaw() {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,6 +16,8 @@ package orm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses/order_clause"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -421,7 +423,7 @@ func (t *dbTables) getGroupSQL(groups []string) (groupSQL string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate order sql.
|
// generate order sql.
|
||||||
func (t *dbTables) getOrderSQL(orders []string) (orderSQL string) {
|
func (t *dbTables) getOrderSQL(orders []*order_clause.Order) (orderSQL string) {
|
||||||
if len(orders) == 0 {
|
if len(orders) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -430,19 +432,25 @@ func (t *dbTables) getOrderSQL(orders []string) (orderSQL string) {
|
|||||||
|
|
||||||
orderSqls := make([]string, 0, len(orders))
|
orderSqls := make([]string, 0, len(orders))
|
||||||
for _, order := range orders {
|
for _, order := range orders {
|
||||||
asc := "ASC"
|
column := order.GetColumn()
|
||||||
if order[0] == '-' {
|
clause := strings.Split(column, clauses.ExprDot)
|
||||||
asc = "DESC"
|
|
||||||
order = order[1:]
|
|
||||||
}
|
|
||||||
exprs := strings.Split(order, ExprSep)
|
|
||||||
|
|
||||||
index, _, fi, suc := t.parseExprs(t.mi, exprs)
|
if order.IsRaw() {
|
||||||
|
if len(clause) == 2 {
|
||||||
|
orderSqls = append(orderSqls, fmt.Sprintf("%s.%s%s%s %s", clause[0], Q, clause[1], Q, order.SortString()))
|
||||||
|
} else if len(clause) == 1 {
|
||||||
|
orderSqls = append(orderSqls, fmt.Sprintf("%s%s%s %s", Q, clause[0], Q, order.SortString()))
|
||||||
|
} else {
|
||||||
|
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(clause, ExprSep)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index, _, fi, suc := t.parseExprs(t.mi, clause)
|
||||||
if !suc {
|
if !suc {
|
||||||
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
|
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(clause, ExprSep)))
|
||||||
}
|
}
|
||||||
|
|
||||||
orderSqls = append(orderSqls, fmt.Sprintf("%s.%s%s%s %s", index, Q, fi.column, Q, asc))
|
orderSqls = append(orderSqls, fmt.Sprintf("%s.%s%s%s %s", index, Q, fi.column, Q, order.SortString()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
orderSQL = fmt.Sprintf("ORDER BY %s ", strings.Join(orderSqls, ", "))
|
orderSQL = fmt.Sprintf("ORDER BY %s ", strings.Join(orderSqls, ", "))
|
||||||
|
|||||||
@ -58,6 +58,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses/order_clause"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
@ -351,7 +352,7 @@ func (o *ormBase) LoadRelatedWithCtx(ctx context.Context, md interface{}, name s
|
|||||||
qs.relDepth = relDepth
|
qs.relDepth = relDepth
|
||||||
|
|
||||||
if len(order) > 0 {
|
if len(order) > 0 {
|
||||||
qs.orders = []string{order}
|
qs.orders = order_clause.ParseOrder(order)
|
||||||
}
|
}
|
||||||
|
|
||||||
find := ind.FieldByIndex(fi.fieldIndex)
|
find := ind.FieldByIndex(fi.fieldIndex)
|
||||||
|
|||||||
@ -16,12 +16,13 @@ package orm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExprSep define the expression separation
|
// ExprSep define the expression separation
|
||||||
const (
|
const (
|
||||||
ExprSep = "__"
|
ExprSep = clauses.ExprSep
|
||||||
)
|
)
|
||||||
|
|
||||||
type condValue struct {
|
type condValue struct {
|
||||||
|
|||||||
@ -17,8 +17,8 @@ package orm
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/beego/beego/v2/client/orm/hints"
|
"github.com/beego/beego/v2/client/orm/hints"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses/order_clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
type colValue struct {
|
type colValue struct {
|
||||||
@ -71,7 +71,7 @@ type querySet struct {
|
|||||||
limit int64
|
limit int64
|
||||||
offset int64
|
offset int64
|
||||||
groups []string
|
groups []string
|
||||||
orders []string
|
orders []*order_clause.Order
|
||||||
distinct bool
|
distinct bool
|
||||||
forUpdate bool
|
forUpdate bool
|
||||||
useIndex int
|
useIndex int
|
||||||
@ -140,8 +140,20 @@ func (o querySet) GroupBy(exprs ...string) QuerySeter {
|
|||||||
|
|
||||||
// add ORDER expression.
|
// add ORDER expression.
|
||||||
// "column" means ASC, "-column" means DESC.
|
// "column" means ASC, "-column" means DESC.
|
||||||
func (o querySet) OrderBy(exprs ...string) QuerySeter {
|
func (o querySet) OrderBy(expressions ...string) QuerySeter {
|
||||||
o.orders = exprs
|
if len(expressions) <= 0 {
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
o.orders = order_clause.ParseOrder(expressions...)
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
|
||||||
|
// add ORDER expression.
|
||||||
|
func (o querySet) OrderClauses(orders ...*order_clause.Order) QuerySeter {
|
||||||
|
if len(orders) <= 0 {
|
||||||
|
return &o
|
||||||
|
}
|
||||||
|
o.orders = orders
|
||||||
return &o
|
return &o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses/order_clause"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
@ -1146,6 +1147,26 @@ func TestOrderBy(t *testing.T) {
|
|||||||
num, err = qs.OrderBy("-profile__age").Filter("user_name", "astaxie").Count()
|
num, err = qs.OrderBy("-profile__age").Filter("user_name", "astaxie").Count()
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(num, 1))
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = qs.OrderClauses(
|
||||||
|
order_clause.Clause(
|
||||||
|
order_clause.Column(`profile__age`),
|
||||||
|
order_clause.SortDescending(),
|
||||||
|
),
|
||||||
|
).Filter("user_name", "astaxie").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
if IsMysql {
|
||||||
|
num, err = qs.OrderClauses(
|
||||||
|
order_clause.Clause(
|
||||||
|
order_clause.Column(`rand()`),
|
||||||
|
order_clause.Raw(),
|
||||||
|
),
|
||||||
|
).Filter("user_name", "astaxie").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
func TestAll(t *testing.T) {
|
||||||
@ -1232,6 +1253,19 @@ func TestValues(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(maps[2]["Profile"], nil))
|
throwFail(t, AssertIs(maps[2]["Profile"], nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
num, err = qs.OrderClauses(
|
||||||
|
order_clause.Clause(
|
||||||
|
order_clause.Column("Id"),
|
||||||
|
order_clause.SortAscending(),
|
||||||
|
),
|
||||||
|
).Values(&maps)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 3))
|
||||||
|
if num == 3 {
|
||||||
|
throwFail(t, AssertIs(maps[0]["UserName"], "slene"))
|
||||||
|
throwFail(t, AssertIs(maps[2]["Profile"], nil))
|
||||||
|
}
|
||||||
|
|
||||||
num, err = qs.OrderBy("Id").Values(&maps, "UserName", "Profile__Age")
|
num, err = qs.OrderBy("Id").Values(&maps, "UserName", "Profile__Age")
|
||||||
throwFail(t, err)
|
throwFail(t, err)
|
||||||
throwFail(t, AssertIs(num, 3))
|
throwFail(t, AssertIs(num, 3))
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package orm
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"github.com/beego/beego/v2/client/orm/clauses/order_clause"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -289,6 +290,28 @@ type QuerySeter interface {
|
|||||||
// for example:
|
// for example:
|
||||||
// qs.OrderBy("-status")
|
// qs.OrderBy("-status")
|
||||||
OrderBy(exprs ...string) QuerySeter
|
OrderBy(exprs ...string) QuerySeter
|
||||||
|
// add ORDER expression by order clauses
|
||||||
|
// for example:
|
||||||
|
// OrderClauses(
|
||||||
|
// order_clause.Clause(
|
||||||
|
// order.Column("Id"),
|
||||||
|
// order.SortAscending(),
|
||||||
|
// ),
|
||||||
|
// order_clause.Clause(
|
||||||
|
// order.Column("status"),
|
||||||
|
// order.SortDescending(),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// OrderClauses(order_clause.Clause(
|
||||||
|
// order_clause.Column(`user__status`),
|
||||||
|
// order_clause.SortDescending(),//default None
|
||||||
|
// ))
|
||||||
|
// OrderClauses(order_clause.Clause(
|
||||||
|
// order_clause.Column(`random()`),
|
||||||
|
// order_clause.SortNone(),//default None
|
||||||
|
// order_clause.Raw(),//default false.if true, do not check field is valid or not
|
||||||
|
// ))
|
||||||
|
OrderClauses(orders ...*order_clause.Order) QuerySeter
|
||||||
// add FORCE INDEX expression.
|
// add FORCE INDEX expression.
|
||||||
// for example:
|
// for example:
|
||||||
// qs.ForceIndex(`idx_name1`,`idx_name2`)
|
// qs.ForceIndex(`idx_name1`,`idx_name2`)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user