mirror of https://github.com/grafana/grafana
Chore: Move folder store interface, implementation and test under pkg/services/folder (#62586)
* Chore: Move folder store into folder service package * Split folder and dashboard store implementationspull/62686/head
parent
151e57df70
commit
f143b0a5b2
@ -0,0 +1,86 @@ |
||||
package folderimpl |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db" |
||||
"github.com/grafana/grafana/pkg/services/dashboards" |
||||
"github.com/grafana/grafana/pkg/services/folder" |
||||
) |
||||
|
||||
// DashboardStore implements the FolderStore interface
|
||||
// It fetches folders from the dashboard DB table
|
||||
type DashboardFolderStoreImpl struct { |
||||
store db.DB |
||||
} |
||||
|
||||
func ProvideDashboardFolderStore(sqlStore db.DB) *DashboardFolderStoreImpl { |
||||
return &DashboardFolderStoreImpl{store: sqlStore} |
||||
} |
||||
|
||||
func (d *DashboardFolderStoreImpl) GetFolderByTitle(ctx context.Context, orgID int64, title string) (*folder.Folder, error) { |
||||
if title == "" { |
||||
return nil, dashboards.ErrFolderTitleEmpty |
||||
} |
||||
|
||||
// there is a unique constraint on org_id, folder_id, title
|
||||
// there are no nested folders so the parent folder id is always 0
|
||||
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, Title: title} |
||||
err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error { |
||||
has, err := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true)).Where("folder_id=0").Get(&dashboard) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if !has { |
||||
return dashboards.ErrFolderNotFound |
||||
} |
||||
dashboard.SetID(dashboard.ID) |
||||
dashboard.SetUID(dashboard.UID) |
||||
return nil |
||||
}) |
||||
return dashboards.FromDashboard(&dashboard), err |
||||
} |
||||
|
||||
func (d *DashboardFolderStoreImpl) GetFolderByID(ctx context.Context, orgID int64, id int64) (*folder.Folder, error) { |
||||
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, ID: id} |
||||
err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error { |
||||
has, err := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true)).Where("folder_id=0").Get(&dashboard) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if !has { |
||||
return dashboards.ErrFolderNotFound |
||||
} |
||||
dashboard.SetID(dashboard.ID) |
||||
dashboard.SetUID(dashboard.UID) |
||||
return nil |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return dashboards.FromDashboard(&dashboard), nil |
||||
} |
||||
|
||||
func (d *DashboardFolderStoreImpl) GetFolderByUID(ctx context.Context, orgID int64, uid string) (*folder.Folder, error) { |
||||
if uid == "" { |
||||
return nil, dashboards.ErrDashboardIdentifierNotSet |
||||
} |
||||
|
||||
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, UID: uid} |
||||
err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error { |
||||
has, err := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true)).Where("folder_id=0").Get(&dashboard) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if !has { |
||||
return dashboards.ErrFolderNotFound |
||||
} |
||||
dashboard.SetID(dashboard.ID) |
||||
dashboard.SetUID(dashboard.UID) |
||||
return nil |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return dashboards.FromDashboard(&dashboard), nil |
||||
} |
@ -0,0 +1,137 @@ |
||||
package folderimpl |
||||
|
||||
import ( |
||||
"context" |
||||
"testing" |
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson" |
||||
"github.com/grafana/grafana/pkg/infra/db" |
||||
"github.com/grafana/grafana/pkg/services/dashboards" |
||||
"github.com/grafana/grafana/pkg/services/dashboards/database" |
||||
"github.com/grafana/grafana/pkg/services/featuremgmt" |
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest" |
||||
"github.com/grafana/grafana/pkg/services/sqlstore" |
||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl" |
||||
"github.com/grafana/grafana/pkg/setting" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func TestIntegrationDashboardFolderStore(t *testing.T) { |
||||
var sqlStore *sqlstore.SQLStore |
||||
var cfg *setting.Cfg |
||||
var dashboardStore *database.DashboardStore |
||||
|
||||
setup := func() { |
||||
sqlStore, cfg = db.InitTestDBwithCfg(t) |
||||
quotaService := quotatest.New(false, nil) |
||||
var err error |
||||
dashboardStore, err = database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(featuremgmt.FlagPanelTitleSearch), tagimpl.ProvideService(sqlStore, cfg), quotaService) |
||||
require.NoError(t, err) |
||||
} |
||||
t.Run("Given dashboard and folder with the same title", func(t *testing.T) { |
||||
setup() |
||||
var orgId int64 = 1 |
||||
title := "Very Unique Name" |
||||
var sqlStore *sqlstore.SQLStore |
||||
var folder1, folder2 *dashboards.Dashboard |
||||
sqlStore = db.InitTestDB(t) |
||||
folderStore := ProvideDashboardFolderStore(sqlStore) |
||||
folder2 = insertTestFolder(t, dashboardStore, "TEST", orgId, 0, "prod") |
||||
_ = insertTestDashboard(t, dashboardStore, title, orgId, folder2.ID, "prod") |
||||
folder1 = insertTestFolder(t, dashboardStore, title, orgId, 0, "prod") |
||||
|
||||
t.Run("GetFolderByTitle should find the folder", func(t *testing.T) { |
||||
result, err := folderStore.GetFolderByTitle(context.Background(), orgId, title) |
||||
require.NoError(t, err) |
||||
require.Equal(t, folder1.ID, result.ID) |
||||
}) |
||||
}) |
||||
|
||||
t.Run("GetFolderByUID", func(t *testing.T) { |
||||
var orgId int64 = 1 |
||||
sqlStore := db.InitTestDB(t) |
||||
folderStore := ProvideDashboardFolderStore(sqlStore) |
||||
folder := insertTestFolder(t, dashboardStore, "TEST", orgId, 0, "prod") |
||||
dash := insertTestDashboard(t, dashboardStore, "Very Unique Name", orgId, folder.ID, "prod") |
||||
|
||||
t.Run("should return folder by UID", func(t *testing.T) { |
||||
d, err := folderStore.GetFolderByUID(context.Background(), orgId, folder.UID) |
||||
require.Equal(t, folder.ID, d.ID) |
||||
require.NoError(t, err) |
||||
}) |
||||
t.Run("should not find dashboard", func(t *testing.T) { |
||||
d, err := folderStore.GetFolderByUID(context.Background(), orgId, dash.UID) |
||||
require.Nil(t, d) |
||||
require.ErrorIs(t, err, dashboards.ErrFolderNotFound) |
||||
}) |
||||
t.Run("should search in organization", func(t *testing.T) { |
||||
d, err := folderStore.GetFolderByUID(context.Background(), orgId+1, folder.UID) |
||||
require.Nil(t, d) |
||||
require.ErrorIs(t, err, dashboards.ErrFolderNotFound) |
||||
}) |
||||
}) |
||||
|
||||
t.Run("GetFolderByID", func(t *testing.T) { |
||||
var orgId int64 = 1 |
||||
sqlStore := db.InitTestDB(t) |
||||
folderStore := ProvideDashboardFolderStore(sqlStore) |
||||
folder := insertTestFolder(t, dashboardStore, "TEST", orgId, 0, "prod") |
||||
dash := insertTestDashboard(t, dashboardStore, "Very Unique Name", orgId, folder.ID, "prod") |
||||
|
||||
t.Run("should return folder by ID", func(t *testing.T) { |
||||
d, err := folderStore.GetFolderByID(context.Background(), orgId, folder.ID) |
||||
require.Equal(t, folder.ID, d.ID) |
||||
require.NoError(t, err) |
||||
}) |
||||
t.Run("should not find dashboard", func(t *testing.T) { |
||||
d, err := folderStore.GetFolderByID(context.Background(), orgId, dash.ID) |
||||
require.Nil(t, d) |
||||
require.ErrorIs(t, err, dashboards.ErrFolderNotFound) |
||||
}) |
||||
t.Run("should search in organization", func(t *testing.T) { |
||||
d, err := folderStore.GetFolderByID(context.Background(), orgId+1, folder.ID) |
||||
require.Nil(t, d) |
||||
require.ErrorIs(t, err, dashboards.ErrFolderNotFound) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
func insertTestDashboard(t *testing.T, dashboardStore *database.DashboardStore, title string, orgId int64, folderId int64, tags ...interface{}) *dashboards.Dashboard { |
||||
t.Helper() |
||||
cmd := dashboards.SaveDashboardCommand{ |
||||
OrgID: orgId, |
||||
FolderID: folderId, |
||||
IsFolder: false, |
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{ |
||||
"id": nil, |
||||
"title": title, |
||||
"tags": tags, |
||||
}), |
||||
} |
||||
dash, err := dashboardStore.SaveDashboard(context.Background(), cmd) |
||||
require.NoError(t, err) |
||||
require.NotNil(t, dash) |
||||
dash.Data.Set("id", dash.ID) |
||||
dash.Data.Set("uid", dash.UID) |
||||
return dash |
||||
} |
||||
|
||||
func insertTestFolder(t *testing.T, dashboardStore *database.DashboardStore, title string, orgId int64, folderId int64, tags ...interface{}) *dashboards.Dashboard { |
||||
t.Helper() |
||||
cmd := dashboards.SaveDashboardCommand{ |
||||
OrgID: orgId, |
||||
FolderID: folderId, |
||||
IsFolder: true, |
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{ |
||||
"id": nil, |
||||
"title": title, |
||||
"tags": tags, |
||||
}), |
||||
} |
||||
dash, err := dashboardStore.SaveDashboard(context.Background(), cmd) |
||||
require.NoError(t, err) |
||||
require.NotNil(t, dash) |
||||
dash.Data.Set("id", dash.ID) |
||||
dash.Data.Set("uid", dash.UID) |
||||
return dash |
||||
} |
@ -1,13 +1,12 @@ |
||||
// Code generated by mockery v2.16.0. DO NOT EDIT.
|
||||
|
||||
package dashboards |
||||
package foldertest |
||||
|
||||
import ( |
||||
context "context" |
||||
|
||||
mock "github.com/stretchr/testify/mock" |
||||
|
||||
folder "github.com/grafana/grafana/pkg/services/folder" |
||||
mock "github.com/stretchr/testify/mock" |
||||
) |
||||
|
||||
// FakeFolderStore is an autogenerated mock type for the FolderStore type
|
Loading…
Reference in new issue