improve write order by (#2301)

Reviewed-on: https://gitea.com/xorm/xorm/pulls/2301
This commit is contained in:
Lunny Xiao 2023-07-22 11:52:38 +00:00
parent 96ed5584e3
commit 9988dac44d
5 changed files with 63 additions and 58 deletions

View File

@ -14,8 +14,8 @@ import (
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
func (statement *Statement) writeDeleteOrder(w builder.Writer) error { func (statement *Statement) writeDeleteOrder(w *builder.BytesWriter) error {
if err := statement.WriteOrderBy(w); err != nil { if err := statement.writeOrderBys(w); err != nil {
return err return err
} }

View File

@ -6,85 +6,91 @@ package statements
import ( import (
"fmt" "fmt"
"strings"
"xorm.io/builder" "xorm.io/builder"
) )
type orderBy struct {
orderStr interface{}
orderArgs []interface{}
direction string // ASC, DESC or "", "" means raw orderStr
}
func (statement *Statement) HasOrderBy() bool { func (statement *Statement) HasOrderBy() bool {
return statement.orderStr != "" return len(statement.orderBy) > 0
} }
// ResetOrderBy reset ordery conditions // ResetOrderBy reset ordery conditions
func (statement *Statement) ResetOrderBy() { func (statement *Statement) ResetOrderBy() {
statement.orderStr = "" statement.orderBy = []orderBy{}
statement.orderArgs = nil }
func (statement *Statement) writeOrderBy(w *builder.BytesWriter, orderBy orderBy) error {
switch t := orderBy.orderStr.(type) {
case (*builder.Expression):
if _, err := fmt.Fprint(w.Builder, statement.dialect.Quoter().Replace(t.Content())); err != nil {
return err
}
w.Append(t.Args()...)
return nil
case string:
if orderBy.direction == "" {
if _, err := fmt.Fprint(w.Builder, statement.dialect.Quoter().Replace(t)); err != nil {
return err
}
w.Append(orderBy.orderArgs...)
return nil
}
if err := statement.dialect.Quoter().QuoteTo(w.Builder, t); err != nil {
return err
}
_, err := fmt.Fprint(w, " ", orderBy.direction)
return err
default:
return ErrUnSupportedSQLType
}
} }
// WriteOrderBy write order by to writer // WriteOrderBy write order by to writer
func (statement *Statement) WriteOrderBy(w builder.Writer) error { func (statement *Statement) writeOrderBys(w *builder.BytesWriter) error {
if len(statement.orderStr) > 0 { if len(statement.orderBy) == 0 {
if _, err := fmt.Fprint(w, " ORDER BY ", statement.orderStr); err != nil { return nil
}
if _, err := fmt.Fprint(w, " ORDER BY "); err != nil {
return err return err
} }
w.Append(statement.orderArgs...) for i, ob := range statement.orderBy {
if err := statement.writeOrderBy(w, ob); err != nil {
return err
}
if i < len(statement.orderBy)-1 {
if _, err := fmt.Fprint(w, ", "); err != nil {
return err
}
}
} }
return nil return nil
} }
// OrderBy generate "Order By order" statement // OrderBy generate "Order By order" statement
func (statement *Statement) OrderBy(order interface{}, args ...interface{}) *Statement { func (statement *Statement) OrderBy(order interface{}, args ...interface{}) *Statement {
if len(statement.orderStr) > 0 { statement.orderBy = append(statement.orderBy, orderBy{order, args, ""})
statement.orderStr += ", "
}
var rawOrder string
switch t := order.(type) {
case (*builder.Expression):
rawOrder = t.Content()
args = t.Args()
case string:
rawOrder = t
default:
statement.LastError = ErrUnSupportedSQLType
return statement
}
statement.orderStr += statement.ReplaceQuote(rawOrder)
if len(args) > 0 {
statement.orderArgs = append(statement.orderArgs, args...)
}
return statement return statement
} }
// Desc generate `ORDER BY xx DESC` // Desc generate `ORDER BY xx DESC`
func (statement *Statement) Desc(colNames ...string) *Statement { func (statement *Statement) Desc(colNames ...string) *Statement {
var buf strings.Builder for _, colName := range colNames {
if len(statement.orderStr) > 0 { statement.orderBy = append(statement.orderBy, orderBy{colName, nil, "DESC"})
fmt.Fprint(&buf, statement.orderStr, ", ")
} }
for i, col := range colNames {
if i > 0 {
fmt.Fprint(&buf, ", ")
}
_ = statement.dialect.Quoter().QuoteTo(&buf, col)
fmt.Fprint(&buf, " DESC")
}
statement.orderStr = buf.String()
return statement return statement
} }
// Asc provide asc order by query condition, the input parameters are columns. // Asc provide asc order by query condition, the input parameters are columns.
func (statement *Statement) Asc(colNames ...string) *Statement { func (statement *Statement) Asc(colNames ...string) *Statement {
var buf strings.Builder for _, colName := range colNames {
if len(statement.orderStr) > 0 { statement.orderBy = append(statement.orderBy, orderBy{colName, nil, "ASC"})
fmt.Fprint(&buf, statement.orderStr, ", ")
} }
for i, col := range colNames {
if i > 0 {
fmt.Fprint(&buf, ", ")
}
_ = statement.dialect.Quoter().QuoteTo(&buf, col)
fmt.Fprint(&buf, " ASC")
}
statement.orderStr = buf.String()
return statement return statement
} }

View File

@ -320,7 +320,7 @@ func (statement *Statement) writeMssqlPaginationCond(w *builder.BytesWriter) err
if err := statement.writeWhere(subWriter); err != nil { if err := statement.writeWhere(subWriter); err != nil {
return err return err
} }
if err := statement.WriteOrderBy(subWriter); err != nil { if err := statement.writeOrderBys(subWriter); err != nil {
return err return err
} }
if err := statement.writeGroupBy(subWriter); err != nil { if err := statement.writeGroupBy(subWriter); err != nil {
@ -375,7 +375,7 @@ func (statement *Statement) writeSelect(buf *builder.BytesWriter, columnStr stri
if err := statement.writeHaving(buf); err != nil { if err := statement.writeHaving(buf); err != nil {
return err return err
} }
if err := statement.WriteOrderBy(buf); err != nil { if err := statement.writeOrderBys(buf); err != nil {
return err return err
} }

View File

@ -50,8 +50,7 @@ type Statement struct {
Start int Start int
LimitN *int LimitN *int
idParam schemas.PK idParam schemas.PK
orderStr string orderBy []orderBy
orderArgs []interface{}
joins []join joins []join
GroupByStr string GroupByStr string
HavingStr string HavingStr string
@ -163,15 +162,15 @@ func (statement *Statement) Reset() {
// SQL adds raw sql statement // SQL adds raw sql statement
func (statement *Statement) SQL(query interface{}, args ...interface{}) *Statement { func (statement *Statement) SQL(query interface{}, args ...interface{}) *Statement {
switch query.(type) { switch t := query.(type) {
case (*builder.Builder): case (*builder.Builder):
var err error var err error
statement.RawSQL, statement.RawParams, err = query.(*builder.Builder).ToSQL() statement.RawSQL, statement.RawParams, err = t.ToSQL()
if err != nil { if err != nil {
statement.LastError = err statement.LastError = err
} }
case string: case string:
statement.RawSQL = query.(string) statement.RawSQL = t
statement.RawParams = args statement.RawParams = args
default: default:
statement.LastError = ErrUnSupportedSQLType statement.LastError = ErrUnSupportedSQLType

View File

@ -319,7 +319,7 @@ func (statement *Statement) WriteUpdate(updateWriter *builder.BytesWriter, cond
if err := cond.WriteTo(statement.QuoteReplacer(whereWriter)); err != nil { if err := cond.WriteTo(statement.QuoteReplacer(whereWriter)); err != nil {
return err return err
} }
if err := statement.WriteOrderBy(whereWriter); err != nil { if err := statement.writeOrderBys(whereWriter); err != nil {
return err return err
} }