mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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
226 lines
5.0 KiB
Go
226 lines
5.0 KiB
Go
package sqlstore
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"github.com/go-xorm/xorm"
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
"github.com/grafana/grafana/pkg/metrics"
|
|
m "github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/services/search"
|
|
)
|
|
|
|
func init() {
|
|
bus.AddHandler("sql", SaveDashboard)
|
|
bus.AddHandler("sql", GetDashboard)
|
|
bus.AddHandler("sql", DeleteDashboard)
|
|
bus.AddHandler("sql", SearchDashboards)
|
|
bus.AddHandler("sql", GetDashboardTags)
|
|
}
|
|
|
|
func SaveDashboard(cmd *m.SaveDashboardCommand) error {
|
|
return inTransaction(func(sess *xorm.Session) error {
|
|
dash := cmd.GetDashboardModel()
|
|
|
|
// try get existing dashboard
|
|
var existing, sameTitle m.Dashboard
|
|
|
|
if dash.Id > 0 {
|
|
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !dashWithIdExists {
|
|
return m.ErrDashboardNotFound
|
|
}
|
|
|
|
// check for is someone else has written in between
|
|
if dash.Version != existing.Version {
|
|
if cmd.Overwrite {
|
|
dash.Version = existing.Version
|
|
} else {
|
|
return m.ErrDashboardVersionMismatch
|
|
}
|
|
}
|
|
}
|
|
|
|
sameTitleExists, err := sess.Where("org_id=? AND slug=?", dash.OrgId, dash.Slug).Get(&sameTitle)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if sameTitleExists {
|
|
// another dashboard with same name
|
|
if dash.Id != sameTitle.Id {
|
|
if cmd.Overwrite {
|
|
dash.Id = sameTitle.Id
|
|
} else {
|
|
return m.ErrDashboardWithSameNameExists
|
|
}
|
|
}
|
|
}
|
|
|
|
affectedRows := int64(0)
|
|
|
|
if dash.Id == 0 {
|
|
metrics.M_Models_Dashboard_Insert.Inc(1)
|
|
affectedRows, err = sess.Insert(dash)
|
|
} else {
|
|
dash.Version += 1
|
|
dash.Data["version"] = dash.Version
|
|
affectedRows, err = sess.Id(dash.Id).Update(dash)
|
|
}
|
|
|
|
if affectedRows == 0 {
|
|
return m.ErrDashboardNotFound
|
|
}
|
|
|
|
// delete existing tabs
|
|
_, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// insert new tags
|
|
tags := dash.GetTags()
|
|
if len(tags) > 0 {
|
|
for _, tag := range tags {
|
|
if _, err := sess.Insert(&DashboardTag{DashboardId: dash.Id, Term: tag}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
cmd.Result = dash
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
func GetDashboard(query *m.GetDashboardQuery) error {
|
|
dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId}
|
|
has, err := x.Get(&dashboard)
|
|
if err != nil {
|
|
return err
|
|
} else if has == false {
|
|
return m.ErrDashboardNotFound
|
|
}
|
|
|
|
dashboard.Data["id"] = dashboard.Id
|
|
query.Result = &dashboard
|
|
|
|
return nil
|
|
}
|
|
|
|
type DashboardSearchProjection struct {
|
|
Id int64
|
|
Title string
|
|
Slug string
|
|
Term string
|
|
}
|
|
|
|
func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
|
|
var sql bytes.Buffer
|
|
params := make([]interface{}, 0)
|
|
|
|
sql.WriteString(`SELECT
|
|
dashboard.id,
|
|
dashboard.title,
|
|
dashboard.slug,
|
|
dashboard_tag.term
|
|
FROM dashboard
|
|
LEFT OUTER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id`)
|
|
|
|
if query.IsStarred {
|
|
sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id")
|
|
}
|
|
|
|
sql.WriteString(` WHERE dashboard.org_id=?`)
|
|
|
|
params = append(params, query.OrgId)
|
|
|
|
if query.IsStarred {
|
|
sql.WriteString(` AND star.user_id=?`)
|
|
params = append(params, query.UserId)
|
|
}
|
|
|
|
if len(query.Title) > 0 {
|
|
sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?")
|
|
params = append(params, "%"+query.Title+"%")
|
|
}
|
|
|
|
sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT 1000"))
|
|
|
|
var res []DashboardSearchProjection
|
|
err := x.Sql(sql.String(), params...).Find(&res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
query.Result = make([]*search.Hit, 0)
|
|
hits := make(map[int64]*search.Hit)
|
|
|
|
for _, item := range res {
|
|
hit, exists := hits[item.Id]
|
|
if !exists {
|
|
hit = &search.Hit{
|
|
Id: item.Id,
|
|
Title: item.Title,
|
|
Uri: "db/" + item.Slug,
|
|
Type: search.DashHitDB,
|
|
Tags: []string{},
|
|
}
|
|
query.Result = append(query.Result, hit)
|
|
hits[item.Id] = hit
|
|
}
|
|
if len(item.Term) > 0 {
|
|
hit.Tags = append(hit.Tags, item.Term)
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
|
|
sql := `SELECT
|
|
COUNT(*) as count,
|
|
term
|
|
FROM dashboard
|
|
INNER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id
|
|
WHERE dashboard.org_id=?
|
|
GROUP BY term`
|
|
|
|
query.Result = make([]*m.DashboardTagCloudItem, 0)
|
|
sess := x.Sql(sql, query.OrgId)
|
|
err := sess.Find(&query.Result)
|
|
return err
|
|
}
|
|
|
|
func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
|
|
return inTransaction2(func(sess *session) error {
|
|
dashboard := m.Dashboard{Slug: cmd.Slug, OrgId: cmd.OrgId}
|
|
has, err := x.Get(&dashboard)
|
|
if err != nil {
|
|
return err
|
|
} else if has == false {
|
|
return m.ErrDashboardNotFound
|
|
}
|
|
|
|
deletes := []string{
|
|
"DELETE FROM dashboard_tag WHERE dashboard_id = ? ",
|
|
"DELETE FROM star WHERE dashboard_id = ? ",
|
|
"DELETE FROM dashboard WHERE id = ?",
|
|
}
|
|
|
|
for _, sql := range deletes {
|
|
_, err := sess.Exec(sql, dashboard.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|