User: Support sort query param for user and org user, search endpoints (#75229)

* User: Add sort option to user search

* Switch to an approach that uses the dashboard search options

* Cable user sort on the org endpoint

* Alias user table with u in org store

* Add test and cover orgs/:orgID/users/search endpoint

* Add test to userimpl store

* Simplify the store_test with sortopts.ParseSortQueryParam

* Account for PR feedback

* Positive check

* Update docs

* Update docs

* Switch to ErrOrFallback

Co-authored-by: Karl Persson <kalle.persson@grafana.com>

---------

Co-authored-by: Karl Persson <kalle.persson@grafana.com>
This commit is contained in:
Gabriel MABILLE
2023-09-28 10:16:18 +02:00
committed by GitHub
parent 4563fc48af
commit 96cbe70b14
13 changed files with 279 additions and 78 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"github.com/grafana/grafana/pkg/services/search/model"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
@@ -61,11 +62,11 @@ func (b *Builder) buildSelect() {
folder.title AS folder_title `)
for _, f := range b.Filters {
if f, ok := f.(FilterSelect); ok {
if f, ok := f.(model.FilterSelect); ok {
b.sql.WriteString(fmt.Sprintf(", %s", f.Select()))
}
if f, ok := f.(FilterWith); ok {
if f, ok := f.(model.FilterWith); ok {
recQuery, recQueryParams = f.With()
}
}
@@ -98,14 +99,14 @@ func (b *Builder) applyFilters() (ordering string) {
orders := []string{}
for _, f := range b.Filters {
if f, ok := f.(FilterLeftJoin); ok {
if f, ok := f.(model.FilterLeftJoin); ok {
s := f.LeftJoin()
if s != "" {
joins = append(joins, fmt.Sprintf(" LEFT OUTER JOIN %s ", s))
}
}
if f, ok := f.(FilterWhere); ok {
if f, ok := f.(model.FilterWhere); ok {
sql, params := f.Where()
if sql != "" {
wheres = append(wheres, sql)
@@ -113,7 +114,7 @@ func (b *Builder) applyFilters() (ordering string) {
}
}
if f, ok := f.(FilterGroupBy); ok {
if f, ok := f.(model.FilterGroupBy); ok {
sql, params := f.GroupBy()
if sql != "" {
groups = append(groups, sql)
@@ -121,8 +122,8 @@ func (b *Builder) applyFilters() (ordering string) {
}
}
if f, ok := f.(FilterOrderBy); ok {
if f, ok := f.(FilterLeftJoin); ok {
if f, ok := f.(model.FilterOrderBy); ok {
if f, ok := f.(model.FilterLeftJoin); ok {
orderJoins = append(orderJoins, fmt.Sprintf(" LEFT OUTER JOIN %s ", f.LeftJoin()))
}
orders = append(orders, f.OrderBy())

View File

@@ -5,45 +5,10 @@ import (
"strings"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/search/model"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
// FilterWhere limits the set of dashboard IDs to the dashboards for
// which the filter is applicable. Results where the first value is
// an empty string are discarded.
type FilterWhere interface {
Where() (string, []any)
}
// FilterWith returns any recursive CTE queries (if supported)
// and their parameters
type FilterWith interface {
With() (string, []any)
}
// FilterGroupBy should be used after performing an outer join on the
// search result to ensure there is only one of each ID in the results.
// The id column must be present in the result.
type FilterGroupBy interface {
GroupBy() (string, []any)
}
// FilterOrderBy provides an ordering for the search result.
type FilterOrderBy interface {
OrderBy() string
}
// FilterLeftJoin adds the returned string as a "LEFT OUTER JOIN" to
// allow for fetching extra columns from a table outside of the
// dashboard column.
type FilterLeftJoin interface {
LeftJoin() string
}
type FilterSelect interface {
Select() string
}
const (
TypeFolder = "dash-folder"
TypeDashboard = "dash-db"
@@ -220,7 +185,7 @@ func sqlUIDin(column string, uids []string) (string, []any) {
type FolderWithAlertsFilter struct {
}
var _ FilterWhere = &FolderWithAlertsFilter{}
var _ model.FilterWhere = &FolderWithAlertsFilter{}
func (f FolderWithAlertsFilter) Where() (string, []any) {
return "EXISTS (SELECT 1 FROM alert_rule WHERE alert_rule.namespace_uid = dashboard.uid)", nil