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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user