Search: Fixes search limits and adds a page parameter (#16458)

* Search: Fixes search limits and adds a page parameter

This adds a page parameter to search api without adding
any major breaking change.

It does at an api validation error when trying to use
a limit beyond 5000. This is a breaking change. We could
remove this and have it only in the docs and describe that this
is a limit that grafana will apply silently.

Fixes #16049

* Fix: Corrected wrong array slice change

* Docs: minor docs fix

* Search: fixed folder tests

* Fixed: Moved limit to correct inner query

* Search: moving limit check and page check

* Search: limit in handler is no longer needed
This commit is contained in:
Torkel Ödegaard
2019-04-17 13:07:50 +02:00
committed by GitHub
parent 9cc67e49b4
commit 8b0dd4244b
12 changed files with 73 additions and 42 deletions
+2 -6
View File
@@ -9,7 +9,7 @@ import (
// FolderService service for operating on folders
type FolderService interface {
GetFolders(limit int) ([]*models.Folder, error)
GetFolders(limit int64) ([]*models.Folder, error)
GetFolderByID(id int64) (*models.Folder, error)
GetFolderByUID(uid string) (*models.Folder, error)
CreateFolder(cmd *models.CreateFolderCommand) error
@@ -25,11 +25,7 @@ var NewFolderService = func(orgId int64, user *models.SignedInUser) FolderServic
}
}
func (dr *dashboardServiceImpl) GetFolders(limit int) ([]*models.Folder, error) {
if limit == 0 {
limit = 1000
}
func (dr *dashboardServiceImpl) GetFolders(limit int64) ([]*models.Folder, error) {
searchQuery := search.Query{
SignedInUser: dr.user,
DashboardIds: make([]int64, 0),
+1 -4
View File
@@ -31,6 +31,7 @@ func (s *SearchService) searchHandler(query *Query) error {
FolderIds: query.FolderIds,
Tags: query.Tags,
Limit: query.Limit,
Page: query.Page,
Permission: query.Permission,
}
@@ -44,10 +45,6 @@ func (s *SearchService) searchHandler(query *Query) error {
// sort main result array
sort.Sort(hits)
if len(hits) > query.Limit {
hits = hits[0:query.Limit]
}
// sort tags
for _, hit := range hits {
sort.Strings(hit.Tags)
+4 -2
View File
@@ -48,7 +48,8 @@ type Query struct {
Tags []string
OrgId int64
SignedInUser *models.SignedInUser
Limit int
Limit int64
Page int64
IsStarred bool
Type string
DashboardIds []int64
@@ -67,7 +68,8 @@ type FindPersistedDashboardsQuery struct {
Type string
FolderIds []int64
Tags []string
Limit int
Limit int64
Page int64
Permission models.PermissionType
Result HitList
+1 -6
View File
@@ -197,12 +197,7 @@ type DashboardSearchProjection struct {
}
func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
limit := query.Limit
if limit == 0 {
limit = 1000
}
sb := NewSearchBuilder(query.SignedInUser, limit, query.Permission).
sb := NewSearchBuilder(query.SignedInUser, query.Limit, query.Page, query.Permission).
WithTags(query.Tags).
WithDashboardIdsIn(query.DashboardIds)
+29
View File
@@ -259,6 +259,35 @@ func TestDashboardDataAccess(t *testing.T) {
So(hit.FolderTitle, ShouldEqual, "")
})
Convey("Should be able to limit search", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
Limit: 1,
SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
}
err := SearchDashboards(&query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
So(query.Result[0].Title, ShouldEqual, "1 test dash folder")
})
Convey("Should be able to search beyond limit using paging", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
Limit: 1,
Page: 2,
SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
}
err := SearchDashboards(&query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
So(query.Result[0].Title, ShouldEqual, "test dash 23")
})
Convey("Should be able to search for a dashboard folder's children", func() {
query := search.FindPersistedDashboardsQuery{
OrgId: 1,
+21 -11
View File
@@ -11,7 +11,8 @@ type SearchBuilder struct {
SqlBuilder
tags []string
isStarred bool
limit int
limit int64
page int64
signedInUser *m.SignedInUser
whereDashboardIdsIn []int64
whereTitle string
@@ -21,10 +22,21 @@ type SearchBuilder struct {
permission m.PermissionType
}
func NewSearchBuilder(signedInUser *m.SignedInUser, limit int, permission m.PermissionType) *SearchBuilder {
func NewSearchBuilder(signedInUser *m.SignedInUser, limit int64, page int64, permission m.PermissionType) *SearchBuilder {
// Default to page 1
if page < 1 {
page = 1
}
// default limit
if limit <= 0 {
limit = 1000
}
searchBuilder := &SearchBuilder{
signedInUser: signedInUser,
limit: limit,
page: page,
permission: permission,
}
@@ -88,12 +100,16 @@ func (sb *SearchBuilder) ToSql() (string, []interface{}) {
sb.buildMainQuery()
}
sb.sql.WriteString(`
ORDER BY dashboard.id ` + dialect.LimitOffset(sb.limit, (sb.page-1)*sb.limit) + `) as ids
INNER JOIN dashboard on ids.id = dashboard.id
`)
sb.sql.WriteString(`
LEFT OUTER JOIN dashboard folder on folder.id = dashboard.folder_id
LEFT OUTER JOIN dashboard_tag on dashboard.id = dashboard_tag.dashboard_id`)
sb.sql.WriteString(" ORDER BY dashboard.title ASC" + dialect.Limit(5000))
sb.sql.WriteString(" ORDER BY dashboard.title ASC")
return sb.sql.String(), sb.params
}
@@ -133,12 +149,7 @@ func (sb *SearchBuilder) buildTagQuery() {
sb.buildSearchWhereClause()
// this ends the inner select (tag filtered part)
sb.sql.WriteString(`
GROUP BY dashboard.id HAVING COUNT(dashboard.id) >= ?
ORDER BY dashboard.id` + dialect.Limit(int64(sb.limit)) + `) as ids
INNER JOIN dashboard on ids.id = dashboard.id
`)
sb.sql.WriteString(`GROUP BY dashboard.id HAVING COUNT(dashboard.id) >= ? `)
sb.params = append(sb.params, len(sb.tags))
}
@@ -152,7 +163,6 @@ func (sb *SearchBuilder) buildMainQuery() {
sb.sql.WriteString(` WHERE `)
sb.buildSearchWhereClause()
sb.sql.WriteString(` ORDER BY dashboard.title` + dialect.Limit(int64(sb.limit)) + `) as ids INNER JOIN dashboard on ids.id = dashboard.id `)
}
func (sb *SearchBuilder) buildSearchWhereClause() {
+1 -1
View File
@@ -14,7 +14,7 @@ func TestSearchBuilder(t *testing.T) {
UserId: 1,
}
sb := NewSearchBuilder(signedInUser, 1000, m.PERMISSION_VIEW)
sb := NewSearchBuilder(signedInUser, 1000, 0, m.PERMISSION_VIEW)
Convey("When building a normal search", func() {
sql, params := sb.IsStarred().WithTitle("test").ToSql()