category.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Copyright 2017 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package storage
  5. import (
  6. "database/sql"
  7. "errors"
  8. "fmt"
  9. "time"
  10. "github.com/miniflux/miniflux/model"
  11. "github.com/miniflux/miniflux/timer"
  12. )
  13. // AnotherCategoryExists checks if another category exists with the same title.
  14. func (s *Storage) AnotherCategoryExists(userID, categoryID int64, title string) bool {
  15. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:AnotherCategoryExists] userID=%d, categoryID=%d, title=%s", userID, categoryID, title))
  16. var result int
  17. query := `SELECT count(*) as c FROM categories WHERE user_id=$1 AND id != $2 AND title=$3`
  18. s.db.QueryRow(query, userID, categoryID, title).Scan(&result)
  19. return result >= 1
  20. }
  21. // CategoryExists checks if the given category exists into the database.
  22. func (s *Storage) CategoryExists(userID, categoryID int64) bool {
  23. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CategoryExists] userID=%d, categoryID=%d", userID, categoryID))
  24. var result int
  25. query := `SELECT count(*) as c FROM categories WHERE user_id=$1 AND id=$2`
  26. s.db.QueryRow(query, userID, categoryID).Scan(&result)
  27. return result >= 1
  28. }
  29. // Category returns a category from the database.
  30. func (s *Storage) Category(userID, categoryID int64) (*model.Category, error) {
  31. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Category] userID=%d, getCategory=%d", userID, categoryID))
  32. var category model.Category
  33. query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 AND id=$2`
  34. err := s.db.QueryRow(query, userID, categoryID).Scan(&category.ID, &category.UserID, &category.Title)
  35. if err == sql.ErrNoRows {
  36. return nil, nil
  37. } else if err != nil {
  38. return nil, fmt.Errorf("unable to fetch category: %v", err)
  39. }
  40. return &category, nil
  41. }
  42. // FirstCategory returns the first category for the given user.
  43. func (s *Storage) FirstCategory(userID int64) (*model.Category, error) {
  44. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FirstCategory] userID=%d", userID))
  45. var category model.Category
  46. query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 ORDER BY title ASC LIMIT 1`
  47. err := s.db.QueryRow(query, userID).Scan(&category.ID, &category.UserID, &category.Title)
  48. if err == sql.ErrNoRows {
  49. return nil, nil
  50. } else if err != nil {
  51. return nil, fmt.Errorf("unable to fetch category: %v", err)
  52. }
  53. return &category, nil
  54. }
  55. // CategoryByTitle finds a category by the title.
  56. func (s *Storage) CategoryByTitle(userID int64, title string) (*model.Category, error) {
  57. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CategoryByTitle] userID=%d, title=%s", userID, title))
  58. var category model.Category
  59. query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 AND title=$2`
  60. err := s.db.QueryRow(query, userID, title).Scan(&category.ID, &category.UserID, &category.Title)
  61. if err == sql.ErrNoRows {
  62. return nil, nil
  63. } else if err != nil {
  64. return nil, fmt.Errorf("Unable to fetch category: %v", err)
  65. }
  66. return &category, nil
  67. }
  68. // Categories returns all categories that belongs to the given user.
  69. func (s *Storage) Categories(userID int64) (model.Categories, error) {
  70. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Categories] userID=%d", userID))
  71. query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 ORDER BY title ASC`
  72. rows, err := s.db.Query(query, userID)
  73. if err != nil {
  74. return nil, fmt.Errorf("Unable to fetch categories: %v", err)
  75. }
  76. defer rows.Close()
  77. categories := make(model.Categories, 0)
  78. for rows.Next() {
  79. var category model.Category
  80. if err := rows.Scan(&category.ID, &category.UserID, &category.Title); err != nil {
  81. return nil, fmt.Errorf("Unable to fetch categories row: %v", err)
  82. }
  83. categories = append(categories, &category)
  84. }
  85. return categories, nil
  86. }
  87. // CategoriesWithFeedCount returns all categories with the number of feeds.
  88. func (s *Storage) CategoriesWithFeedCount(userID int64) (model.Categories, error) {
  89. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CategoriesWithFeedCount] userID=%d", userID))
  90. query := `SELECT
  91. c.id, c.user_id, c.title,
  92. (SELECT count(*) FROM feeds WHERE feeds.category_id=c.id) AS count
  93. FROM categories c WHERE user_id=$1
  94. ORDER BY c.title ASC`
  95. rows, err := s.db.Query(query, userID)
  96. if err != nil {
  97. return nil, fmt.Errorf("Unable to fetch categories: %v", err)
  98. }
  99. defer rows.Close()
  100. categories := make(model.Categories, 0)
  101. for rows.Next() {
  102. var category model.Category
  103. if err := rows.Scan(&category.ID, &category.UserID, &category.Title, &category.FeedCount); err != nil {
  104. return nil, fmt.Errorf("Unable to fetch categories row: %v", err)
  105. }
  106. categories = append(categories, &category)
  107. }
  108. return categories, nil
  109. }
  110. // CreateCategory creates a new category.
  111. func (s *Storage) CreateCategory(category *model.Category) error {
  112. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateCategory] title=%s", category.Title))
  113. query := `
  114. INSERT INTO categories
  115. (user_id, title)
  116. VALUES
  117. ($1, $2)
  118. RETURNING id
  119. `
  120. err := s.db.QueryRow(
  121. query,
  122. category.UserID,
  123. category.Title,
  124. ).Scan(&category.ID)
  125. if err != nil {
  126. return fmt.Errorf("Unable to create category: %v", err)
  127. }
  128. return nil
  129. }
  130. // UpdateCategory updates an existing category.
  131. func (s *Storage) UpdateCategory(category *model.Category) error {
  132. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateCategory] categoryID=%d", category.ID))
  133. query := `UPDATE categories SET title=$1 WHERE id=$2 AND user_id=$3`
  134. _, err := s.db.Exec(
  135. query,
  136. category.Title,
  137. category.ID,
  138. category.UserID,
  139. )
  140. if err != nil {
  141. return fmt.Errorf("Unable to update category: %v", err)
  142. }
  143. return nil
  144. }
  145. // RemoveCategory deletes a category.
  146. func (s *Storage) RemoveCategory(userID, categoryID int64) error {
  147. defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveCategory] userID=%d, categoryID=%d", userID, categoryID))
  148. result, err := s.db.Exec("DELETE FROM categories WHERE id = $1 AND user_id = $2", categoryID, userID)
  149. if err != nil {
  150. return fmt.Errorf("Unable to remove this category: %v", err)
  151. }
  152. count, err := result.RowsAffected()
  153. if err != nil {
  154. return fmt.Errorf("Unable to remove this category: %v", err)
  155. }
  156. if count == 0 {
  157. return errors.New("no category has been removed")
  158. }
  159. return nil
  160. }