diff --git a/pkg/services/sqlstore/migrator/dialect.go b/pkg/services/sqlstore/migrator/dialect.go index 20cb7b4156f..8ca59d25eb1 100644 --- a/pkg/services/sqlstore/migrator/dialect.go +++ b/pkg/services/sqlstore/migrator/dialect.go @@ -27,6 +27,8 @@ type Dialect interface { BooleanStr(bool) string DateTimeFunc(string) string + OrderBy(order string) string + CreateIndexSQL(tableName string, index *Index) string CreateTableSQL(table *Table) string AddColumnSQL(tableName string, col *Column) string @@ -308,3 +310,7 @@ func (b *BaseDialect) Lock(_ LockCfg) error { func (b *BaseDialect) Unlock(_ LockCfg) error { return nil } + +func (b *BaseDialect) OrderBy(order string) string { + return order +} diff --git a/pkg/services/sqlstore/migrator/postgres_dialect.go b/pkg/services/sqlstore/migrator/postgres_dialect.go index 2978f98ef00..f361b792b31 100644 --- a/pkg/services/sqlstore/migrator/postgres_dialect.go +++ b/pkg/services/sqlstore/migrator/postgres_dialect.go @@ -284,6 +284,19 @@ func (db *PostgresDialect) Lock(cfg LockCfg) error { return nil } +// OrderBy normalizes ordering so that nulls end up last in sorting, which they do by default in both sqlite and mysql but not postgres +// order should be a string like `dashboard.id ASC` +func (db *PostgresDialect) OrderBy(order string) string { + nullSort := "FIRST" + normalizedOrder := strings.ToUpper(strings.TrimSpace(order)) + + if strings.HasSuffix(normalizedOrder, " DESC") { + nullSort = "LAST" + } + + return fmt.Sprintf("%s NULLS %s", order, nullSort) +} + func (db *PostgresDialect) Unlock(cfg LockCfg) error { // trying to release a previously-acquired exclusive session level advisory lock. // it will either return true if the lock is successfully released or diff --git a/pkg/services/sqlstore/searchstore/builder.go b/pkg/services/sqlstore/searchstore/builder.go index c27451bd7e7..1ae89d05de9 100644 --- a/pkg/services/sqlstore/searchstore/builder.go +++ b/pkg/services/sqlstore/searchstore/builder.go @@ -140,7 +140,12 @@ func (b *Builder) applyFilters() (ordering string) { b.params = append(b.params, groupParams...) } - orderBy := fmt.Sprintf(" ORDER BY %s", strings.Join(orders, ", ")) + orderByCols := []string{} + for _, o := range orders { + orderByCols = append(orderByCols, b.Dialect.OrderBy(o)) + } + + orderBy := fmt.Sprintf(" ORDER BY %s", strings.Join(orderByCols, ", ")) b.sql.WriteString(orderBy) order := strings.Join(orderJoins, "")