Folders: Change query to an inner join on dashboards rather than 2 gets (#103183)
This commit is contained in:
@@ -2,6 +2,7 @@ package folderimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
@@ -20,37 +21,6 @@ func ProvideDashboardFolderStore(sqlStore db.DB) *DashboardFolderStoreImpl {
|
||||
return &DashboardFolderStoreImpl{store: sqlStore}
|
||||
}
|
||||
|
||||
func (d *DashboardFolderStoreImpl) GetFolderByTitle(ctx context.Context, orgID int64, title string, folderUID *string) (*folder.Folder, error) {
|
||||
if title == "" {
|
||||
return nil, dashboards.ErrFolderTitleEmpty
|
||||
}
|
||||
|
||||
// there is a unique constraint on org_id, folder_uid, title
|
||||
// there are no nested folders so the parent folder id is always 0
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
|
||||
// nolint:staticcheck
|
||||
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, Title: title}
|
||||
err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
s := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true))
|
||||
if folderUID != nil {
|
||||
s = s.Where("folder_uid = ?", *folderUID)
|
||||
} else {
|
||||
s = s.Where("folder_uid IS NULL")
|
||||
}
|
||||
has, err := s.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) {
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
|
||||
// nolint:staticcheck
|
||||
@@ -98,6 +68,74 @@ func (d *DashboardFolderStoreImpl) GetFolderByUID(ctx context.Context, orgID int
|
||||
return dashboards.FromDashboard(&dashboard), nil
|
||||
}
|
||||
|
||||
func (d *DashboardFolderStoreImpl) Get(ctx context.Context, q folder.GetFolderQuery) (*folder.Folder, error) {
|
||||
foldr := &folder.Folder{}
|
||||
err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
exists := false
|
||||
var err error
|
||||
s := strings.Builder{}
|
||||
s.WriteString(`SELECT
|
||||
d.id as id,
|
||||
d.org_id as org_id,
|
||||
d.uid as uid,
|
||||
f0.parent_uid as parent_uid,
|
||||
d.title as title,
|
||||
f0.created as created,
|
||||
f0.updated as updated,
|
||||
f0.description as description,
|
||||
d.version as version,
|
||||
d.created_by as created_by,
|
||||
d.updated_by as updated_by,
|
||||
d.has_acl as has_acl`)
|
||||
if q.WithFullpath {
|
||||
s.WriteString(fmt.Sprintf(`, %s AS fullpath`, getFullpathSQL(d.store.GetDialect())))
|
||||
}
|
||||
if q.WithFullpathUIDs {
|
||||
s.WriteString(fmt.Sprintf(`, %s AS fullpath_uids`, getFullapathUIDsSQL(d.store.GetDialect())))
|
||||
}
|
||||
s.WriteString(" FROM folder f0")
|
||||
s.WriteString(" INNER JOIN dashboard d ON f0.uid = d.uid AND f0.org_id = d.org_id")
|
||||
if q.WithFullpath || q.WithFullpathUIDs {
|
||||
s.WriteString(getFullpathJoinsSQL())
|
||||
}
|
||||
switch {
|
||||
case q.UID != nil:
|
||||
s.WriteString(" WHERE f0.uid = ? AND f0.org_id = ?")
|
||||
exists, err = sess.SQL(s.String(), q.UID, q.OrgID).Get(foldr)
|
||||
// nolint:staticcheck
|
||||
case q.ID != nil:
|
||||
// main difference from sqlstore.Get is that we join to use d.id instead of f0.id here
|
||||
s.WriteString(" WHERE d.id = ?")
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
|
||||
// nolint:staticcheck
|
||||
exists, err = sess.SQL(s.String(), q.ID).Get(foldr)
|
||||
case q.Title != nil:
|
||||
s.WriteString(" WHERE f0.title = ? AND f0.org_id = ?")
|
||||
args := []any{*q.Title, q.OrgID}
|
||||
if q.ParentUID != nil {
|
||||
s.WriteString(" AND f0.parent_uid = ?")
|
||||
args = append(args, *q.ParentUID)
|
||||
} else {
|
||||
s.WriteString(" AND f0.parent_uid IS NULL")
|
||||
}
|
||||
exists, err = sess.SQL(s.String(), args...).Get(foldr)
|
||||
default:
|
||||
return folder.ErrBadRequest.Errorf("one of ID, UID, or Title must be included in the command")
|
||||
}
|
||||
if err != nil {
|
||||
return folder.ErrDatabaseError.Errorf("failed to get folder: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return dashboards.ErrFolderNotFound
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
foldr.Fullpath = strings.TrimLeft(foldr.Fullpath, "/")
|
||||
foldr.FullpathUIDs = strings.TrimLeft(foldr.FullpathUIDs, "/")
|
||||
return foldr.WithURL(), err
|
||||
}
|
||||
|
||||
// GetFolders returns all folders for the given orgID and UIDs.
|
||||
// If no UIDs are provided then all folders for the org are returned.
|
||||
func (d *DashboardFolderStoreImpl) GetFolders(ctx context.Context, orgID int64, uids []string) (map[string]*folder.Folder, error) {
|
||||
|
||||
Reference in New Issue
Block a user