-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcachey.go
More file actions
182 lines (150 loc) · 5.04 KB
/
cachey.go
File metadata and controls
182 lines (150 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package cachey
import (
"fmt"
"time"
"github.com/codemaestro64/cachey/store"
"github.com/codemaestro64/cachey/store/memory"
"github.com/codemaestro64/cachey/store/redis"
)
// Cache represents a caching mechanism that wraps a store implementation.
type Cache struct {
store store.Store // The underlying store for caching data.
}
// Supported cache store constants.
const (
MemoryStore = "memory" // Name of the memory store.
RedisStore = "redis" // Name of the redis store
ForeverDuration = -1 // Duration to store data indefinitely.
)
type StoreConstructorFunc func() store.Store
// stores maps store names to their corresponding store constructors.
var stores = map[string]StoreConstructorFunc{
MemoryStore: memory.NewMemoryStore,
RedisStore: redis.NewRedisStore,
}
// New initializes a new Cache instance using the specified store name.
// It returns an error if the store is not registered.
func New(storeName string, options ...store.Option) (*Cache, error) {
storeConstructor, ok := stores[storeName]
if !ok {
return nil, fmt.Errorf("cache store `%s` is not registered", storeName)
}
store := storeConstructor()
// apply options to the store
for _, option := range options {
err := option(store)
if err != nil {
return nil, err
}
}
// initialize store with applied config
err := store.Init()
if err != nil {
return nil, err
}
return &Cache{store: store}, nil
}
// Registerstore registers a new cache store with the given name and constructor function.
// Returns an error if the store is already registered.
func RegisterStore(storeName string, constructorFunc StoreConstructorFunc) error {
if _, exists := stores[storeName]; exists {
return fmt.Errorf("cache store `%s` is already registered", storeName)
}
stores[storeName] = constructorFunc
return nil
}
// Has checks if a value exists in the cache for the given key.
// Returns true if the key exists, false otherwise.
func (c *Cache) Has(key string) (bool, error) {
return c.store.Has(key)
}
// Get retrieves the value associated with the given key from the cache.
// Returns nil if the key does not exist.
func (c *Cache) Get(key string) (any, error) {
return c.store.Get(key)
}
// GetOrDefault retrieves the value associated with the given key.
// If the key does not exist, it calls the provided defaultFunc to get a default value.
func (c *Cache) GetOrDefault(key string, defaultFunc func() any) (any, error) {
data, err := c.Get(key)
if err != nil {
return nil, err
}
if data != nil {
return data, nil
}
return defaultFunc(), nil
}
// Remember retrieves the value for the specified key from the cache.
// If it does not exist, it calls rememberFunc to generate the value,
// stores it in the cache with the specified duration, and returns it.
func (c *Cache) Remember(key string, duration time.Duration, rememberFunc func() any) (any, error) {
data, err := c.Get(key)
if err != nil {
return nil, err
}
if data != nil {
return data, nil
}
data = rememberFunc()
c.Put(key, data, duration)
return data, nil
}
// RememberForever retrieves the value for the specified key from the cache.
// If it does not exist, it calls rememberFunc to generate the value,
// and stores it indefinitely in the cache.
func (c *Cache) RememberForever(key string, rememberFunc func() any) (any, error) {
return c.Remember(key, ForeverDuration, rememberFunc)
}
// Pull retrieves the value for the specified key from the cache and
// removes it from the cache. Returns the value or nil if it doesn't exist.
func (c *Cache) Pull(key string) (any, error) {
data, err := c.Get(key)
if err != nil {
return nil, err
}
c.Forget(key)
return data, nil
}
// PullOrDefault retrieves the value for the specified key from the cache.
// If it does not exist, it calls defaultFunc to get a default value,
// removes the key from the cache, and returns the value.
func (c *Cache) PullOrDefault(key string, defaultFunc func() any) (any, error) {
data, err := c.GetOrDefault(key, defaultFunc)
if err != nil {
return nil, err
}
c.Forget(key)
return data, nil
}
// Put stores the given data in the cache under the specified key
// with the provided duration. If the duration is zero, the data is
// stored indefinitely.
func (c *Cache) Put(key string, data any, duration time.Duration) error {
return c.store.Put(key, data, duration)
}
// Forever stores the given data in the cache under the specified key
// indefinitely, ignoring the duration.
func (c *Cache) Forever(key string, data any) {
c.Put(key, data, ForeverDuration)
}
// Add stores the given data in the cache under the specified key
// only if the key does not already exist. If the key exists, no action is taken.
func (c *Cache) Add(key string, data any, duration time.Duration) error {
has, err := c.Has(key)
if err != nil {
return err
}
if !has {
return c.store.Put(key, data, duration)
}
return nil
}
// Forget removes the value associated with the specified key from the cache.
func (c *Cache) Forget(key string) error {
return c.store.Delete(key)
}
// Flush empties the cache.
func (c *Cache) Flush() error {
return c.store.Flush()
}