sqlstore: finish removing Find and SearchDashboards (#49347)

* chore: replace artisnal FakeDashboardService with generated mock

Maintaining a handcrafted FakeDashboardService is not sustainable now that we are in the process of moving the dashboard-related functions out of sqlstore.

* sqlstore: finish removing Find and SearchDashboards

Find and SearchDashboards were previously copied into the dashboard service. This commit completes that work, removing Find and SearchDashboards from the sqlstore and updating callers to use the dashboard service.

* dashboards: remove SearchDashboards from Store interface

SearchDashboards is a wrapper around FindDashboard that transforms the results, so it's been moved out of the Store entirely and the functionality moved into the Dashboard Service's search implementation.

The database tests depended heavily on the transformation, so I added testSearchDashboards, a copy of search dashboards, instead of (heavily) refactoring all the tests.
This commit is contained in:
Kristin Laemmert
2022-05-24 09:24:55 -04:00
committed by GitHub
parent 86871807d2
commit debbb8d59d
15 changed files with 212 additions and 304 deletions
-157
View File
@@ -7,9 +7,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
"github.com/grafana/grafana/pkg/util"
)
@@ -27,160 +24,6 @@ func init() {
var generateNewUid func() string = util.GenerateShortUID
type DashboardSearchProjection struct {
ID int64 `xorm:"id"`
UID string `xorm:"uid"`
Title string
Slug string
Term string
IsFolder bool
FolderID int64 `xorm:"folder_id"`
FolderUID string `xorm:"folder_uid"`
FolderSlug string
FolderTitle string
SortMeta int64
}
func (ss *SQLStore) FindDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
filters := []interface{}{
permissions.DashboardPermissionFilter{
OrgRole: query.SignedInUser.OrgRole,
OrgId: query.SignedInUser.OrgId,
Dialect: dialect,
UserId: query.SignedInUser.UserId,
PermissionLevel: query.Permission,
},
}
if !accesscontrol.IsDisabled(ss.Cfg) {
// if access control is enabled, overwrite the filters so far
filters = []interface{}{
permissions.NewAccessControlDashboardPermissionFilter(query.SignedInUser, query.Permission, query.Type),
}
}
for _, filter := range query.Sort.Filter {
filters = append(filters, filter)
}
filters = append(filters, query.Filters...)
if query.OrgId != 0 {
filters = append(filters, searchstore.OrgFilter{OrgId: query.OrgId})
} else if query.SignedInUser.OrgId != 0 {
filters = append(filters, searchstore.OrgFilter{OrgId: query.SignedInUser.OrgId})
}
if len(query.Tags) > 0 {
filters = append(filters, searchstore.TagsFilter{Tags: query.Tags})
}
if len(query.DashboardIds) > 0 {
filters = append(filters, searchstore.DashboardFilter{IDs: query.DashboardIds})
}
if query.IsStarred {
filters = append(filters, searchstore.StarredFilter{UserId: query.SignedInUser.UserId})
}
if len(query.Title) > 0 {
filters = append(filters, searchstore.TitleFilter{Dialect: dialect, Title: query.Title})
}
if len(query.Type) > 0 {
filters = append(filters, searchstore.TypeFilter{Dialect: dialect, Type: query.Type})
}
if len(query.FolderIds) > 0 {
filters = append(filters, searchstore.FolderFilter{IDs: query.FolderIds})
}
var res []DashboardSearchProjection
sb := &searchstore.Builder{Dialect: dialect, Filters: filters}
limit := query.Limit
if limit < 1 {
limit = 1000
}
page := query.Page
if page < 1 {
page = 1
}
sql, params := sb.ToSQL(limit, page)
err := ss.WithDbSession(ctx, func(dbSession *DBSession) error {
return dbSession.SQL(sql, params...).Find(&res)
})
if err != nil {
return nil, err
}
return res, nil
}
func (ss *SQLStore) SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error {
res, err := ss.FindDashboards(ctx, query)
if err != nil {
return err
}
makeQueryResult(query, res)
return nil
}
func getHitType(item DashboardSearchProjection) models.HitType {
var hitType models.HitType
if item.IsFolder {
hitType = models.DashHitFolder
} else {
hitType = models.DashHitDB
}
return hitType
}
func makeQueryResult(query *models.FindPersistedDashboardsQuery, res []DashboardSearchProjection) {
query.Result = make([]*models.Hit, 0)
hits := make(map[int64]*models.Hit)
for _, item := range res {
hit, exists := hits[item.ID]
if !exists {
hit = &models.Hit{
ID: item.ID,
UID: item.UID,
Title: item.Title,
URI: "db/" + item.Slug,
URL: models.GetDashboardFolderUrl(item.IsFolder, item.UID, item.Slug),
Type: getHitType(item),
FolderID: item.FolderID,
FolderUID: item.FolderUID,
FolderTitle: item.FolderTitle,
Tags: []string{},
}
if item.FolderID > 0 {
hit.FolderURL = models.GetFolderUrl(item.FolderUID, item.FolderSlug)
}
if query.Sort.MetaName != "" {
hit.SortMeta = item.SortMeta
hit.SortMetaName = query.Sort.MetaName
}
query.Result = append(query.Result, hit)
hits[item.ID] = hit
}
if len(item.Term) > 0 {
hit.Tags = append(hit.Tags, item.Term)
}
}
}
func (ss *SQLStore) GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
sql := `SELECT
@@ -5,14 +5,16 @@ import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
@@ -43,7 +45,7 @@ func TestBuilder_EqualResults_Basic(t *testing.T) {
Dialect: db.Dialect,
}
res := []sqlstore.DashboardSearchProjection{}
res := []dashboards.DashboardSearchProjection{}
err := db.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
sql, params := builder.ToSQL(limit, page)
return sess.SQL(sql, params...).Find(&res)
@@ -52,7 +54,7 @@ func TestBuilder_EqualResults_Basic(t *testing.T) {
assert.Len(t, res, 1)
res[0].UID = ""
assert.EqualValues(t, []sqlstore.DashboardSearchProjection{
assert.EqualValues(t, []dashboards.DashboardSearchProjection{
{
ID: dashIds[0],
Title: "A",
@@ -80,9 +82,9 @@ func TestBuilder_Pagination(t *testing.T) {
Dialect: db.Dialect,
}
resPg1 := []sqlstore.DashboardSearchProjection{}
resPg2 := []sqlstore.DashboardSearchProjection{}
resPg3 := []sqlstore.DashboardSearchProjection{}
resPg1 := []dashboards.DashboardSearchProjection{}
resPg2 := []dashboards.DashboardSearchProjection{}
resPg3 := []dashboards.DashboardSearchProjection{}
err := db.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
sql, params := builder.ToSQL(15, 1)
err := sess.SQL(sql, params...).Find(&resPg1)
@@ -135,7 +137,7 @@ func TestBuilder_Permissions(t *testing.T) {
Dialect: db.Dialect,
}
res := []sqlstore.DashboardSearchProjection{}
res := []dashboards.DashboardSearchProjection{}
err := db.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
sql, params := builder.ToSQL(limit, page)
return sess.SQL(sql, params...).Find(&res)
-1
View File
@@ -97,7 +97,6 @@ type Store interface {
SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error
RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error
GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error
SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error
GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error
GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error
GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error