Skip to content

Commit d28a9c2

Browse files
committed
feat: allow store options override in Set() method
1 parent 0d1032b commit d28a9c2

35 files changed

+313
-233
lines changed

Makefile

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
.PHONY: mocks
22

33
mocks:
4+
# mocks
45
mockery -case=snake -name=CacheInterface -dir=cache/ -output test/mocks/cache/
56
mockery -case=snake -name=CodecInterface -dir=codec/ -output test/mocks/codec/
67
mockery -case=snake -name=SetterCacheInterface -dir=cache/ -output test/mocks/cache/
78
mockery -case=snake -name=MetricsInterface -dir=metrics/ -output test/mocks/metrics/
89
mockery -case=snake -name=StoreInterface -dir=store/ -output test/mocks/store/
9-
mockery -case=snake -name=BigcacheClientInterface -dir=store/ -output test/mocks/store/
10-
mockery -case=snake -name=MemcacheClientInterface -dir=store/ -output test/mocks/store/
11-
mockery -case=snake -name=RedisClientInterface -dir=store/ -output test/mocks/store/
12-
mockery -case=snake -name=RistrettoClientInterface -dir=store/ -output test/mocks/store/
10+
11+
# in package store clients mocks
12+
mockery -case=snake -inpkg -name=BigcacheClientInterface -dir=store/ -output store/
13+
mockery -case=snake -inpkg -name=MemcacheClientInterface -dir=store/ -output store/
14+
mockery -case=snake -inpkg -name=RedisClientInterface -dir=store/ -output store/
15+
mockery -case=snake -inpkg -name=RistrettoClientInterface -dir=store/ -output store/

README.md

+47-30
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Here is what it brings in detail:
1616
* ✅ A loadable cache: allow you to call a callback function to put your data back in cache
1717
* ✅ A metric cache to let you store metrics about your caches usage (hits, miss, set success, set error, ...)
1818
* ✅ A marshaler to automatically marshal/unmarshal your cache values as a struct
19+
* ✅ Define default values in stores and override them when setting data
1920

2021
## Built-in stores
2122

@@ -40,10 +41,15 @@ Here is a simple cache instanciation with Redis but you can also look at other a
4041
```go
4142
memcacheStore := store.NewMemcache(
4243
memcache.New("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212"),
44+
&store.Options{
45+
Expiration: 10*time.Second,
46+
},
4347
)
4448

45-
cacheManager := cache.New(memcacheStore, &cache.Options{Expiration: 15*time.Second})
46-
err := cacheManager.Set("my-key", []byte("my-value))
49+
cacheManager := cache.New(memcacheStore)
50+
err := cacheManager.Set("my-key", []byte("my-value), &cache.Options{
51+
Expiration: 15*time.Second, // Override default value of 10 seconds defined in the store
52+
})
4753
if err != nil {
4854
panic(err)
4955
}
@@ -55,12 +61,10 @@ value := cacheManager.Get("my-key")
5561
5662
```go
5763
bigcacheClient, _ := bigcache.NewBigCache(bigcache.DefaultConfig(5 * time.Minute))
58-
bigcacheStore := store.NewBigcache(
59-
bigcacheClient,
60-
)
64+
bigcacheStore := store.NewBigcache(bigcacheClient, nil) // No otions provided (as second argument)
6165
62-
cacheManager := cache.New(bigcacheStore, nil)
63-
err := cacheManager.Set("my-key", "my-value")
66+
cacheManager := cache.New(bigcacheStore)
67+
err := cacheManager.Set("my-key", "my-value", nil)
6468
if err != nil {
6569
panic(err)
6670
}
@@ -71,14 +75,18 @@ value := cacheManager.Get("my-key")
7175
#### Memory (using Ristretto)
7276
7377
```go
74-
ristrettoCache, err := ristretto.NewCache(&ristretto.Config{NumCounters: 1000, MaxCost: 100, BufferItems: 64})
78+
ristrettoCache, err := ristretto.NewCache(&ristretto.Config{
79+
NumCounters: 1000,
80+
MaxCost: 100,
81+
BufferItems: 64,
82+
})
7583
if err != nil {
7684
panic(err)
7785
}
78-
ristrettoStore := store.NewRistretto(ristrettoCache)
86+
ristrettoStore := store.NewRistretto(ristrettoCache, nil)
7987
80-
cacheManager := cache.New(ristrettoStore, nil)
81-
err := cacheManager.Set("my-key", "my-value")
88+
cacheManager := cache.New(ristrettoStore)
89+
err := cacheManager.Set("my-key", "my-value", &cache.Options{Cost: 2})
8290
if err != nil {
8391
panic(err)
8492
}
@@ -89,10 +97,12 @@ value := cacheManager.Get("my-key")
8997
#### Redis
9098
9199
```go
92-
redisStore := store.NewRedis(redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"}))
100+
redisStore := store.NewRedis(redis.NewClient(&redis.Options{
101+
Addr: "127.0.0.1:6379",
102+
}), nil)
93103
94-
cacheManager := cache.New(redisStore, &cache.Options{Expiration: 15*time.Second})
95-
err := cacheManager.Set("my-key", "my-value")
104+
cacheManager := cache.New(redisStore)
105+
err := cacheManager.Set("my-key", "my-value", &cache.Options{Expiration: 15*time.Second})
96106
if err != nil {
97107
panic(err)
98108
}
@@ -114,13 +124,13 @@ if err != nil {
114124
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
115125
116126
// Initialize stores
117-
ristrettoStore := store.NewRistretto(ristrettoCache)
118-
redisStore := store.NewRedis(redisClient)
127+
ristrettoStore := store.NewRistretto(ristrettoCache, nil)
128+
redisStore := store.NewRedis(redisClient, &cache.Optiobs{Expiration: 5*time.Second})
119129
120130
// Initialize chained cache
121131
cacheManager := cache.NewChain(
122-
cache.New(ristrettoStore, nil),
123-
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
132+
cache.New(ristrettoStore),
133+
cache.New(redisStore),
124134
)
125135
126136
// ... Then, do what you want with your cache
@@ -135,7 +145,7 @@ This cache will provide a load function that acts as a callable function and wil
135145
```go
136146
// Initialize Redis client and store
137147
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
138-
redisStore := store.NewRedis(redisClient)
148+
redisStore := store.NewRedis(redisClient, nil)
139149
140150
// Initialize a load function that loads your data from a custom source
141151
loadFunction := func(key interface{}) (interface{}, error) {
@@ -146,7 +156,7 @@ loadFunction := func(key interface{}) (interface{}, error) {
146156
// Initialize loadable cache
147157
cacheManager := cache.NewLoadable(
148158
loadFunction,
149-
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
159+
cache.New(redisStore),
150160
)
151161
152162
// ... Then, you can get your data and your function will automatically put them in cache(s)
@@ -161,15 +171,15 @@ This cache will record metrics depending on the metric provider you pass to it.
161171
```go
162172
// Initialize Redis client and store
163173
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
164-
redisStore := store.NewRedis(redisClient)
174+
redisStore := store.NewRedis(redisClient, nil)
165175
166176
// Initializes Prometheus metrics service
167177
promMetrics := metrics.NewPrometheus("my-test-app")
168178
169179
// Initialize metric cache
170180
cacheManager := cache.NewMetric(
171181
promMetrics,
172-
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
182+
cache.New(redisStore),
173183
)
174184
175185
// ... Then, you can get your data and metrics will be observed by Prometheus
@@ -182,12 +192,12 @@ Some caches like Redis stores and returns the value as a string so you have to m
182192
```go
183193
// Initialize Redis client and store
184194
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
185-
redisStore := store.NewRedis(redisClient)
195+
redisStore := store.NewRedis(redisClient, nil)
186196
187197
// Initialize chained cache
188198
cacheManager := cache.NewMetric(
189199
promMetrics,
190-
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
200+
cache.New(redisStore),
191201
)
192202
193203
// Initializes marshaler
@@ -242,13 +252,20 @@ func main() {
242252
// Initialize Prometheus metrics collector
243253
promMetrics := metrics.NewPrometheus("my-test-app")
244254
245-
ristrettoCache, err := ristretto.NewCache(&ristretto.Config{NumCounters: 1000, MaxCost: 100, BufferItems: 64})
255+
// Initialize Ristretto store
256+
ristrettoCache, err := ristretto.NewCache(&ristretto.Config{
257+
NumCounters: 1000,
258+
MaxCost: 100,
259+
BufferItems: 64,
260+
})
246261
if err != nil {
247262
panic(err)
248263
}
249264
250-
ristrettoStore := store.NewRistretto(ristrettoCache)
251-
redisStore := store.NewRedis(redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"}))
265+
ristrettoStore := store.NewRistretto(ristrettoCache, &cache.Options{Cost: 4})
266+
267+
// Initialize Redis store
268+
redisStore := store.NewRedis(redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"}), &cache.Options{Expiration: 5*time.Second})
252269
253270
// Initialize a load function that loads your data from a custom source
254271
loadFunction := func(key interface{}) (interface{}, error) {
@@ -260,8 +277,8 @@ func main() {
260277
// and a load function that will put data back into caches if none has the value
261278
cacheManager := cache.NewMetric(promMetrics, cache.NewLoadable(loadFunction,
262279
cache.NewChain(
263-
cache.New(ristrettoStore, nil),
264-
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
280+
cache.New(ristrettoStore),
281+
cache.New(redisStore),
265282
),
266283
))
267284
@@ -270,7 +287,7 @@ func main() {
270287
key := Book{Slug: "my-test-amazing-book"}
271288
value := Book{ID: 1, Name: "My test amazing book", Slug: "my-test-amazing-book"}
272289
273-
err = marshaller.Set(key, value)
290+
err = marshaller.Set(key, value, nil)
274291
if err != nil {
275292
panic(err)
276293
}

cache/cache.go

+3-9
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,12 @@ const (
1414
// Cache represents the configuration needed by a cache
1515
type Cache struct {
1616
codec codec.CodecInterface
17-
options *Options
1817
}
1918

2019
// New instanciates a new cache entry
21-
func New(store store.StoreInterface, options *Options) *Cache {
22-
if options == nil {
23-
options = &Options{}
24-
}
25-
20+
func New(store store.StoreInterface) *Cache {
2621
return &Cache{
2722
codec: codec.New(store),
28-
options: options,
2923
}
3024
}
3125

@@ -36,9 +30,9 @@ func (c *Cache) Get(key interface{}) (interface{}, error) {
3630
}
3731

3832
// Set populates the cache item using the given key
39-
func (c *Cache) Set(key, object interface{}) error {
33+
func (c *Cache) Set(key, object interface{}, options *store.Options) error {
4034
cacheKey := c.getCacheKey(key)
41-
return c.codec.Set(cacheKey, object, c.options.ExpirationValue())
35+
return c.codec.Set(cacheKey, object, options)
4236
}
4337

4438
// GetCodec returns the current codec

cache/cache_test.go

+14-31
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/eko/gache/codec"
9+
"github.com/eko/gache/store"
910
mocksStore "github.com/eko/gache/test/mocks/store"
1011

1112
"github.com/stretchr/testify/assert"
@@ -14,24 +15,20 @@ import (
1415
func TestNew(t *testing.T) {
1516
// Given
1617
store := &mocksStore.StoreInterface{}
17-
options := &Options{
18-
Expiration: 5 * time.Second,
19-
}
2018

2119
// When
22-
cache := New(store, options)
20+
cache := New(store)
2321

2422
// Then
2523
assert.IsType(t, new(Cache), cache)
2624
assert.IsType(t, new(codec.Codec), cache.codec)
2725

2826
assert.Equal(t, store, cache.codec.GetStore())
29-
assert.Equal(t, options, cache.options)
3027
}
3128

3229
func TestCacheSet(t *testing.T) {
3330
// Given
34-
options := &Options{
31+
options := &store.Options{
3532
Expiration: 5 * time.Second,
3633
}
3734

@@ -42,19 +39,19 @@ func TestCacheSet(t *testing.T) {
4239
}
4340

4441
store := &mocksStore.StoreInterface{}
45-
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, options.ExpirationValue()).
42+
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, options).
4643
Return(nil)
4744

48-
cache := New(store, options)
45+
cache := New(store)
4946

5047
// When
51-
err := cache.Set("my-key", value)
48+
err := cache.Set("my-key", value, options)
5249
assert.Nil(t, err)
5350
}
5451

5552
func TestCacheSetWhenErrorOccurs(t *testing.T) {
5653
// Given
57-
options := &Options{
54+
options := &store.Options{
5855
Expiration: 5 * time.Second,
5956
}
6057

@@ -67,22 +64,18 @@ func TestCacheSetWhenErrorOccurs(t *testing.T) {
6764
storeErr := errors.New("An error has occured while inserting data into store")
6865

6966
store := &mocksStore.StoreInterface{}
70-
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, options.ExpirationValue()).
67+
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, options).
7168
Return(storeErr)
7269

73-
cache := New(store, options)
70+
cache := New(store)
7471

7572
// When
76-
err := cache.Set("my-key", value)
73+
err := cache.Set("my-key", value, options)
7774
assert.Equal(t, storeErr, err)
7875
}
7976

8077
func TestCacheGet(t *testing.T) {
8178
// Given
82-
options := &Options{
83-
Expiration: 5 * time.Second,
84-
}
85-
8679
cacheValue := &struct {
8780
Hello string
8881
}{
@@ -92,7 +85,7 @@ func TestCacheGet(t *testing.T) {
9285
store := &mocksStore.StoreInterface{}
9386
store.On("Get", "9b1ac8a6e8ca8ca9477c0a252eb37756").Return(cacheValue, nil)
9487

95-
cache := New(store, options)
88+
cache := New(store)
9689

9790
// When
9891
value, err := cache.Get("my-key")
@@ -104,16 +97,12 @@ func TestCacheGet(t *testing.T) {
10497

10598
func TestCacheGetWhenNotFound(t *testing.T) {
10699
// Given
107-
options := &Options{
108-
Expiration: 5 * time.Second,
109-
}
110-
111100
returnedErr := errors.New("Unable to find item in store")
112101

113102
store := &mocksStore.StoreInterface{}
114103
store.On("Get", "9b1ac8a6e8ca8ca9477c0a252eb37756").Return(nil, returnedErr)
115104

116-
cache := New(store, options)
105+
cache := New(store)
117106

118107
// When
119108
value, err := cache.Get("my-key")
@@ -126,11 +115,8 @@ func TestCacheGetWhenNotFound(t *testing.T) {
126115
func TestCacheGetCodec(t *testing.T) {
127116
// Given
128117
store := &mocksStore.StoreInterface{}
129-
options := &Options{
130-
Expiration: 5 * time.Second,
131-
}
132118

133-
cache := New(store, options)
119+
cache := New(store)
134120

135121
// When
136122
value := cache.GetCodec()
@@ -143,11 +129,8 @@ func TestCacheGetCodec(t *testing.T) {
143129
func TestCacheGetType(t *testing.T) {
144130
// Given
145131
store := &mocksStore.StoreInterface{}
146-
options := &Options{
147-
Expiration: 5 * time.Second,
148-
}
149132

150-
cache := New(store, options)
133+
cache := New(store)
151134

152135
// When - Then
153136
assert.Equal(t, CacheType, cache.GetType())

0 commit comments

Comments
 (0)