annotation.go 6.8 KB

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