interface.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package store
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "time"
  8. )
  9. var (
  10. // ErrNotFound is returned when the store implementation cannot find the value
  11. // for a given key.
  12. ErrNotFound = errors.New("store: key not found")
  13. // ErrCantDecode is returned when a store adaptor cannot decode the store format
  14. // to a value used by the code.
  15. ErrCantDecode = errors.New("store: can't decode value")
  16. // ErrCantEncode is returned when a store adaptor cannot encode the value into
  17. // the format that the store uses.
  18. ErrCantEncode = errors.New("store: can't encode value")
  19. // ErrBadConfig is returned when a store adaptor's configuration is invalid.
  20. ErrBadConfig = errors.New("store: configuration is invalid")
  21. )
  22. // Interface defines the calls that Anubis uses for storage in a local or remote
  23. // datastore. This can be implemented with an in-memory, on-disk, or in-database
  24. // storage backend.
  25. type Interface interface {
  26. // Delete removes a value from the store by key.
  27. Delete(ctx context.Context, key string) error
  28. // Get returns the value of a key assuming that value exists and has not expired.
  29. Get(ctx context.Context, key string) ([]byte, error)
  30. // Set puts a value into the store that expires according to its expiry.
  31. Set(ctx context.Context, key string, value []byte, expiry time.Duration) error
  32. // IsPersistent returns true if this storage backend persists data across
  33. // service restarts (e.g., bbolt, valkey). Returns false for volatile storage
  34. // like in-memory backends.
  35. IsPersistent() bool
  36. }
  37. func z[T any]() T { return *new(T) }
  38. type JSON[T any] struct {
  39. Underlying Interface
  40. Prefix string
  41. }
  42. func (j *JSON[T]) Delete(ctx context.Context, key string) error {
  43. if j.Prefix != "" {
  44. key = j.Prefix + key
  45. }
  46. return j.Underlying.Delete(ctx, key)
  47. }
  48. func (j *JSON[T]) Get(ctx context.Context, key string) (T, error) {
  49. if j.Prefix != "" {
  50. key = j.Prefix + key
  51. }
  52. data, err := j.Underlying.Get(ctx, key)
  53. if err != nil {
  54. return z[T](), err
  55. }
  56. var result T
  57. if err := json.Unmarshal(data, &result); err != nil {
  58. return z[T](), fmt.Errorf("%w: %w", ErrCantDecode, err)
  59. }
  60. return result, nil
  61. }
  62. func (j *JSON[T]) Set(ctx context.Context, key string, value T, expiry time.Duration) error {
  63. if j.Prefix != "" {
  64. key = j.Prefix + key
  65. }
  66. data, err := json.Marshal(value)
  67. if err != nil {
  68. return fmt.Errorf("%w: %w", ErrCantEncode, err)
  69. }
  70. if err := j.Underlying.Set(ctx, key, data, expiry); err != nil {
  71. return err
  72. }
  73. return nil
  74. }
  75. func (j *JSON[T]) IsPersistent() bool {
  76. return j.Underlying.IsPersistent()
  77. }