123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- package helpers
- import (
- "context"
- "encoding/json"
- "fmt"
- "os"
- "strings"
- "github.com/redis/go-redis/v9"
- )
- type DocAlreadyExists struct {
- Key string
- Value string
- }
- func (d *DocAlreadyExists) Error() string {
- return fmt.Sprintf("Key: '%s' already exists with value: '%s'", d.Key, d.Value)
- }
- type DocDoesntExist struct {
- Key string
- }
- func (d *DocDoesntExist) Error() string {
- return fmt.Sprintf("Document with ID: '%s' does not exist.", d.Key)
- }
- type InvalidTopic struct {Topic string}
- func (i *InvalidTopic) Error() string {
- return fmt.Sprintf("Topic: %s is not a valid topic category.", i.Topic)
- }
- type RedisConf struct {
- Addr string
- Port string
- }
- type RedisCaller struct {
- ctx context.Context
- Client *redis.Client
- }
- /*
- Creates a new RedisCaller struct
- :param redisCfg: a redis configuration struct
- */
- func NewRedisClient(redisCfg RedisConf) *RedisCaller {
- return &RedisCaller{Client: redis.NewClient(&redis.Options{
- Addr: fmt.Sprintf("%s:%v", redisCfg.Addr, redisCfg.Port),
- DB: 0, // use default DB
- }),
- ctx: context.Background(),}
- }
- /*
- retrieves all of the document IDs in the Redis database
- */
- func (r *RedisCaller) AllDocIds() ([]string, error) {
- return r.Client.Keys(r.ctx, "*").Result()
- }
- /*
- Sets the item (id) to the value supplied in value
- :param doc: the documents.Document struct to input to the database
- */
- func (r *RedisCaller) AddDoc(doc Document) error {
- _, ok := TopicMap[doc.Category]
- if !ok {
- return &InvalidTopic{Topic: doc.Category}
- }
- val, err := r.Client.Get(r.ctx, string(doc.Ident)).Result()
- if err == redis.Nil {
- data, err := json.Marshal(&doc)
- if err != nil {
- return err
- }
- err = r.Client.Set(r.ctx, string(doc.Ident), data, 0).Err()
- if err != nil {
- return err
- }
- return nil
- } else if err != nil {
- return err
- }
- return &DocAlreadyExists{Key: string(doc.Ident), Value: val}
- }
- /*
- Add an image to the image store
- :param img: an ImageStoreItem struct with the appropriate metadata
- */
- func (r *RedisCaller) AddImage(img *ImageStoreItem) error {
- val, err := r.Client.Get(r.ctx, img.Identifier).Result()
- if err == redis.Nil {
- data, err := json.Marshal(img)
- if err != nil {
- return err
- }
- err = r.Client.Set(r.ctx, img.Identifier, data, 0).Err()
- if err != nil {
- return err
- }
- return nil
- } else if err != nil {
- return err
- }
- return &DocAlreadyExists{Key: img.Identifier, Value: val}
- }
- /*
- Gets the item stored at the key (id)
- :param id: the id of the object to get
- */
- func (r *RedisCaller) GetItem(id string) (*Document, error) {
- var doc Document
- val, err := r.Client.Get(r.ctx, id).Result()
- if err == redis.Nil {
- return nil, err
- } else if err != nil {
- return nil, err
- }
- data := []byte(val)
- err = json.Unmarshal(data, &doc)
- if err != nil {
- return nil, err
- }
- return &doc, nil
- }
- /*
- Retrieve all redis items by category. Returns all the IDs of items that belong to that category
- :param category: the category to filter by
- */
- func (r *RedisCaller) GetByCategory(category string) ([]string, error) {
- ids, err := r.AllDocIds()
- if err != nil {
- return nil, err
- }
- var matches []string
- for i := range ids {
- item, err := r.GetItem(ids[i])
- if err != nil {
- return nil, err
- }
- if item.Category == category {
- matches = append(matches, ids[i])
- }
- }
- return matches, nil
- }
- /*
- Delete the target document in redis
- :param id: the id to delete from redis
- */
- func (r *RedisCaller) DeleteDoc(id string) error {
- _, err := r.Client.Get(r.ctx, id).Result()
- if err == redis.Nil {
- return &DocDoesntExist{id}
- } else if err != nil {
- return err
- }
- err = r.Client.Del(r.ctx, id).Err()
- if err != nil {
- return err
- }
- return nil
- }
- /*
- Update a value in redis
- :param id: the id of the document to edit
- */
- func (r *RedisCaller) editVal(id string, in interface{}) error {
- _, err := r.Client.Get(r.ctx, id).Result()
- if err != nil {
- if err == redis.Nil {
- return &DocDoesntExist{Key: id}
- }
- return err
- }
- data, err := json.Marshal(&in)
- if err != nil {
- return err
- }
- err = r.Client.Set(r.ctx, id, data, 0).Err()
- if err != nil {
- return err
- }
- return nil
- }
- func (r *RedisCaller) SeedData(seedLoc string) error {
- dirs, err := os.ReadDir(seedLoc)
- if err != nil {
- return err
- }
- for i := range dirs {
- key := strings.Split(dirs[i].Name(), ".")[0]
- b, err := os.ReadFile(fmt.Sprintf("%s/%s", seedLoc, dirs[i].Name()))
- if err != nil {
- return err
- }
- err = r.Client.Set(r.ctx, key, b, 0).Err()
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (r *RedisCaller) UpdatePost(id string, new Document) error {
- return r.editVal(id, new)
- }
- func (r *RedisCaller) UpdateHeader(id string, new HeaderCollection) error {
- return r.editVal(id, new)
- }
- func (r *RedisCaller) UpdateMenu(id string, new MenuElement) error {
- return r.editVal(id, new)
- }
|