redis.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package helpers
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "strings"
  8. "github.com/redis/go-redis/v9"
  9. )
  10. type DocAlreadyExists struct {
  11. Key string
  12. Value string
  13. }
  14. func (d *DocAlreadyExists) Error() string {
  15. return fmt.Sprintf("Key: '%s' already exists with value: '%s'", d.Key, d.Value)
  16. }
  17. type DocDoesntExist struct {
  18. Key string
  19. }
  20. func (d *DocDoesntExist) Error() string {
  21. return fmt.Sprintf("Document with ID: '%s' does not exist.", d.Key)
  22. }
  23. type InvalidTopic struct {Topic string}
  24. func (i *InvalidTopic) Error() string {
  25. return fmt.Sprintf("Topic: %s is not a valid topic category.", i.Topic)
  26. }
  27. type RedisConf struct {
  28. Addr string
  29. Port string
  30. }
  31. type RedisCaller struct {
  32. ctx context.Context
  33. Client *redis.Client
  34. }
  35. /*
  36. Creates a new RedisCaller struct
  37. :param redisCfg: a redis configuration struct
  38. */
  39. func NewRedisClient(redisCfg RedisConf) *RedisCaller {
  40. return &RedisCaller{Client: redis.NewClient(&redis.Options{
  41. Addr: fmt.Sprintf("%s:%v", redisCfg.Addr, redisCfg.Port),
  42. DB: 0, // use default DB
  43. }),
  44. ctx: context.Background(),}
  45. }
  46. /*
  47. retrieves all of the document IDs in the Redis database
  48. */
  49. func (r *RedisCaller) AllDocIds() ([]string, error) {
  50. return r.Client.Keys(r.ctx, "*").Result()
  51. }
  52. /*
  53. Sets the item (id) to the value supplied in value
  54. :param doc: the documents.Document struct to input to the database
  55. */
  56. func (r *RedisCaller) AddDoc(doc Document) error {
  57. _, ok := TopicMap[doc.Category]
  58. if !ok {
  59. return &InvalidTopic{Topic: doc.Category}
  60. }
  61. val, err := r.Client.Get(r.ctx, doc.Ident).Result()
  62. if err == redis.Nil {
  63. data, err := json.Marshal(&doc)
  64. if err != nil {
  65. return err
  66. }
  67. err = r.Client.Set(r.ctx, doc.Ident, data, 0).Err()
  68. if err != nil {
  69. return err
  70. }
  71. return nil
  72. } else if err != nil {
  73. return err
  74. }
  75. return &DocAlreadyExists{Key: doc.Ident, Value: val}
  76. }
  77. /*
  78. Add an image to the image store
  79. :param img: an ImageStoreItem struct with the appropriate metadata
  80. */
  81. func (r *RedisCaller) AddImage(img *ImageStoreItem) error {
  82. val, err := r.Client.Get(r.ctx, img.Identifier).Result()
  83. if err == redis.Nil {
  84. data, err := json.Marshal(img)
  85. if err != nil {
  86. return err
  87. }
  88. err = r.Client.Set(r.ctx, img.Identifier, data, 0).Err()
  89. if err != nil {
  90. return err
  91. }
  92. return nil
  93. } else if err != nil {
  94. return err
  95. }
  96. return &DocAlreadyExists{Key: img.Identifier, Value: val}
  97. }
  98. /*
  99. Gets the item stored at the key (id)
  100. :param id: the id of the object to get
  101. */
  102. func (r *RedisCaller) GetItem(id string) (*Document, error) {
  103. var doc Document
  104. val, err := r.Client.Get(r.ctx, id).Result()
  105. if err == redis.Nil {
  106. return nil, err
  107. } else if err != nil {
  108. return nil, err
  109. }
  110. data := []byte(val)
  111. err = json.Unmarshal(data, &doc)
  112. if err != nil {
  113. return nil, err
  114. }
  115. return &doc, nil
  116. }
  117. /*
  118. Retrieve all redis items by category. Returns all the IDs of items that belong to that category
  119. :param category: the category to filter by
  120. */
  121. func (r *RedisCaller) GetByCategory(category string) ([]string, error) {
  122. ids, err := r.AllDocIds()
  123. if err != nil {
  124. return nil, err
  125. }
  126. var matches []string
  127. for i := range ids {
  128. item, err := r.GetItem(ids[i])
  129. if err != nil {
  130. return nil, err
  131. }
  132. if item.Category == category {
  133. matches = append(matches, ids[i])
  134. }
  135. }
  136. return matches, nil
  137. }
  138. /*
  139. Delete the target document in redis
  140. :param id: the id to delete from redis
  141. */
  142. func (r *RedisCaller) DeleteDoc(id string) error {
  143. _, err := r.Client.Get(r.ctx, id).Result()
  144. if err == redis.Nil {
  145. return &DocDoesntExist{id}
  146. } else if err != nil {
  147. return err
  148. }
  149. err = r.Client.Del(r.ctx, id).Err()
  150. if err != nil {
  151. return err
  152. }
  153. return nil
  154. }
  155. /*
  156. Update a value in redis
  157. :param id: the id of the document to edit
  158. */
  159. func (r *RedisCaller) editVal(id string, in interface{}) error {
  160. _, err := r.Client.Get(r.ctx, id).Result()
  161. if err != nil {
  162. if err == redis.Nil {
  163. return &DocDoesntExist{Key: id}
  164. }
  165. return err
  166. }
  167. data, err := json.Marshal(&in)
  168. if err != nil {
  169. return err
  170. }
  171. err = r.Client.Set(r.ctx, id, data, 0).Err()
  172. if err != nil {
  173. return err
  174. }
  175. return nil
  176. }
  177. func (r *RedisCaller) SeedData(seedLoc string) error {
  178. dirs, err := os.ReadDir(seedLoc)
  179. if err != nil {
  180. return err
  181. }
  182. for i := range dirs {
  183. key := strings.Split(dirs[i].Name(), ".")[0]
  184. b, err := os.ReadFile(fmt.Sprintf("%s/%s", seedLoc, dirs[i].Name()))
  185. if err != nil {
  186. return err
  187. }
  188. err = r.Client.Set(r.ctx, key, b, 0).Err()
  189. if err != nil {
  190. return err
  191. }
  192. }
  193. return nil
  194. }
  195. func (r *RedisCaller) UpdatePost(id string, new Document) error {
  196. return r.editVal(id, new)
  197. }
  198. func (r *RedisCaller) UpdateHeader(id string, new HeaderCollection) error {
  199. return r.editVal(id, new)
  200. }
  201. func (r *RedisCaller) UpdateMenu(id string, new MenuElement) error {
  202. return r.editVal(id, new)
  203. }