mirror of
https://github.com/grafana/grafana.git
synced 2025-09-29 03:23:53 +08:00
Dashboards: Split GetDashboardVersions method (#49967)
* Split GetDashboarVersions method * Add sqlstore dialect and tests * Fix signature of PAtchPreference * Add GetDialect to sqlstore and remove GetDashboardVersions * Add GetDialect to db interface * Implement List * add deleted test function * Remove GetDialect from sqlstore interface * Remove deleted method from mock * Refactor test
This commit is contained in:
@ -565,19 +565,20 @@ func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Respon
|
|||||||
return dashboardGuardianResponse(err)
|
return dashboardGuardianResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
query := models.GetDashboardVersionsQuery{
|
query := dashver.ListDashboardVersionsQuery{
|
||||||
OrgId: c.OrgId,
|
OrgID: c.OrgId,
|
||||||
DashboardId: dashID,
|
DashboardID: dashID,
|
||||||
DashboardUID: dashUID,
|
DashboardUID: dashUID,
|
||||||
Limit: c.QueryInt("limit"),
|
Limit: c.QueryInt("limit"),
|
||||||
Start: c.QueryInt("start"),
|
Start: c.QueryInt("start"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := hs.SQLStore.GetDashboardVersions(c.Req.Context(), &query); err != nil {
|
res, err := hs.dashboardVersionService.List(c.Req.Context(), &query)
|
||||||
|
if err != nil {
|
||||||
return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dashID), err)
|
return response.Error(404, fmt.Sprintf("No versions found for dashboardId %d", dashID), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, version := range query.Result {
|
for _, version := range res {
|
||||||
if version.RestoredFrom == version.Version {
|
if version.RestoredFrom == version.Version {
|
||||||
version.Message = "Initial save (created by migration)"
|
version.Message = "Initial save (created by migration)"
|
||||||
continue
|
continue
|
||||||
@ -593,7 +594,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Respon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.JSON(http.StatusOK, query.Result)
|
return response.JSON(http.StatusOK, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDashboardVersion returns the dashboard version with the given ID.
|
// GetDashboardVersion returns the dashboard version with the given ID.
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Get(ctx context.Context, query *GetDashboardVersionQuery) (*DashboardVersion, error)
|
Get(context.Context, *GetDashboardVersionQuery) (*DashboardVersion, error)
|
||||||
DeleteExpired(ctx context.Context, cmd *DeleteExpiredVersionsCommand) error
|
DeleteExpired(context.Context, *DeleteExpiredVersionsCommand) error
|
||||||
|
List(context.Context, *ListDashboardVersionsQuery) ([]*DashboardVersionDTO, error)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ func ProvideService(db db.DB) dashver.Service {
|
|||||||
return &Service{
|
return &Service{
|
||||||
store: &sqlStore{
|
store: &sqlStore{
|
||||||
db: db,
|
db: db,
|
||||||
|
dialect: db.GetDialect(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,3 +64,11 @@ func (s *Service) DeleteExpired(ctx context.Context, cmd *dashver.DeleteExpiredV
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List all dashboard versions for the given dashboard ID.
|
||||||
|
func (s *Service) List(ctx context.Context, query *dashver.ListDashboardVersionsQuery) ([]*dashver.DashboardVersionDTO, error) {
|
||||||
|
if query.Limit == 0 {
|
||||||
|
query.Limit = 1000
|
||||||
|
}
|
||||||
|
return s.store.List(ctx, query)
|
||||||
|
}
|
||||||
|
@ -53,10 +53,24 @@ func TestDeleteExpiredVersions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListDashboardVersions(t *testing.T) {
|
||||||
|
dashboardVersionStore := newDashboardVersionStoreFake()
|
||||||
|
dashboardVersionService := Service{store: dashboardVersionStore}
|
||||||
|
|
||||||
|
t.Run("Get all versions for a given Dashboard ID", func(t *testing.T) {
|
||||||
|
query := dashver.ListDashboardVersionsQuery{}
|
||||||
|
dashboardVersionStore.ExpectedListVersions = []*dashver.DashboardVersionDTO{{}}
|
||||||
|
res, err := dashboardVersionService.List(context.Background(), &query)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 1, len(res))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type FakeDashboardVersionStore struct {
|
type FakeDashboardVersionStore struct {
|
||||||
ExpectedDashboardVersion *dashver.DashboardVersion
|
ExpectedDashboardVersion *dashver.DashboardVersion
|
||||||
ExptectedDeletedVersions int64
|
ExptectedDeletedVersions int64
|
||||||
ExpectedVersions []interface{}
|
ExpectedVersions []interface{}
|
||||||
|
ExpectedListVersions []*dashver.DashboardVersionDTO
|
||||||
ExpectedError error
|
ExpectedError error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,3 +89,7 @@ func (f *FakeDashboardVersionStore) GetBatch(ctx context.Context, cmd *dashver.D
|
|||||||
func (f *FakeDashboardVersionStore) DeleteBatch(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand, versionIdsToDelete []interface{}) (int64, error) {
|
func (f *FakeDashboardVersionStore) DeleteBatch(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand, versionIdsToDelete []interface{}) (int64, error) {
|
||||||
return f.ExptectedDeletedVersions, f.ExpectedError
|
return f.ExptectedDeletedVersions, f.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FakeDashboardVersionStore) List(ctx context.Context, query *dashver.ListDashboardVersionsQuery) ([]*dashver.DashboardVersionDTO, error) {
|
||||||
|
return f.ExpectedListVersions, f.ExpectedError
|
||||||
|
}
|
||||||
|
@ -7,16 +7,19 @@ import (
|
|||||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
)
|
)
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
Get(context.Context, *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error)
|
Get(context.Context, *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error)
|
||||||
GetBatch(context.Context, *dashver.DeleteExpiredVersionsCommand, int, int) ([]interface{}, error)
|
GetBatch(context.Context, *dashver.DeleteExpiredVersionsCommand, int, int) ([]interface{}, error)
|
||||||
DeleteBatch(context.Context, *dashver.DeleteExpiredVersionsCommand, []interface{}) (int64, error)
|
DeleteBatch(context.Context, *dashver.DeleteExpiredVersionsCommand, []interface{}) (int64, error)
|
||||||
|
List(context.Context, *dashver.ListDashboardVersionsQuery) ([]*dashver.DashboardVersionDTO, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sqlStore struct {
|
type sqlStore struct {
|
||||||
db db.DB
|
db db.DB
|
||||||
|
dialect migrator.Dialect
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) {
|
func (ss *sqlStore) Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) {
|
||||||
@ -75,3 +78,38 @@ func (ss *sqlStore) DeleteBatch(ctx context.Context, cmd *dashver.DeleteExpiredV
|
|||||||
})
|
})
|
||||||
return deleted, err
|
return deleted, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss *sqlStore) List(ctx context.Context, query *dashver.ListDashboardVersionsQuery) ([]*dashver.DashboardVersionDTO, error) {
|
||||||
|
var dashboardVersion []*dashver.DashboardVersionDTO
|
||||||
|
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
err := sess.Table("dashboard_version").
|
||||||
|
Select(`dashboard_version.id,
|
||||||
|
dashboard_version.dashboard_id,
|
||||||
|
dashboard_version.parent_version,
|
||||||
|
dashboard_version.restored_from,
|
||||||
|
dashboard_version.version,
|
||||||
|
dashboard_version.created,
|
||||||
|
dashboard_version.created_by as created_by_id,
|
||||||
|
dashboard_version.message,
|
||||||
|
dashboard_version.data,`+
|
||||||
|
ss.dialect.Quote("user")+`.login as created_by`).
|
||||||
|
Join("LEFT", ss.dialect.Quote("user"), `dashboard_version.created_by = `+ss.dialect.Quote("user")+`.id`).
|
||||||
|
Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`).
|
||||||
|
Where("dashboard_version.dashboard_id=? AND dashboard.org_id=?", query.DashboardID, query.OrgID).
|
||||||
|
OrderBy("dashboard_version.version DESC").
|
||||||
|
Limit(query.Limit, query.Start).
|
||||||
|
Find(&dashboardVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dashboardVersion) < 1 {
|
||||||
|
return dashver.ErrNoVersionsForDashboardID
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dashboardVersion, nil
|
||||||
|
}
|
||||||
|
@ -30,8 +30,8 @@ func TestIntegrationGetDashboardVersion(t *testing.T) {
|
|||||||
|
|
||||||
res, err := dashVerStore.Get(context.Background(), &query)
|
res, err := dashVerStore.Get(context.Background(), &query)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, query.DashboardID, savedDash.Id)
|
assert.Equal(t, query.DashboardID, savedDash.Id)
|
||||||
require.Equal(t, query.Version, savedDash.Version)
|
assert.Equal(t, query.Version, savedDash.Version)
|
||||||
|
|
||||||
dashCmd := &models.Dashboard{
|
dashCmd := &models.Dashboard{
|
||||||
Id: res.ID,
|
Id: res.ID,
|
||||||
@ -41,8 +41,8 @@ func TestIntegrationGetDashboardVersion(t *testing.T) {
|
|||||||
err = getDashboard(t, ss, dashCmd)
|
err = getDashboard(t, ss, dashCmd)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
require.EqualValues(t, dashCmd.Data.Get("uid"), res.Data.Get("uid"))
|
assert.EqualValues(t, dashCmd.Data.Get("uid"), res.Data.Get("uid"))
|
||||||
require.EqualValues(t, dashCmd.Data.Get("orgId"), res.Data.Get("orgId"))
|
assert.EqualValues(t, dashCmd.Data.Get("orgId"), res.Data.Get("orgId"))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Attempt to get a version that doesn't exist", func(t *testing.T) {
|
t.Run("Attempt to get a version that doesn't exist", func(t *testing.T) {
|
||||||
@ -54,7 +54,7 @@ func TestIntegrationGetDashboardVersion(t *testing.T) {
|
|||||||
|
|
||||||
_, err := dashVerStore.Get(context.Background(), &query)
|
_, err := dashVerStore.Get(context.Background(), &query)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Equal(t, models.ErrDashboardVersionNotFound, err)
|
assert.Equal(t, models.ErrDashboardVersionNotFound, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +79,44 @@ func TestIntegrationDeleteExpiredVersions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntegrationListDashboardVersions(t *testing.T) {
|
||||||
|
ss := sqlstore.InitTestDB(t)
|
||||||
|
dashVerStore := sqlStore{db: ss, dialect: ss.Dialect}
|
||||||
|
savedDash := insertTestDashboard(t, ss, "test dash 43", 1, 0, false, "diff-all")
|
||||||
|
|
||||||
|
t.Run("Get all versions for a given Dashboard ID", func(t *testing.T) {
|
||||||
|
query := dashver.ListDashboardVersionsQuery{
|
||||||
|
DashboardID: savedDash.Id,
|
||||||
|
OrgID: 1,
|
||||||
|
Limit: 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := dashVerStore.List(context.Background(), &query)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(res))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Attempt to get the versions for a non-existent Dashboard ID", func(t *testing.T) {
|
||||||
|
query := dashver.ListDashboardVersionsQuery{DashboardID: int64(999), OrgID: 1, Limit: 1000}
|
||||||
|
|
||||||
|
res, err := dashVerStore.List(context.Background(), &query)
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.ErrorIs(t, dashver.ErrNoVersionsForDashboardID, err)
|
||||||
|
assert.Equal(t, 0, len(res))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get all versions for an updated dashboard", func(t *testing.T) {
|
||||||
|
updateTestDashboard(t, ss, savedDash, map[string]interface{}{
|
||||||
|
"tags": "different-tag",
|
||||||
|
})
|
||||||
|
query := dashver.ListDashboardVersionsQuery{DashboardID: savedDash.Id, OrgID: 1, Limit: 1000}
|
||||||
|
res, err := dashVerStore.List(context.Background(), &query)
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, 2, len(res))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func getDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *models.Dashboard) error {
|
func getDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *models.Dashboard) error {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
return sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
@ -95,6 +133,7 @@ func getDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *models.D
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string, orgId int64,
|
func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string, orgId int64,
|
||||||
folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard {
|
folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@ -149,3 +188,64 @@ func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string
|
|||||||
|
|
||||||
return dash
|
return dash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *models.Dashboard, data map[string]interface{}) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data["id"] = dashboard.Id
|
||||||
|
|
||||||
|
parentVersion := dashboard.Version
|
||||||
|
|
||||||
|
cmd := models.SaveDashboardCommand{
|
||||||
|
OrgId: dashboard.OrgId,
|
||||||
|
Overwrite: true,
|
||||||
|
Dashboard: simplejson.NewFromAny(data),
|
||||||
|
}
|
||||||
|
var dash *models.Dashboard
|
||||||
|
err := sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
|
var existing models.Dashboard
|
||||||
|
dash = cmd.GetDashboardModel()
|
||||||
|
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, dashWithIdExists)
|
||||||
|
|
||||||
|
if dash.Version != existing.Version {
|
||||||
|
dash.SetVersion(existing.Version)
|
||||||
|
dash.Version = existing.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
dash.SetVersion(dash.Version + 1)
|
||||||
|
dash.Created = time.Now()
|
||||||
|
dash.Updated = time.Now()
|
||||||
|
dash.Id = dashboard.Id
|
||||||
|
dash.Uid = util.GenerateShortUID()
|
||||||
|
|
||||||
|
_, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
err = sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
|
dashVersion := &models.DashboardVersion{
|
||||||
|
DashboardId: dash.Id,
|
||||||
|
ParentVersion: parentVersion,
|
||||||
|
RestoredFrom: cmd.RestoredFrom,
|
||||||
|
Version: dash.Version,
|
||||||
|
Created: time.Now(),
|
||||||
|
CreatedBy: dash.UpdatedBy,
|
||||||
|
Message: cmd.Message,
|
||||||
|
Data: dash.Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
if affectedRows, err := sess.Insert(dashVersion); err != nil {
|
||||||
|
return err
|
||||||
|
} else if affectedRows == 0 {
|
||||||
|
return models.ErrDashboardNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
type FakeDashboardVersionService struct {
|
type FakeDashboardVersionService struct {
|
||||||
ExpectedDashboardVersion *dashver.DashboardVersion
|
ExpectedDashboardVersion *dashver.DashboardVersion
|
||||||
ExpectedDashboardVersions []*dashver.DashboardVersion
|
ExpectedDashboardVersions []*dashver.DashboardVersion
|
||||||
|
ExpectedListDashboarVersions []*dashver.DashboardVersionDTO
|
||||||
counter int
|
counter int
|
||||||
ExpectedError error
|
ExpectedError error
|
||||||
}
|
}
|
||||||
@ -28,3 +29,7 @@ func (f *FakeDashboardVersionService) Get(ctx context.Context, query *dashver.Ge
|
|||||||
func (f *FakeDashboardVersionService) DeleteExpired(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand) error {
|
func (f *FakeDashboardVersionService) DeleteExpired(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand) error {
|
||||||
return f.ExpectedError
|
return f.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FakeDashboardVersionService) List(ctx context.Context, query *dashver.ListDashboardVersionsQuery) ([]*dashver.DashboardVersionDTO, error) {
|
||||||
|
return f.ExpectedListDashboarVersions, f.ExpectedError
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrDashboardVersionNotFound = errors.New("dashboard version not found")
|
ErrDashboardVersionNotFound = errors.New("dashboard version not found")
|
||||||
ErrNoVersionsForDashboardId = errors.New("no dashboard versions found for the given DashboardId")
|
ErrNoVersionsForDashboardID = errors.New("no dashboard versions found for the given DashboardId")
|
||||||
)
|
)
|
||||||
|
|
||||||
type DashboardVersion struct {
|
type DashboardVersion struct {
|
||||||
@ -35,3 +35,23 @@ type GetDashboardVersionQuery struct {
|
|||||||
type DeleteExpiredVersionsCommand struct {
|
type DeleteExpiredVersionsCommand struct {
|
||||||
DeletedRows int64
|
DeletedRows int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ListDashboardVersionsQuery struct {
|
||||||
|
DashboardID int64
|
||||||
|
DashboardUID string
|
||||||
|
OrgID int64
|
||||||
|
Limit int
|
||||||
|
Start int
|
||||||
|
}
|
||||||
|
|
||||||
|
type DashboardVersionDTO struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
DashboardID int64 `json:"dashboardId"`
|
||||||
|
DashboardUID string `json:"dashboardUid"`
|
||||||
|
ParentVersion int `json:"parentVersion"`
|
||||||
|
RestoredFrom int `json:"restoredFrom"`
|
||||||
|
Version int `json:"version"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
CreatedBy string `json:"createdBy"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
@ -8,6 +8,6 @@ type Service interface {
|
|||||||
GetWithDefaults(context.Context, *GetPreferenceWithDefaultsQuery) (*Preference, error)
|
GetWithDefaults(context.Context, *GetPreferenceWithDefaultsQuery) (*Preference, error)
|
||||||
Get(context.Context, *GetPreferenceQuery) (*Preference, error)
|
Get(context.Context, *GetPreferenceQuery) (*Preference, error)
|
||||||
Save(context.Context, *SavePreferenceCommand) error
|
Save(context.Context, *SavePreferenceCommand) error
|
||||||
Patch(ctx context.Context, cmd *PatchPreferenceCommand) error
|
Patch(context.Context, *PatchPreferenceCommand) error
|
||||||
GetDefaults() *Preference
|
GetDefaults() *Preference
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,11 @@ package sqlstore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/util"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -253,3 +256,64 @@ func updateThumbnailState(t *testing.T, sqlStore *SQLStore, dashboardUID string,
|
|||||||
err := sqlStore.UpdateThumbnailState(context.Background(), &cmd)
|
err := sqlStore.UpdateThumbnailState(context.Background(), &cmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data["id"] = dashboard.Id
|
||||||
|
|
||||||
|
parentVersion := dashboard.Version
|
||||||
|
|
||||||
|
cmd := models.SaveDashboardCommand{
|
||||||
|
OrgId: dashboard.OrgId,
|
||||||
|
Overwrite: true,
|
||||||
|
Dashboard: simplejson.NewFromAny(data),
|
||||||
|
}
|
||||||
|
var dash *models.Dashboard
|
||||||
|
err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
|
||||||
|
var existing models.Dashboard
|
||||||
|
dash = cmd.GetDashboardModel()
|
||||||
|
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, dashWithIdExists)
|
||||||
|
|
||||||
|
if dash.Version != existing.Version {
|
||||||
|
dash.SetVersion(existing.Version)
|
||||||
|
dash.Version = existing.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
dash.SetVersion(dash.Version + 1)
|
||||||
|
dash.Created = time.Now()
|
||||||
|
dash.Updated = time.Now()
|
||||||
|
dash.Id = dashboard.Id
|
||||||
|
dash.Uid = util.GenerateShortUID()
|
||||||
|
|
||||||
|
_, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
|
||||||
|
dashVersion := &models.DashboardVersion{
|
||||||
|
DashboardId: dash.Id,
|
||||||
|
ParentVersion: parentVersion,
|
||||||
|
RestoredFrom: cmd.RestoredFrom,
|
||||||
|
Version: dash.Version,
|
||||||
|
Created: time.Now(),
|
||||||
|
CreatedBy: dash.UpdatedBy,
|
||||||
|
Message: cmd.Message,
|
||||||
|
Data: dash.Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
if affectedRows, err := sess.Insert(dashVersion); err != nil {
|
||||||
|
return err
|
||||||
|
} else if affectedRows == 0 {
|
||||||
|
return models.ErrDashboardNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package sqlstore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetDashboardVersions gets all dashboard versions for the given dashboard ID.
|
|
||||||
func (ss *SQLStore) GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error {
|
|
||||||
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
|
||||||
if query.Limit == 0 {
|
|
||||||
query.Limit = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
err := sess.Table("dashboard_version").
|
|
||||||
Select(`dashboard_version.id,
|
|
||||||
dashboard_version.dashboard_id,
|
|
||||||
dashboard_version.parent_version,
|
|
||||||
dashboard_version.restored_from,
|
|
||||||
dashboard_version.version,
|
|
||||||
dashboard_version.created,
|
|
||||||
dashboard_version.created_by as created_by_id,
|
|
||||||
dashboard_version.message,
|
|
||||||
dashboard_version.data,`+
|
|
||||||
dialect.Quote("user")+`.login as created_by`).
|
|
||||||
Join("LEFT", dialect.Quote("user"), `dashboard_version.created_by = `+dialect.Quote("user")+`.id`).
|
|
||||||
Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`).
|
|
||||||
Where("dashboard_version.dashboard_id=? AND dashboard.org_id=?", query.DashboardId, query.OrgId).
|
|
||||||
OrderBy("dashboard_version.version DESC").
|
|
||||||
Limit(query.Limit, query.Start).
|
|
||||||
Find(&query.Result)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(query.Result) < 1 {
|
|
||||||
return models.ErrNoVersionsForDashboardId
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
package sqlstore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
data["id"] = dashboard.Id
|
|
||||||
|
|
||||||
parentVersion := dashboard.Version
|
|
||||||
|
|
||||||
cmd := models.SaveDashboardCommand{
|
|
||||||
OrgId: dashboard.OrgId,
|
|
||||||
Overwrite: true,
|
|
||||||
Dashboard: simplejson.NewFromAny(data),
|
|
||||||
}
|
|
||||||
var dash *models.Dashboard
|
|
||||||
err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
|
|
||||||
var existing models.Dashboard
|
|
||||||
dash = cmd.GetDashboardModel()
|
|
||||||
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, dashWithIdExists)
|
|
||||||
|
|
||||||
if dash.Version != existing.Version {
|
|
||||||
dash.SetVersion(existing.Version)
|
|
||||||
dash.Version = existing.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
dash.SetVersion(dash.Version + 1)
|
|
||||||
dash.Created = time.Now()
|
|
||||||
dash.Updated = time.Now()
|
|
||||||
dash.Id = dashboard.Id
|
|
||||||
dash.Uid = util.GenerateShortUID()
|
|
||||||
|
|
||||||
_, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
|
|
||||||
dashVersion := &models.DashboardVersion{
|
|
||||||
DashboardId: dash.Id,
|
|
||||||
ParentVersion: parentVersion,
|
|
||||||
RestoredFrom: cmd.RestoredFrom,
|
|
||||||
Version: dash.Version,
|
|
||||||
Created: time.Now(),
|
|
||||||
CreatedBy: dash.UpdatedBy,
|
|
||||||
Message: cmd.Message,
|
|
||||||
Data: dash.Data,
|
|
||||||
}
|
|
||||||
|
|
||||||
if affectedRows, err := sess.Insert(dashVersion); err != nil {
|
|
||||||
return err
|
|
||||||
} else if affectedRows == 0 {
|
|
||||||
return models.ErrDashboardNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIntegrationGetDashboardVersions(t *testing.T) {
|
|
||||||
sqlStore := InitTestDB(t)
|
|
||||||
savedDash := insertTestDashboard(t, sqlStore, "test dash 43", 1, 0, false, "diff-all")
|
|
||||||
|
|
||||||
t.Run("Get all versions for a given Dashboard ID", func(t *testing.T) {
|
|
||||||
query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
|
|
||||||
|
|
||||||
err := sqlStore.GetDashboardVersions(context.Background(), &query)
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.Equal(t, 1, len(query.Result))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Attempt to get the versions for a non-existent Dashboard ID", func(t *testing.T) {
|
|
||||||
query := models.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1}
|
|
||||||
|
|
||||||
err := sqlStore.GetDashboardVersions(context.Background(), &query)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Equal(t, models.ErrNoVersionsForDashboardId, err)
|
|
||||||
require.Equal(t, 0, len(query.Result))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Get all versions for an updated dashboard", func(t *testing.T) {
|
|
||||||
updateTestDashboard(t, sqlStore, savedDash, map[string]interface{}{
|
|
||||||
"tags": "different-tag",
|
|
||||||
})
|
|
||||||
query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
|
|
||||||
err := sqlStore.GetDashboardVersions(context.Background(), &query)
|
|
||||||
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.Equal(t, 2, len(query.Result))
|
|
||||||
})
|
|
||||||
}
|
|
@ -4,9 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DB interface {
|
type DB interface {
|
||||||
WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
||||||
WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
||||||
|
GetDialect() migrator.Dialect
|
||||||
}
|
}
|
||||||
|
@ -344,10 +344,6 @@ func (m *SQLStoreMock) InTransaction(ctx context.Context, fn func(ctx context.Co
|
|||||||
return m.ExpectedError
|
return m.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SQLStoreMock) GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error {
|
|
||||||
return m.ExpectedError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m SQLStoreMock) GetDashboardAclInfoList(ctx context.Context, query *models.GetDashboardAclInfoListQuery) error {
|
func (m SQLStoreMock) GetDashboardAclInfoList(ctx context.Context, query *models.GetDashboardAclInfoListQuery) error {
|
||||||
query.Result = m.ExpectedDashboardAclInfoList
|
query.Result = m.ExpectedDashboardAclInfoList
|
||||||
return m.ExpectedError
|
return m.ExpectedError
|
||||||
|
@ -154,6 +154,11 @@ func (ss *SQLStore) Quote(value string) string {
|
|||||||
return ss.engine.Quote(value)
|
return ss.engine.Quote(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDialect return the dialect
|
||||||
|
func (ss *SQLStore) GetDialect() migrator.Dialect {
|
||||||
|
return ss.Dialect
|
||||||
|
}
|
||||||
|
|
||||||
func (ss *SQLStore) ensureMainOrgAndAdminUser() error {
|
func (ss *SQLStore) ensureMainOrgAndAdminUser() error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
@ -73,7 +73,6 @@ type Store interface {
|
|||||||
GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error
|
GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error
|
||||||
WithTransactionalDbSession(ctx context.Context, callback DBTransactionFunc) error
|
WithTransactionalDbSession(ctx context.Context, callback DBTransactionFunc) error
|
||||||
InTransaction(ctx context.Context, fn func(ctx context.Context) error) error
|
InTransaction(ctx context.Context, fn func(ctx context.Context) error) error
|
||||||
GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error
|
|
||||||
CreatePlaylist(ctx context.Context, cmd *models.CreatePlaylistCommand) error
|
CreatePlaylist(ctx context.Context, cmd *models.CreatePlaylistCommand) error
|
||||||
UpdatePlaylist(ctx context.Context, cmd *models.UpdatePlaylistCommand) error
|
UpdatePlaylist(ctx context.Context, cmd *models.UpdatePlaylistCommand) error
|
||||||
GetPlaylist(ctx context.Context, query *models.GetPlaylistByIdQuery) error
|
GetPlaylist(ctx context.Context, query *models.GetPlaylistByIdQuery) error
|
||||||
|
Reference in New Issue
Block a user