annotation.go 7.1 KB

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