star sqlstore split (#45851)

* start for stars split

* some updates
This commit is contained in:
ying-jeanne 2022-05-16 16:42:02 +02:00 committed by GitHub
parent 522a31c479
commit 2d4065600c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 272 additions and 0 deletions

View File

@ -89,6 +89,7 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/star/starimpl"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/teamguardian"
teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database"
@ -258,6 +259,7 @@ var wireBasicSet = wire.NewSet(
wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)),
ossaccesscontrol.ProvideDashboardPermissions,
wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)),
starimpl.ProvideService,
)
var wireSet = wire.NewSet(

View File

@ -0,0 +1,54 @@
package star
import "errors"
var ErrCommandValidationFailed = errors.New("command missing required fields")
type Star struct {
ID int64 `xorm:"pk autoincr 'id'"`
UserID int64 `xorm:"user_id"`
DashboardID int64 `xorm:"dashboard_id"`
}
// ----------------------
// COMMANDS
type StarDashboardCommand struct {
UserID int64 `xorm:"user_id"`
DashboardID int64 `xorm:"dashboard_id"`
}
func (cmd *StarDashboardCommand) Validate() error {
if cmd.DashboardID == 0 || cmd.UserID == 0 {
return ErrCommandValidationFailed
}
return nil
}
type UnstarDashboardCommand struct {
UserID int64 `xorm:"user_id"`
DashboardID int64 `xorm:"dashboard_id"`
}
func (cmd *UnstarDashboardCommand) Validate() error {
if cmd.DashboardID == 0 || cmd.UserID == 0 {
return ErrCommandValidationFailed
}
return nil
}
// ---------------------
// QUERIES
type GetUserStarsQuery struct {
UserID int64 `xorm:"user_id"`
}
type IsStarredByUserQuery struct {
UserID int64 `xorm:"user_id"`
DashboardID int64 `xorm:"dashboard_id"`
}
type GetUserStarsResult struct {
UserStars map[int64]bool
}

12
pkg/services/star/star.go Normal file
View File

@ -0,0 +1,12 @@
package star
import (
"context"
)
type Service interface {
Add(ctx context.Context, cmd *StarDashboardCommand) error
Delete(ctx context.Context, cmd *UnstarDashboardCommand) error
IsStarredByUser(ctx context.Context, query *IsStarredByUserQuery) (bool, error)
GetByUser(ctx context.Context, cmd *GetUserStarsQuery) (*GetUserStarsResult, error)
}

View File

@ -0,0 +1,42 @@
package starimpl
import (
"context"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/services/star"
)
type Service struct {
store store
}
func ProvideService(db db.DB) *Service {
return &Service{
store: &sqlStore{
db: db,
},
}
}
func (s *Service) Add(ctx context.Context, cmd *star.StarDashboardCommand) error {
if err := cmd.Validate(); err != nil {
return err
}
return s.store.Insert(ctx, cmd)
}
func (s *Service) Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error {
if err := cmd.Validate(); err != nil {
return err
}
return s.store.Delete(ctx, cmd)
}
func (s *Service) IsStarredByUser(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error) {
return s.store.Get(ctx, query)
}
func (s *Service) GetByUser(ctx context.Context, cmd *star.GetUserStarsQuery) (*star.GetUserStarsResult, error) {
return s.store.List(ctx, cmd)
}

View File

@ -0,0 +1,69 @@
package starimpl
import (
"context"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/services/star"
)
type store interface {
Get(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error)
Insert(ctx context.Context, cmd *star.StarDashboardCommand) error
Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error
List(ctx context.Context, query *star.GetUserStarsQuery) (*star.GetUserStarsResult, error)
}
type sqlStore struct {
db db.DB
}
func (s *sqlStore) Get(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error) {
var isStarred bool
err := s.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
rawSQL := "SELECT 1 from star where user_id=? and dashboard_id=?"
results, err := sess.Query(rawSQL, query.UserID, query.DashboardID)
if err != nil {
return err
}
isStarred = len(results) != 0
return nil
})
return isStarred, err
}
func (s *sqlStore) Insert(ctx context.Context, cmd *star.StarDashboardCommand) error {
return s.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
entity := star.Star{
UserID: cmd.UserID,
DashboardID: cmd.DashboardID,
}
_, err := sess.Insert(&entity)
return err
})
}
func (s *sqlStore) Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error {
return s.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
var rawSQL = "DELETE FROM star WHERE user_id=? and dashboard_id=?"
_, err := sess.Exec(rawSQL, cmd.UserID, cmd.DashboardID)
return err
})
}
func (s *sqlStore) List(ctx context.Context, query *star.GetUserStarsQuery) (*star.GetUserStarsResult, error) {
userStars := make(map[int64]bool)
err := s.db.WithDbSession(ctx, func(dbSession *sqlstore.DBSession) error {
var stars = make([]star.Star, 0)
err := dbSession.Where("user_id=?", query.UserID).Find(&stars)
for _, star := range stars {
userStars[star.DashboardID] = true
}
return err
})
return &star.GetUserStarsResult{UserStars: userStars}, err
}

View File

@ -0,0 +1,60 @@
//go:build integration
// +build integration
package starimpl
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/star"
"github.com/stretchr/testify/require"
)
func TestUserStarsDataAccess(t *testing.T) {
t.Run("Testing User Stars Data Access", func(t *testing.T) {
ss := sqlstore.InitTestDB(t)
starStore := sqlStore{db: ss}
t.Run("Given saved star", func(t *testing.T) {
cmd := star.StarDashboardCommand{
DashboardID: 10,
UserID: 12,
}
err := starStore.Insert(context.Background(), &cmd)
require.NoError(t, err)
t.Run("IsStarredByUser should return true when starred", func(t *testing.T) {
query := star.IsStarredByUserQuery{UserID: 12, DashboardID: 10}
isStarred, err := starStore.Get(context.Background(), &query)
require.NoError(t, err)
require.True(t, isStarred)
})
t.Run("IsStarredByUser should return false when not starred", func(t *testing.T) {
query := star.IsStarredByUserQuery{UserID: 12, DashboardID: 12}
isStarred, err := starStore.Get(context.Background(), &query)
require.NoError(t, err)
require.False(t, isStarred)
})
t.Run("List should return a list of size 1", func(t *testing.T) {
query := star.GetUserStarsQuery{UserID: 12}
result, err := starStore.List(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, 1, len(result.UserStars))
})
t.Run("Delete should remove the star", func(t *testing.T) {
deleteQuery := star.UnstarDashboardCommand{DashboardID: 10, UserID: 12}
err := starStore.Delete(context.Background(), &deleteQuery)
require.NoError(t, err)
getQuery := star.IsStarredByUserQuery{UserID: 12, DashboardID: 10}
isStarred, err := starStore.Get(context.Background(), &getQuery)
require.NoError(t, err)
require.False(t, isStarred)
})
})
})
}

View File

@ -0,0 +1,33 @@
package startest
import (
"context"
"github.com/grafana/grafana/pkg/services/star"
)
type FakeStarService struct {
ExpectedStars *star.Star
ExpectedError error
ExpectedUserStars *star.GetUserStarsResult
}
func NewStarServiceFake() *FakeStarService {
return &FakeStarService{}
}
func (f *FakeStarService) IsStarredByUser(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error) {
return true, f.ExpectedError
}
func (f *FakeStarService) Add(ctx context.Context, cmd *star.StarDashboardCommand) error {
return f.ExpectedError
}
func (f *FakeStarService) Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error {
return f.ExpectedError
}
func (f *FakeStarService) GetByUser(ctx context.Context, query *star.GetUserStarsQuery) (*star.GetUserStarsResult, error) {
return f.ExpectedUserStars, f.ExpectedError
}