category.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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/helper"
  11. "github.com/miniflux/miniflux/model"
  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 helper.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 helper.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 helper.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 helper.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 helper.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 helper.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 helper.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. rows, err := s.db.Query(query, userID)
  95. if err != nil {
  96. return nil, fmt.Errorf("Unable to fetch categories: %v", err)
  97. }
  98. defer rows.Close()
  99. categories := make(model.Categories, 0)
  100. for rows.Next() {
  101. var category model.Category
  102. if err := rows.Scan(&category.ID, &category.UserID, &category.Title, &category.FeedCount); err != nil {
  103. return nil, fmt.Errorf("Unable to fetch categories row: %v", err)
  104. }
  105. categories = append(categories, &category)
  106. }
  107. return categories, nil
  108. }
  109. // CreateCategory creates a new category.
  110. func (s *Storage) CreateCategory(category *model.Category) error {
  111. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateCategory] title=%s", category.Title))
  112. query := `
  113. INSERT INTO categories
  114. (user_id, title)
  115. VALUES
  116. ($1, $2)
  117. RETURNING id
  118. `
  119. err := s.db.QueryRow(
  120. query,
  121. category.UserID,
  122. category.Title,
  123. ).Scan(&category.ID)
  124. if err != nil {
  125. return fmt.Errorf("Unable to create category: %v", err)
  126. }
  127. return nil
  128. }
  129. // UpdateCategory updates an existing category.
  130. func (s *Storage) UpdateCategory(category *model.Category) error {
  131. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateCategory] categoryID=%d", category.ID))
  132. query := `UPDATE categories SET title=$1 WHERE id=$2 AND user_id=$3`
  133. _, err := s.db.Exec(
  134. query,
  135. category.Title,
  136. category.ID,
  137. category.UserID,
  138. )
  139. if err != nil {
  140. return fmt.Errorf("Unable to update category: %v", err)
  141. }
  142. return nil
  143. }
  144. // RemoveCategory deletes a category.
  145. func (s *Storage) RemoveCategory(userID, categoryID int64) error {
  146. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveCategory] userID=%d, categoryID=%d", userID, categoryID))
  147. result, err := s.db.Exec("DELETE FROM categories WHERE id = $1 AND user_id = $2", categoryID, userID)
  148. if err != nil {
  149. return fmt.Errorf("Unable to remove this category: %v", err)
  150. }
  151. count, err := result.RowsAffected()
  152. if err != nil {
  153. return fmt.Errorf("Unable to remove this category: %v", err)
  154. }
  155. if count == 0 {
  156. return errors.New("no category has been removed")
  157. }
  158. return nil
  159. }