annotation.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package sqlstore
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "time"
  8. "github.com/grafana/grafana/pkg/models"
  9. "github.com/grafana/grafana/pkg/services/annotations"
  10. )
  11. type SqlAnnotationRepo struct {
  12. }
  13. func (r *SqlAnnotationRepo) Save(item *annotations.Item) error {
  14. return inTransaction(func(sess *DBSession) error {
  15. tags := models.ParseTagPairs(item.Tags)
  16. item.Tags = models.JoinTagPairs(tags)
  17. item.Created = time.Now().UnixNano() / int64(time.Millisecond)
  18. if _, err := sess.Table("annotation").Insert(item); err != nil {
  19. return err
  20. }
  21. if item.Tags != nil {
  22. if tags, err := r.ensureTagsExist(sess, tags); err != nil {
  23. return err
  24. } else {
  25. for _, tag := range tags {
  26. if _, err := sess.Exec("INSERT INTO annotation_tag (annotation_id, tag_id) VALUES(?,?)", item.Id, tag.Id); err != nil {
  27. return err
  28. }
  29. }
  30. }
  31. }
  32. return nil
  33. })
  34. }
  35. // Will insert if needed any new key/value pars and return ids
  36. func (r *SqlAnnotationRepo) ensureTagsExist(sess *DBSession, tags []*models.Tag) ([]*models.Tag, error) {
  37. for _, tag := range tags {
  38. var existingTag models.Tag
  39. // check if it exists
  40. if exists, err := sess.Table("tag").Where("`key`=? AND `value`=?", tag.Key, tag.Value).Get(&existingTag); err != nil {
  41. return nil, err
  42. } else if exists {
  43. tag.Id = existingTag.Id
  44. } else {
  45. if _, err := sess.Table("tag").Insert(tag); err != nil {
  46. return nil, err
  47. }
  48. }
  49. }
  50. return tags, nil
  51. }
  52. func (r *SqlAnnotationRepo) Update(item *annotations.Item) error {
  53. return inTransaction(func(sess *DBSession) error {
  54. var (
  55. isExist bool
  56. err error
  57. )
  58. existing := new(annotations.Item)
  59. if item.Id == 0 && item.RegionId != 0 {
  60. // Update region end time
  61. isExist, err = sess.Table("annotation").Where("region_id=? AND id!=? AND org_id=?", item.RegionId, item.RegionId, item.OrgId).Get(existing)
  62. } else {
  63. isExist, err = sess.Table("annotation").Where("id=? AND org_id=?", item.Id, item.OrgId).Get(existing)
  64. }
  65. if err != nil {
  66. return err
  67. }
  68. if !isExist {
  69. return errors.New("Annotation not found")
  70. }
  71. existing.Epoch = item.Epoch
  72. existing.Text = item.Text
  73. if item.RegionId != 0 {
  74. existing.RegionId = item.RegionId
  75. }
  76. if item.Tags != nil {
  77. if tags, err := r.ensureTagsExist(sess, models.ParseTagPairs(item.Tags)); err != nil {
  78. return err
  79. } else {
  80. if _, err := sess.Exec("DELETE FROM annotation_tag WHERE annotation_id = ?", existing.Id); err != nil {
  81. return err
  82. }
  83. for _, tag := range tags {
  84. if _, err := sess.Exec("INSERT INTO annotation_tag (annotation_id, tag_id) VALUES(?,?)", existing.Id, tag.Id); err != nil {
  85. return err
  86. }
  87. }
  88. }
  89. }
  90. existing.Tags = item.Tags
  91. if _, err := sess.Table("annotation").Id(existing.Id).Cols("epoch", "text", "region_id", "tags").Update(existing); err != nil {
  92. return err
  93. }
  94. return nil
  95. })
  96. }
  97. func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
  98. var sql bytes.Buffer
  99. params := make([]interface{}, 0)
  100. sql.WriteString(`
  101. SELECT
  102. annotation.id,
  103. annotation.epoch as time,
  104. annotation.dashboard_id,
  105. annotation.panel_id,
  106. annotation.new_state,
  107. annotation.prev_state,
  108. annotation.alert_id,
  109. annotation.region_id,
  110. annotation.text,
  111. annotation.tags,
  112. annotation.data,
  113. annotation.created,
  114. usr.email,
  115. usr.login,
  116. alert.name as alert_name
  117. FROM annotation
  118. LEFT OUTER JOIN ` + dialect.Quote("user") + ` as usr on usr.id = annotation.user_id
  119. LEFT OUTER JOIN alert on alert.id = annotation.alert_id
  120. `)
  121. sql.WriteString(`WHERE annotation.org_id = ?`)
  122. params = append(params, query.OrgId)
  123. if query.AnnotationId != 0 {
  124. fmt.Print("annotation query")
  125. sql.WriteString(` AND annotation.id = ?`)
  126. params = append(params, query.AnnotationId)
  127. }
  128. if query.RegionId != 0 {
  129. sql.WriteString(` AND annotation.region_id = ?`)
  130. params = append(params, query.RegionId)
  131. }
  132. if query.AlertId != 0 {
  133. sql.WriteString(` AND annotation.alert_id = ?`)
  134. params = append(params, query.AlertId)
  135. }
  136. if query.DashboardId != 0 {
  137. sql.WriteString(` AND annotation.dashboard_id = ?`)
  138. params = append(params, query.DashboardId)
  139. }
  140. if query.PanelId != 0 {
  141. sql.WriteString(` AND annotation.panel_id = ?`)
  142. params = append(params, query.PanelId)
  143. }
  144. if query.From > 0 && query.To > 0 {
  145. sql.WriteString(` AND annotation.epoch BETWEEN ? AND ?`)
  146. params = append(params, query.From, query.To)
  147. }
  148. if query.Type == "alert" {
  149. sql.WriteString(` AND annotation.alert_id > 0`)
  150. }
  151. if len(query.Tags) > 0 {
  152. keyValueFilters := []string{}
  153. tags := models.ParseTagPairs(query.Tags)
  154. for _, tag := range tags {
  155. if tag.Value == "" {
  156. keyValueFilters = append(keyValueFilters, "(tag.key = ?)")
  157. params = append(params, tag.Key)
  158. } else {
  159. keyValueFilters = append(keyValueFilters, "(tag.key = ? AND tag.value = ?)")
  160. params = append(params, tag.Key, tag.Value)
  161. }
  162. }
  163. if len(tags) > 0 {
  164. tagsSubQuery := fmt.Sprintf(`
  165. SELECT SUM(1) FROM annotation_tag at
  166. INNER JOIN tag on tag.id = at.tag_id
  167. WHERE at.annotation_id = annotation.id
  168. AND (
  169. %s
  170. )
  171. `, strings.Join(keyValueFilters, " OR "))
  172. sql.WriteString(fmt.Sprintf(" AND (%s) = %d ", tagsSubQuery, len(tags)))
  173. }
  174. }
  175. if query.Limit == 0 {
  176. query.Limit = 10
  177. }
  178. var sort string = "epoch DESC"
  179. switch query.Sort {
  180. case "time.asc":
  181. sort = "epoch ASC"
  182. case "created":
  183. sort = "annotation.created DESC"
  184. case "created.asc":
  185. sort = "annotation.created ASC"
  186. }
  187. sql.WriteString(fmt.Sprintf(" ORDER BY %s LIMIT %v", sort, query.Limit))
  188. items := make([]*annotations.ItemDTO, 0)
  189. if err := x.Sql(sql.String(), params...).Find(&items); err != nil {
  190. return nil, err
  191. }
  192. return items, nil
  193. }
  194. func (r *SqlAnnotationRepo) Delete(params *annotations.DeleteParams) error {
  195. return inTransaction(func(sess *DBSession) error {
  196. var (
  197. sql string
  198. annoTagSql string
  199. queryParams []interface{}
  200. )
  201. if params.RegionId != 0 {
  202. annoTagSql = "DELETE FROM annotation_tag WHERE annotation_id IN (SELECT id FROM annotation WHERE region_id = ?)"
  203. sql = "DELETE FROM annotation WHERE region_id = ?"
  204. queryParams = []interface{}{params.RegionId}
  205. } else if params.Id != 0 {
  206. annoTagSql = "DELETE FROM annotation_tag WHERE annotation_id IN (SELECT id FROM annotation WHERE id = ?)"
  207. sql = "DELETE FROM annotation WHERE id = ?"
  208. queryParams = []interface{}{params.Id}
  209. } else {
  210. annoTagSql = "DELETE FROM annotation_tag WHERE annotation_id IN (SELECT id FROM annotation WHERE dashboard_id = ? AND panel_id = ?)"
  211. sql = "DELETE FROM annotation WHERE dashboard_id = ? AND panel_id = ?"
  212. queryParams = []interface{}{params.DashboardId, params.PanelId}
  213. }
  214. if _, err := sess.Exec(annoTagSql, queryParams...); err != nil {
  215. return err
  216. }
  217. if _, err := sess.Exec(sql, queryParams...); err != nil {
  218. return err
  219. }
  220. return nil
  221. })
  222. }