mirror of
https://github.com/grafana/grafana.git
synced 2025-01-27 00:37:04 -06:00
Nested folders: Fetch multiple folders from dashboard folder store (#72464)
This commit is contained in:
parent
7612f3d955
commit
1869da1d86
@ -2,6 +2,7 @@ package folderimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
@ -84,3 +85,38 @@ func (d *DashboardFolderStoreImpl) GetFolderByUID(ctx context.Context, orgID int
|
||||
}
|
||||
return dashboards.FromDashboard(&dashboard), nil
|
||||
}
|
||||
|
||||
func (d *DashboardFolderStoreImpl) GetFolders(ctx context.Context, orgID int64, uids []string) (map[string]*folder.Folder, error) {
|
||||
m := make(map[string]*folder.Folder, len(uids))
|
||||
var folders []*folder.Folder
|
||||
if err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
b := strings.Builder{}
|
||||
args := make([]interface{}, 0, len(uids)+1)
|
||||
|
||||
b.WriteString("SELECT * FROM dashboard WHERE org_id=? ")
|
||||
args = append(args, orgID)
|
||||
for i, uid := range uids {
|
||||
if i == 0 {
|
||||
b.WriteString(" AND (")
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
b.WriteString(" OR ")
|
||||
}
|
||||
b.WriteString(" uid=? ")
|
||||
args = append(args, uid)
|
||||
|
||||
if i == len(uids)-1 {
|
||||
b.WriteString(")")
|
||||
}
|
||||
}
|
||||
return sess.SQL(b.String(), args...).Find(&folders)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, f := range folders {
|
||||
m[f.UID] = f
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
@ -184,14 +184,25 @@ func (s *Service) GetChildren(ctx context.Context, cmd *folder.GetChildrenQuery)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
childrenUIDs := make([]string, 0, len(children))
|
||||
for _, f := range children {
|
||||
childrenUIDs = append(childrenUIDs, f.UID)
|
||||
}
|
||||
|
||||
dashFolders, err := s.dashboardFolderStore.GetFolders(ctx, cmd.OrgID, childrenUIDs)
|
||||
if err != nil {
|
||||
return nil, folder.ErrInternal.Errorf("failed to fetch subfolders from dashboard store: %w", err)
|
||||
}
|
||||
|
||||
filtered := make([]*folder.Folder, 0, len(children))
|
||||
for _, f := range children {
|
||||
// fetch folder from dashboard store
|
||||
dashFolder, err := s.dashboardFolderStore.GetFolderByUID(ctx, f.OrgID, f.UID)
|
||||
if err != nil {
|
||||
s.log.Error("failed to fetch folder by UID from dashboard store", "uid", f.UID, "error", err)
|
||||
dashFolder, ok := dashFolders[f.UID]
|
||||
if !ok {
|
||||
s.log.Error("failed to fetch folder by UID from dashboard store", "uid", f.UID)
|
||||
continue
|
||||
}
|
||||
|
||||
// always expose the dashboard store sequential ID
|
||||
f.ID = dashFolder.ID
|
||||
|
||||
@ -500,9 +511,14 @@ func (s *Service) Delete(ctx context.Context, cmd *folder.DeleteFolderCommand) e
|
||||
result = append(result, subfolders...)
|
||||
}
|
||||
|
||||
dashFolders, err := s.dashboardFolderStore.GetFolders(ctx, cmd.OrgID, result)
|
||||
if err != nil {
|
||||
return folder.ErrInternal.Errorf("failed to fetch subfolders from dashboard store: %w", err)
|
||||
}
|
||||
|
||||
for _, folder := range result {
|
||||
dashFolder, err := s.dashboardFolderStore.GetFolderByUID(ctx, cmd.OrgID, folder)
|
||||
if err != nil {
|
||||
dashFolder, ok := dashFolders[folder]
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ func TestIntegrationFolderService(t *testing.T) {
|
||||
f := folder.NewFolder(util.GenerateShortUID(), "")
|
||||
f.ID = rand.Int63()
|
||||
f.UID = util.GenerateShortUID()
|
||||
folderStore.On("GetFolderByUID", mock.Anything, orgID, f.UID).Return(f, nil)
|
||||
folderStore.On("GetFolders", mock.Anything, orgID, []string{f.UID}).Return(map[string]*folder.Folder{f.UID: f}, nil)
|
||||
|
||||
var actualCmd *dashboards.DeleteDashboardCommand
|
||||
dashStore.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.16.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.32.0. DO NOT EDIT.
|
||||
|
||||
package foldertest
|
||||
|
||||
@ -19,6 +19,10 @@ func (_m *FakeFolderStore) GetFolderByID(ctx context.Context, orgID int64, id in
|
||||
ret := _m.Called(ctx, orgID, id)
|
||||
|
||||
var r0 *folder.Folder
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) (*folder.Folder, error)); ok {
|
||||
return rf(ctx, orgID, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) *folder.Folder); ok {
|
||||
r0 = rf(ctx, orgID, id)
|
||||
} else {
|
||||
@ -27,7 +31,6 @@ func (_m *FakeFolderStore) GetFolderByID(ctx context.Context, orgID int64, id in
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, int64) error); ok {
|
||||
r1 = rf(ctx, orgID, id)
|
||||
} else {
|
||||
@ -42,6 +45,10 @@ func (_m *FakeFolderStore) GetFolderByTitle(ctx context.Context, orgID int64, ti
|
||||
ret := _m.Called(ctx, orgID, title)
|
||||
|
||||
var r0 *folder.Folder
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*folder.Folder, error)); ok {
|
||||
return rf(ctx, orgID, title)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *folder.Folder); ok {
|
||||
r0 = rf(ctx, orgID, title)
|
||||
} else {
|
||||
@ -50,7 +57,6 @@ func (_m *FakeFolderStore) GetFolderByTitle(ctx context.Context, orgID int64, ti
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
|
||||
r1 = rf(ctx, orgID, title)
|
||||
} else {
|
||||
@ -65,6 +71,10 @@ func (_m *FakeFolderStore) GetFolderByUID(ctx context.Context, orgID int64, uid
|
||||
ret := _m.Called(ctx, orgID, uid)
|
||||
|
||||
var r0 *folder.Folder
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*folder.Folder, error)); ok {
|
||||
return rf(ctx, orgID, uid)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *folder.Folder); ok {
|
||||
r0 = rf(ctx, orgID, uid)
|
||||
} else {
|
||||
@ -73,7 +83,6 @@ func (_m *FakeFolderStore) GetFolderByUID(ctx context.Context, orgID int64, uid
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
|
||||
r1 = rf(ctx, orgID, uid)
|
||||
} else {
|
||||
@ -83,13 +92,38 @@ func (_m *FakeFolderStore) GetFolderByUID(ctx context.Context, orgID int64, uid
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewFakeFolderStore interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
// GetFolders provides a mock function with given fields: ctx, orgID, uids
|
||||
func (_m *FakeFolderStore) GetFolders(ctx context.Context, orgID int64, uids []string) (map[string]*folder.Folder, error) {
|
||||
ret := _m.Called(ctx, orgID, uids)
|
||||
|
||||
var r0 map[string]*folder.Folder
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, []string) (map[string]*folder.Folder, error)); ok {
|
||||
return rf(ctx, orgID, uids)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, []string) map[string]*folder.Folder); ok {
|
||||
r0 = rf(ctx, orgID, uids)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]*folder.Folder)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, []string) error); ok {
|
||||
r1 = rf(ctx, orgID, uids)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewFakeFolderStore creates a new instance of FakeFolderStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeFolderStore(t mockConstructorTestingTNewFakeFolderStore) *FakeFolderStore {
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewFakeFolderStore(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *FakeFolderStore {
|
||||
mock := &FakeFolderStore{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
@ -39,4 +39,6 @@ type FolderStore interface {
|
||||
GetFolderByUID(ctx context.Context, orgID int64, uid string) (*Folder, error)
|
||||
// GetFolderByID retrieves a folder by its ID
|
||||
GetFolderByID(ctx context.Context, orgID int64, id int64) (*Folder, error)
|
||||
// GetFolders returns all folders for the given orgID and UIDs.
|
||||
GetFolders(ctx context.Context, orgID int64, uids []string) (map[string]*Folder, error)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user