未验证 提交 59b92c03 编写于 作者: M Ming Deng 提交者: GitHub

Merge pull request #4279 from jianzhiyao/frt/supports_for_4144

supports_for_4144
package clauses
const (
ExprSep = "__"
ExprDot = "."
)
package order_clause
import (
"github.com/astaxie/beego/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
}
}
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 (
"fmt"
"github.com/astaxie/beego/client/orm/clauses"
"github.com/astaxie/beego/client/orm/clauses/order_clause"
"strings"
"time"
)
......@@ -421,7 +423,7 @@ func (t *dbTables) getGroupSQL(groups []string) (groupSQL string) {
}
// 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 {
return
}
......@@ -430,19 +432,25 @@ func (t *dbTables) getOrderSQL(orders []string) (orderSQL string) {
orderSqls := make([]string, 0, len(orders))
for _, order := range orders {
asc := "ASC"
if order[0] == '-' {
asc = "DESC"
order = order[1:]
}
exprs := strings.Split(order, ExprSep)
column := order.GetColumn()
clause := strings.Split(column, clauses.ExprDot)
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 {
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(clause, ExprSep)))
}
index, _, fi, suc := t.parseExprs(t.mi, exprs)
if !suc {
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
orderSqls = append(orderSqls, fmt.Sprintf("%s.%s%s%s %s", index, Q, fi.column, Q, order.SortString()))
}
orderSqls = append(orderSqls, fmt.Sprintf("%s.%s%s%s %s", index, Q, fi.column, Q, asc))
}
orderSQL = fmt.Sprintf("ORDER BY %s ", strings.Join(orderSqls, ", "))
......
......@@ -58,6 +58,7 @@ import (
"database/sql"
"errors"
"fmt"
"github.com/astaxie/beego/client/orm/clauses/order_clause"
"os"
"reflect"
"time"
......@@ -351,7 +352,7 @@ func (o *ormBase) LoadRelatedWithCtx(ctx context.Context, md interface{}, name s
qs.relDepth = relDepth
if len(order) > 0 {
qs.orders = []string{order}
qs.orders = order_clause.ParseOrder(order)
}
find := ind.FieldByIndex(fi.fieldIndex)
......
......@@ -16,12 +16,13 @@ package orm
import (
"fmt"
"github.com/astaxie/beego/client/orm/clauses"
"strings"
)
// ExprSep define the expression separation
const (
ExprSep = "__"
ExprSep = clauses.ExprSep
)
type condValue struct {
......
......@@ -17,8 +17,8 @@ package orm
import (
"context"
"fmt"
"github.com/astaxie/beego/client/orm/hints"
"github.com/astaxie/beego/client/orm/clauses/order_clause"
)
type colValue struct {
......@@ -71,7 +71,7 @@ type querySet struct {
limit int64
offset int64
groups []string
orders []string
orders []*order_clause.Order
distinct bool
forUpdate bool
useIndex int
......@@ -139,8 +139,20 @@ func (o querySet) GroupBy(exprs ...string) QuerySeter {
// add ORDER expression.
// "column" means ASC, "-column" means DESC.
func (o querySet) OrderBy(exprs ...string) QuerySeter {
o.orders = exprs
func (o querySet) OrderBy(expressions ...string) QuerySeter {
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
}
......
......@@ -21,6 +21,7 @@ import (
"context"
"database/sql"
"fmt"
"github.com/astaxie/beego/client/orm/clauses/order_clause"
"io/ioutil"
"math"
"os"
......@@ -1077,6 +1078,26 @@ func TestOrderBy(t *testing.T) {
num, err = qs.OrderBy("-profile__age").Filter("user_name", "astaxie").Count()
throwFail(t, err)
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) {
......@@ -1163,6 +1184,19 @@ func TestValues(t *testing.T) {
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")
throwFail(t, err)
throwFail(t, AssertIs(num, 3))
......
......@@ -17,6 +17,7 @@ package orm
import (
"context"
"database/sql"
"github.com/astaxie/beego/client/orm/clauses/order_clause"
"reflect"
"time"
......@@ -289,6 +290,28 @@ type QuerySeter interface {
// for example:
// qs.OrderBy("-status")
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.
// for example:
// qs.ForceIndex(`idx_name1`,`idx_name2`)
......
......@@ -452,9 +452,11 @@ func (m *taskManager) StartTask() {
func (m *taskManager) run() {
now := time.Now().Local()
m.taskLock.Lock()
for _, t := range m.adminTaskList {
t.SetNext(nil, now)
}
m.taskLock.Unlock()
for {
// we only use RLock here because NewMapSorter copy the reference, do not change any thing
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册