Add support for NULLS_FIRST and NULLS_LAST sorting order.
This commit is contained in:
parent
0fc51cf402
commit
dab153a739
8 changed files with 882 additions and 19 deletions
|
|
@ -12,6 +12,7 @@ type Dialect interface {
|
|||
IdentifierQuoteChar() byte
|
||||
ArgumentPlaceholder() QueryPlaceholderFunc
|
||||
IsReservedWord(name string) bool
|
||||
SerializeOrderBy() func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
||||
}
|
||||
|
||||
// SerializerFunc func
|
||||
|
|
@ -33,6 +34,7 @@ type DialectParams struct {
|
|||
IdentifierQuoteChar byte
|
||||
ArgumentPlaceholder QueryPlaceholderFunc
|
||||
ReservedWords []string
|
||||
SerializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
||||
}
|
||||
|
||||
// NewDialect creates new dialect with params
|
||||
|
|
@ -46,6 +48,7 @@ func NewDialect(params DialectParams) Dialect {
|
|||
identifierQuoteChar: params.IdentifierQuoteChar,
|
||||
argumentPlaceholder: params.ArgumentPlaceholder,
|
||||
reservedWords: arrayOfStringsToMapOfStrings(params.ReservedWords),
|
||||
serializeOrderBy: params.SerializeOrderBy,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,8 +61,7 @@ type dialectImpl struct {
|
|||
identifierQuoteChar byte
|
||||
argumentPlaceholder QueryPlaceholderFunc
|
||||
reservedWords map[string]bool
|
||||
|
||||
supportsReturning bool
|
||||
serializeOrderBy func(expression Expression, ascending, nullsFirst *bool) SerializerFunc
|
||||
}
|
||||
|
||||
func (d *dialectImpl) Name() string {
|
||||
|
|
@ -101,6 +103,10 @@ func (d *dialectImpl) IsReservedWord(name string) bool {
|
|||
return isReservedWord
|
||||
}
|
||||
|
||||
func (d *dialectImpl) SerializeOrderBy() func(expression Expression, ascending, nullsFirst *bool) SerializerFunc {
|
||||
return d.serializeOrderBy
|
||||
}
|
||||
|
||||
func arrayOfStringsToMapOfStrings(arr []string) map[string]bool {
|
||||
ret := map[string]bool{}
|
||||
for _, elem := range arr {
|
||||
|
|
|
|||
|
|
@ -64,14 +64,24 @@ func (e *ExpressionInterfaceImpl) AS(alias string) Projection {
|
|||
return newAlias(e.Parent, alias)
|
||||
}
|
||||
|
||||
// ASC expression will be used to sort query result in ascending order
|
||||
// ASC expression will be used to sort a query result in ascending order
|
||||
func (e *ExpressionInterfaceImpl) ASC() OrderByClause {
|
||||
return newOrderByClause(e.Parent, true)
|
||||
return newOrderByAscending(e.Parent, true)
|
||||
}
|
||||
|
||||
// DESC expression will be used to sort query result in descending order
|
||||
// DESC expression will be used to sort a query result in descending order
|
||||
func (e *ExpressionInterfaceImpl) DESC() OrderByClause {
|
||||
return newOrderByClause(e.Parent, false)
|
||||
return newOrderByAscending(e.Parent, false)
|
||||
}
|
||||
|
||||
// NULLS_FIRST specifies sort where null values appear before all non-null values
|
||||
func (e *ExpressionInterfaceImpl) NULLS_FIRST() OrderByClause {
|
||||
return newOrderByNullsFirst(e.Parent, true)
|
||||
}
|
||||
|
||||
// NULLS_LAST specifies sort where null values appear after all non-null values
|
||||
func (e *ExpressionInterfaceImpl) NULLS_LAST() OrderByClause {
|
||||
return newOrderByNullsFirst(e.Parent, false)
|
||||
}
|
||||
|
||||
func (e *ExpressionInterfaceImpl) serializeForGroupBy(statement StatementType, out *SQLBuilder) {
|
||||
|
|
|
|||
|
|
@ -2,28 +2,78 @@ package jet
|
|||
|
||||
// OrderByClause interface
|
||||
type OrderByClause interface {
|
||||
// NULLS_FIRST specifies sort where null values appear before all non-null values.
|
||||
// For some dialects(mysql,mariadb), which do not support NULL_FIRST, NULL_FIRST is simulated
|
||||
// with additional IS_NOT_NULL expression.
|
||||
// For instance,
|
||||
// Rental.ReturnDate.DESC().NULLS_FIRST()
|
||||
// would translate to,
|
||||
// rental.return_date IS NOT NULL, rental.return_date DESC
|
||||
NULLS_FIRST() OrderByClause
|
||||
|
||||
// NULLS_LAST specifies sort where null values appear after all non-null values.
|
||||
// For some dialects(mysql,mariadb), which do not support NULLS_LAST, NULLS_LAST is simulated
|
||||
// with additional IS_NULL expression.
|
||||
// For instance,
|
||||
// Rental.ReturnDate.ASC().NULLS_LAST()
|
||||
// would translate to,
|
||||
// rental.return_date IS NULL, rental.return_date ASC
|
||||
NULLS_LAST() OrderByClause
|
||||
|
||||
serializeForOrderBy(statement StatementType, out *SQLBuilder)
|
||||
}
|
||||
|
||||
type orderByClauseImpl struct {
|
||||
expression Expression
|
||||
ascent bool
|
||||
ascending *bool
|
||||
nullsFirst *bool
|
||||
}
|
||||
|
||||
func (o *orderByClauseImpl) serializeForOrderBy(statement StatementType, out *SQLBuilder) {
|
||||
if o.expression == nil {
|
||||
func (ord *orderByClauseImpl) NULLS_FIRST() OrderByClause {
|
||||
nullsFirst := true
|
||||
ord.nullsFirst = &nullsFirst
|
||||
return ord
|
||||
}
|
||||
func (ord *orderByClauseImpl) NULLS_LAST() OrderByClause {
|
||||
nullsFirst := false
|
||||
ord.nullsFirst = &nullsFirst
|
||||
return ord
|
||||
}
|
||||
|
||||
func (ord *orderByClauseImpl) serializeForOrderBy(statement StatementType, out *SQLBuilder) {
|
||||
customSerializer := out.Dialect.SerializeOrderBy()
|
||||
if customSerializer != nil {
|
||||
customSerializer(ord.expression, ord.ascending, ord.nullsFirst)(statement, out)
|
||||
return
|
||||
}
|
||||
|
||||
if ord.expression == nil {
|
||||
panic("jet: nil expression in ORDER BY clause")
|
||||
}
|
||||
|
||||
o.expression.serializeForOrderBy(statement, out)
|
||||
ord.expression.serializeForOrderBy(statement, out)
|
||||
|
||||
if o.ascent {
|
||||
out.WriteString("ASC")
|
||||
} else {
|
||||
out.WriteString("DESC")
|
||||
if ord.ascending != nil {
|
||||
if *ord.ascending {
|
||||
out.WriteString("ASC")
|
||||
} else {
|
||||
out.WriteString("DESC")
|
||||
}
|
||||
}
|
||||
|
||||
if ord.nullsFirst != nil {
|
||||
if *ord.nullsFirst {
|
||||
out.WriteString("NULLS FIRST")
|
||||
} else {
|
||||
out.WriteString("NULLS LAST")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newOrderByClause(expression Expression, ascent bool) OrderByClause {
|
||||
return &orderByClauseImpl{expression: expression, ascent: ascent}
|
||||
func newOrderByAscending(expression Expression, ascending bool) OrderByClause {
|
||||
return &orderByClauseImpl{expression: expression, ascending: &ascending}
|
||||
}
|
||||
|
||||
func newOrderByNullsFirst(expression Expression, nullsFirst bool) OrderByClause {
|
||||
return &orderByClauseImpl{expression: expression, nullsFirst: &nullsFirst}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ func Serialize(exp Serializer, statementType StatementType, out *SQLBuilder, opt
|
|||
exp.serialize(statementType, out, options...)
|
||||
}
|
||||
|
||||
func SerializeForOrderBy(exp Expression, statementType StatementType, out *SQLBuilder) {
|
||||
exp.serializeForOrderBy(statementType, out)
|
||||
}
|
||||
|
||||
func contains(options []SerializeOption, option SerializeOption) bool {
|
||||
for _, opt := range options {
|
||||
if opt == option {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue