feat(playlist): changes to relation table

Also introduces an abstraction between playlist and dashboard.
This will make it possible to att search, and tag filtering to
playlists without any major refactoring
This commit is contained in:
bergquist
2016-01-08 17:32:55 +01:00
parent 0ea01f24a8
commit 8a38991270
6 changed files with 246 additions and 64 deletions

View File

@@ -176,7 +176,7 @@ func Register(r *macaron.Macaron) {
r.Group("/playlists", func() { r.Group("/playlists", func() {
r.Get("/", wrap(SearchPlaylists)) r.Get("/", wrap(SearchPlaylists))
r.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist)) r.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist))
r.Get("/:id/dashboards", ValidateOrgPlaylist, wrap(GetPlaylistDashboards)) r.Get("/:id/playlistitems", ValidateOrgPlaylist, wrap(GetPlaylistItems))
r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist)) r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist))
r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistQuery{}), ValidateOrgPlaylist, wrap(UpdatePlaylist)) r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistQuery{}), ValidateOrgPlaylist, wrap(UpdatePlaylist))
r.Post("/", reqEditorRole, bind(m.CreatePlaylistQuery{}), wrap(CreatePlaylist)) r.Post("/", reqEditorRole, bind(m.CreatePlaylistQuery{}), wrap(CreatePlaylist))

View File

@@ -1,9 +1,12 @@
package api package api
import ( import (
"errors"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"strconv"
) )
func ValidateOrgPlaylist(c *middleware.Context) { func ValidateOrgPlaylist(c *middleware.Context) {
@@ -52,19 +55,67 @@ func GetPlaylist(c *middleware.Context) Response {
return ApiError(500, "Playlist not found", err) return ApiError(500, "Playlist not found", err)
} }
return Json(200, cmd.Result) itemQuery := m.GetPlaylistItemsByIdQuery{PlaylistId: id}
if err := bus.Dispatch(&itemQuery); err != nil {
log.Warn("itemQuery failed: %v", err)
return ApiError(500, "Playlist items not found", err)
}
playlistDTOs := make([]m.PlaylistItemDTO, 0)
for _, item := range *itemQuery.Result {
playlistDTOs = append(playlistDTOs, m.PlaylistItemDTO{
Id: item.Id,
PlaylistId: item.PlaylistId,
Type: item.Type,
Value: item.Value,
Order: item.Order,
})
}
dto := &m.PlaylistDTO{
Id: cmd.Result.Id,
Title: cmd.Result.Title,
Timespan: cmd.Result.Timespan,
OrgId: cmd.Result.OrgId,
Items: playlistDTOs,
}
return Json(200, dto)
} }
func GetPlaylistDashboards(c *middleware.Context) Response { func LoadPlaylistItems(id int64) ([]m.PlaylistItem, error) {
id := c.ParamsInt64(":id") itemQuery := m.GetPlaylistItemsByIdQuery{PlaylistId: id}
if err := bus.Dispatch(&itemQuery); err != nil {
log.Warn("itemQuery failed: %v", err)
return nil, errors.New("Playlist not found")
}
query := m.GetPlaylistDashboardsQuery{Id: id} return *itemQuery.Result, nil
if err := bus.Dispatch(&query); err != nil { }
return ApiError(500, "Playlist not found", err)
func LoadPlaylistDashboards(id int64) ([]m.PlaylistDashboardDto, error) {
playlistItems, _ := LoadPlaylistItems(id)
dashboardIds := make([]int64, 0)
for _, i := range playlistItems {
dashboardId, _ := strconv.ParseInt(i.Value, 10, 64)
dashboardIds = append(dashboardIds, dashboardId)
}
if len(dashboardIds) == 0 {
return make([]m.PlaylistDashboardDto, 0), nil
}
dashboardQuery := m.GetPlaylistDashboardsQuery{DashboardIds: dashboardIds}
if err := bus.Dispatch(&dashboardQuery); err != nil {
log.Warn("dashboardquery failed: %v", err)
return nil, errors.New("Playlist not found")
} }
dtos := make([]m.PlaylistDashboardDto, 0) dtos := make([]m.PlaylistDashboardDto, 0)
for _, item := range *query.Result { for _, item := range *dashboardQuery.Result {
dtos = append(dtos, m.PlaylistDashboardDto{ dtos = append(dtos, m.PlaylistDashboardDto{
Id: item.Id, Id: item.Id,
Slug: item.Slug, Slug: item.Slug,
@@ -73,7 +124,43 @@ func GetPlaylistDashboards(c *middleware.Context) Response {
}) })
} }
return Json(200, dtos) return dtos, nil
}
func GetPlaylistItems(c *middleware.Context) Response {
id := c.ParamsInt64(":id")
items, err := LoadPlaylistItems(id)
if err != nil {
return ApiError(500, "Could not load playlist items", err)
}
playlistDTOs := make([]m.PlaylistItemDTO, 0)
for _, item := range items {
playlistDTOs = append(playlistDTOs, m.PlaylistItemDTO{
Id: item.Id,
PlaylistId: item.PlaylistId,
Type: item.Type,
Value: item.Value,
Order: item.Order,
Title: item.Title,
})
}
return Json(200, playlistDTOs)
}
func GetPlaylistDashboards(c *middleware.Context) Response {
id := c.ParamsInt64(":id")
playlists, err := LoadPlaylistDashboards(id)
if err != nil {
return ApiError(500, "Could not load dashboards", err)
}
return Json(200, playlists)
} }
func DeletePlaylist(c *middleware.Context) Response { func DeletePlaylist(c *middleware.Context) Response {
@@ -103,5 +190,25 @@ func UpdatePlaylist(c *middleware.Context, query m.UpdatePlaylistQuery) Response
return ApiError(500, "Failed to save playlist", err) return ApiError(500, "Failed to save playlist", err)
} }
items, err := LoadPlaylistItems(query.Id)
playlistDTOs := make([]m.PlaylistItemDTO, 0)
for _, item := range items {
playlistDTOs = append(playlistDTOs, m.PlaylistItemDTO{
Id: item.Id,
PlaylistId: item.PlaylistId,
Type: item.Type,
Value: item.Value,
Order: item.Order,
})
}
if err != nil {
return ApiError(500, "Failed to save playlist", err)
}
query.Result.Items = playlistDTOs
return Json(200, query.Result) return Json(200, query.Result)
} }

View File

@@ -14,18 +14,42 @@ var (
type Playlist struct { type Playlist struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Type string `json:"type"`
Timespan string `json:"timespan"` Timespan string `json:"timespan"`
Data []int64 `json:"data"`
OrgId int64 `json:"-"` OrgId int64 `json:"-"`
} }
type PlaylistDTO struct {
Id int64 `json:"id"`
Title string `json:"title"`
Timespan string `json:"timespan"`
OrgId int64 `json:"-"`
Items []PlaylistItemDTO `json:"items"`
}
type PlaylistItemDTO struct {
Id int64 `json:"id"`
PlaylistId int64 `json:"playlistid"`
Type string `json:"type"`
Title string `json:"title"`
Value string `json:"value"`
Order int `json:"order"`
}
type PlaylistDashboard struct { type PlaylistDashboard struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Slug string `json:"slug"` Slug string `json:"slug"`
Title string `json:"title"` Title string `json:"title"`
} }
type PlaylistItem struct {
Id int64
PlaylistId int64
Type string
Value string
Order int
Title string
}
func (this PlaylistDashboard) TableName() string { func (this PlaylistDashboard) TableName() string {
return "dashboard" return "dashboard"
} }
@@ -60,9 +84,9 @@ type UpdatePlaylistQuery struct {
Title string Title string
Type string Type string
Timespan string Timespan string
Data []int64 Items []PlaylistItemDTO
Result *Playlist Result *PlaylistDTO
} }
type CreatePlaylistQuery struct { type CreatePlaylistQuery struct {
@@ -71,6 +95,7 @@ type CreatePlaylistQuery struct {
Timespan string Timespan string
Data []int64 Data []int64
OrgId int64 OrgId int64
Items []PlaylistItemDTO
Result *Playlist Result *Playlist
} }
@@ -80,8 +105,13 @@ type GetPlaylistByIdQuery struct {
Result *Playlist Result *Playlist
} }
type GetPlaylistItemsByIdQuery struct {
PlaylistId int64
Result *[]PlaylistItem
}
type GetPlaylistDashboardsQuery struct { type GetPlaylistDashboardsQuery struct {
Id int64 DashboardIds []int64
Result *PlaylistDashboards Result *PlaylistDashboards
} }

View File

@@ -220,26 +220,6 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
} }
} }
var playlists = make(m.Playlists, 0)
err = sess.Where("data LIKE ?", fmt.Sprintf("%%%v%%", dashboard.Id)).Find(&playlists)
if err != nil {
return err
}
for _, playlist := range playlists {
filteredData := make([]int64, 0)
for _, plDashboardId := range playlist.Data {
if plDashboardId != dashboard.Id {
filteredData = append(filteredData, plDashboardId)
}
}
playlist.Data = filteredData
_, err = sess.Id(playlist.Id).Cols("data").Update(playlist)
if err != nil {
return err
}
}
return nil return nil
}) })
} }

View File

@@ -8,8 +8,6 @@ func addPlaylistMigrations(mg *Migrator) {
Columns: []*Column{ Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "data", Type: DB_Text, Nullable: false},
{Name: "timespan", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "timespan", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "org_id", Type: DB_BigInt, Nullable: false}, {Name: "org_id", Type: DB_BigInt, Nullable: false},
}, },
@@ -17,4 +15,18 @@ func addPlaylistMigrations(mg *Migrator) {
// create table // create table
mg.AddMigration("create playlist table v1", NewAddTableMigration(playlistV1)) mg.AddMigration("create playlist table v1", NewAddTableMigration(playlistV1))
playlistItemV1 := Table{
Name: "playlist_item",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "playlist_id", Type: DB_BigInt, Nullable: false},
{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "value", Type: DB_Text, Nullable: false},
{Name: "title", Type: DB_Text, Nullable: false},
{Name: "order", Type: DB_Int, Nullable: false},
},
}
mg.AddMigration("create playlist item table v1", NewAddTableMigration(playlistItemV1))
} }

View File

@@ -1,6 +1,7 @@
package sqlstore package sqlstore
import ( import (
"fmt"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
@@ -14,6 +15,7 @@ func init() {
bus.AddHandler("sql", SearchPlaylists) bus.AddHandler("sql", SearchPlaylists)
bus.AddHandler("sql", GetPlaylist) bus.AddHandler("sql", GetPlaylist)
bus.AddHandler("sql", GetPlaylistDashboards) bus.AddHandler("sql", GetPlaylistDashboards)
bus.AddHandler("sql", GetPlaylistItem)
} }
func CreatePlaylist(query *m.CreatePlaylistQuery) error { func CreatePlaylist(query *m.CreatePlaylistQuery) error {
@@ -21,14 +23,27 @@ func CreatePlaylist(query *m.CreatePlaylistQuery) error {
playlist := m.Playlist{ playlist := m.Playlist{
Title: query.Title, Title: query.Title,
Type: query.Type,
Data: query.Data,
Timespan: query.Timespan, Timespan: query.Timespan,
OrgId: query.OrgId, OrgId: query.OrgId,
} }
_, err = x.Insert(&playlist) _, err = x.Insert(&playlist)
fmt.Printf("%v", playlist.Id)
playlistItems := make([]m.PlaylistItem, 0)
for _, item := range query.Items {
playlistItems = append(playlistItems, m.PlaylistItem{
PlaylistId: playlist.Id,
Type: item.Type,
Value: item.Value,
Order: item.Order,
Title: item.Title,
})
}
_, err = x.Insert(&playlistItems)
query.Result = &playlist query.Result = &playlist
return err return err
} }
@@ -39,8 +54,6 @@ func UpdatePlaylist(query *m.UpdatePlaylistQuery) error {
playlist := m.Playlist{ playlist := m.Playlist{
Id: query.Id, Id: query.Id,
Title: query.Title, Title: query.Title,
Type: query.Type,
Data: query.Data,
Timespan: query.Timespan, Timespan: query.Timespan,
} }
@@ -50,9 +63,39 @@ func UpdatePlaylist(query *m.UpdatePlaylistQuery) error {
return m.ErrPlaylistNotFound return m.ErrPlaylistNotFound
} }
_, err = x.Id(query.Id).Cols("id", "title", "data", "timespan").Update(&playlist) query.Result = &m.PlaylistDTO{
Id: playlist.Id,
OrgId: playlist.OrgId,
Title: playlist.Title,
Timespan: playlist.Timespan,
}
_, err = x.Id(query.Id).Cols("id", "title", "timespan").Update(&playlist)
if err != nil {
return err
}
rawSql := "DELETE FROM playlist_item WHERE playlist_id = ?"
_, err = x.Exec(rawSql, query.Id)
if err != nil {
return err
}
playlistItems := make([]m.PlaylistItem, 0)
for _, item := range query.Items {
playlistItems = append(playlistItems, m.PlaylistItem{
PlaylistId: playlist.Id,
Type: item.Type,
Value: item.Value,
Order: item.Order,
Title: item.Title,
})
}
_, err = x.Insert(&playlistItems)
query.Result = &playlist
return err return err
} }
@@ -63,6 +106,7 @@ func GetPlaylist(query *m.GetPlaylistByIdQuery) error {
playlist := m.Playlist{} playlist := m.Playlist{}
_, err := x.Id(query.Id).Get(&playlist) _, err := x.Id(query.Id).Get(&playlist)
query.Result = &playlist query.Result = &playlist
return err return err
@@ -74,9 +118,17 @@ func DeletePlaylist(query *m.DeletePlaylistQuery) error {
} }
return inTransaction(func(sess *xorm.Session) error { return inTransaction(func(sess *xorm.Session) error {
var rawSql = "DELETE FROM playlist WHERE id = ?" var rawPlaylistSql = "DELETE FROM playlist WHERE id = ?"
_, err := sess.Exec(rawSql, query.Id) _, err := sess.Exec(rawPlaylistSql, query.Id)
if err != nil {
return err return err
}
var rawItemSql = "DELETE FROM playlist_item WHERE playlist_id = ?"
_, err2 := sess.Exec(rawItemSql, query.Id)
return err2
}) })
} }
@@ -96,31 +148,32 @@ func SearchPlaylists(query *m.PlaylistQuery) error {
return err return err
} }
func GetPlaylistItem(query *m.GetPlaylistItemsByIdQuery) error {
if query.PlaylistId == 0 {
return m.ErrCommandValidationFailed
}
var playlistItems = make([]m.PlaylistItem, 0)
err := x.Where("playlist_id=?", query.PlaylistId).Find(&playlistItems)
query.Result = &playlistItems
return err
}
func GetPlaylistDashboards(query *m.GetPlaylistDashboardsQuery) error { func GetPlaylistDashboards(query *m.GetPlaylistDashboardsQuery) error {
if query.Id == 0 { if len(query.DashboardIds) == 0 {
return m.ErrCommandValidationFailed return m.ErrCommandValidationFailed
} }
var dashboards = make(m.PlaylistDashboards, 0) var dashboards = make(m.PlaylistDashboards, 0)
var playlist = m.Playlist{}
hasPlaylist, err := x.Id(query.Id).Get(&playlist)
err := x.In("id", query.DashboardIds).Find(&dashboards)
query.Result = &dashboards query.Result = &dashboards
if err != nil { if err != nil {
return err return err
} }
if !hasPlaylist || len(playlist.Data) == 0 {
return nil
}
err = x.In("id", playlist.Data).Find(&dashboards)
if err != nil {
return err
}
return nil return nil
} }