Skip to content

Commit

Permalink
Reworked options to be variadics
Browse files Browse the repository at this point in the history
  • Loading branch information
eko committed May 26, 2022
1 parent e7ac21a commit 1a47e5f
Show file tree
Hide file tree
Showing 60 changed files with 2,213 additions and 1,032 deletions.
60 changes: 27 additions & 33 deletions README.md
Expand Up @@ -48,15 +48,13 @@ Here is a simple cache instantiation with Redis but you can also look at other a
```go
memcacheStore := store.NewMemcache(
memcache.New("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212"),
&store.Options{
Expiration: 10*time.Second,
},
store.WithExpiration(10*time.Second),
)

cacheManager := cache.New[[]byte](memcacheStore)
err := cacheManager.Set(ctx, "my-key", []byte("my-value"), &store.Options{
Expiration: 15*time.Second, // Override default value of 10 seconds defined in the store
})
err := cacheManager.Set(ctx, "my-key", []byte("my-value"),
store.WithExpiration(15*time.Second), // Override default value of 10 seconds defined in the store
)
if err != nil {
panic(err)
}
Expand All @@ -72,10 +70,10 @@ cacheManager.Clear(ctx) // Clears the entire cache, in case you want to flush al

```go
bigcacheClient, _ := bigcache.NewBigCache(bigcache.DefaultConfig(5 * time.Minute))
bigcacheStore := store.NewBigcache(bigcacheClient, nil) // No options provided (as second argument)
bigcacheStore := store.NewBigcache(bigcacheClient)

cacheManager := cache.New[[]byte](bigcacheStore)
err := cacheManager.Set(ctx, "my-key", []byte("my-value"), nil)
err := cacheManager.Set(ctx, "my-key", []byte("my-value"))
if err != nil {
panic(err)
}
Expand All @@ -94,10 +92,10 @@ ristrettoCache, err := ristretto.NewCache(&ristretto.Config{
if err != nil {
panic(err)
}
ristrettoStore := store.NewRistretto(ristrettoCache, nil)
ristrettoStore := store.NewRistretto(ristrettoCache)

cacheManager := cache.New[string](ristrettoStore)
err := cacheManager.Set(ctx, "my-key", "my-value", &store.Options{Cost: 2})
err := cacheManager.Set(ctx, "my-key", "my-value", store.WithCost(2))
if err != nil {
panic(err)
}
Expand All @@ -111,10 +109,10 @@ cacheManager.Delete(ctx, "my-key")

```go
gocacheClient := gocache.New(5*time.Minute, 10*time.Minute)
gocacheStore := store.NewGoCache(gocacheClient, nil)
gocacheStore := store.NewGoCache(gocacheClient)

cacheManager := cache.New[[]byte](gocacheStore)
err := cacheManager.Set(ctx, "my-key", []byte("my-value"), nil)
err := cacheManager.Set(ctx, "my-key", []byte("my-value"))
if err != nil {
panic(err)
}
Expand All @@ -131,10 +129,10 @@ fmt.Printf("%s", value)
```go
redisStore := store.NewRedis(redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
}), nil)
}))

cacheManager := cache.New[string](redisStore)
err := cacheManager.Set("my-key", "my-value", &store.Options{Expiration: 15*time.Second})
err := cacheManager.Set("my-key", "my-value", store.WithExpiration(15*time.Second))
if err != nil {
panic(err)
}
Expand All @@ -153,9 +151,7 @@ switch err {
#### Freecache

```go
freecacheStore := store.NewFreecache(freecache.NewCache(1000), &Options{
Expiration: 10 * time.Second,
})
freecacheStore := store.NewFreecache(freecache.NewCache(1000), store.WithExpiration(10 * time.Second))

cacheManager := cache.New[[]byte](freecacheStore)
err := cacheManager.Set(ctx, "by-key", []byte("my-value"), opts)
Expand All @@ -179,9 +175,7 @@ if err != nil {
}

cacheManager := cache.New[string](pegasusStore)
err = cacheManager.Set(ctx, "my-key", "my-value", &store.Options{
Expiration: 10 * time.Second,
})
err = cacheManager.Set(ctx, "my-key", "my-value", store.WithExpiration(10 * time.Second))
if err != nil {
panic(err)
}
Expand All @@ -203,8 +197,8 @@ if err != nil {
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})

// Initialize stores
ristrettoStore := store.NewRistretto(ristrettoCache, nil)
redisStore := store.NewRedis(redisClient, &store.Options{Expiration: 5*time.Second})
ristrettoStore := store.NewRistretto(ristrettoCache)
redisStore := store.NewRedis(redisClient, store.WithExpiration(5*time.Second))

// Initialize chained cache
cacheManager := cache.NewChain[any](
Expand All @@ -229,7 +223,7 @@ type Book struct {

// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)
redisStore := store.NewRedis(redisClient)

// Initialize a load function that loads your data from a custom source
loadFunction := func(ctx context.Context, key any) (*Book, error) {
Expand All @@ -255,7 +249,7 @@ This cache will record metrics depending on the metric provider you pass to it.
```go
// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)
redisStore := store.NewRedis(redisClient)

// Initializes Prometheus metrics service
promMetrics := metrics.NewPrometheus("my-test-app")
Expand All @@ -276,7 +270,7 @@ Some caches like Redis stores and returns the value as a string so you have to m
```go
// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)
redisStore := store.NewRedis(redisClient)

// Initialize chained cache
cacheManager := cache.NewMetric[any](
Expand Down Expand Up @@ -319,7 +313,7 @@ Here is an example on how to use it:
```go
// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)
redisStore := store.NewRedis(redisClient)

// Initialize chained cache
cacheManager := cache.NewMetric[*Book](
Expand All @@ -334,13 +328,13 @@ key := BookQuery{Slug: "my-test-amazing-book"}
value := &Book{ID: 1, Name: "My test amazing book", Slug: "my-test-amazing-book"}

// Set an item in the cache and attach it a "book" tag
err = marshal.Set(ctx, key, value, store.Options{Tags: []string{"book"}})
err = marshal.Set(ctx, key, value, store.WithTags([]string{"book"}))
if err != nil {
panic(err)
}

// Remove all items that have the "book" tag
err := marshal.Invalidate(ctx, store.InvalidateOptions{Tags: []string{"book"}})
err := marshal.Invalidate(ctx, store.WithInvalidateTags([]string{"book"}))
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -370,7 +364,7 @@ func main() {
}), nil)

cacheManager := cache.New[string](redisStore)
err := cacheManager.Set("my-key", "my-value", &store.Options{Expiration: 15*time.Second})
err := cacheManager.Set("my-key", "my-value", store.WithExpiration(15*time.Second))
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -411,9 +405,9 @@ Cache respect the following interface so you can write your own (proprietary?) c
```go
type CacheInterface[T any] interface {
Get(ctx context.Context, key any) (T, error)
Set(ctx context.Context, key any, object T, options *store.Options) error
Set(ctx context.Context, key any, object T, options ...store.Option) error
Delete(ctx context.Context, key any) error
Invalidate(ctx context.Context, options store.InvalidateOptions) error
Invalidate(ctx context.Context, options ...store.InvalidateOption) error
Clear(ctx context.Context) error
GetType() string
}
Expand All @@ -440,9 +434,9 @@ You also have the ability to write your own custom store by implementing the fol
type StoreInterface interface {
Get(ctx context.Context, key any) (any, error)
GetWithTTL(ctx context.Context, key any) (any, time.Duration, error)
Set(ctx context.Context, key any, value any, options *Options) error
Set(ctx context.Context, key any, value any, options ...Option) error
Delete(ctx context.Context, key any) error
Invalidate(ctx context.Context, options InvalidateOptions) error
Invalidate(ctx context.Context, options ...InvalidateOption) error
Clear(ctx context.Context) error
GetType() string
}
Expand Down
8 changes: 4 additions & 4 deletions cache/cache.go
Expand Up @@ -61,9 +61,9 @@ func (c *Cache[T]) GetWithTTL(ctx context.Context, key any) (T, time.Duration, e
}

// Set populates the cache item using the given key
func (c *Cache[T]) Set(ctx context.Context, key any, object T, options *store.Options) error {
func (c *Cache[T]) Set(ctx context.Context, key any, object T, options ...store.Option) error {
cacheKey := c.getCacheKey(key)
return c.codec.Set(ctx, cacheKey, object, options)
return c.codec.Set(ctx, cacheKey, object, options...)
}

// Delete removes the cache item using the given key
Expand All @@ -73,8 +73,8 @@ func (c *Cache[T]) Delete(ctx context.Context, key any) error {
}

// Invalidate invalidates cache item from given options
func (c *Cache[T]) Invalidate(ctx context.Context, options store.InvalidateOptions) error {
return c.codec.Invalidate(ctx, options)
func (c *Cache[T]) Invalidate(ctx context.Context, options ...store.InvalidateOption) error {
return c.codec.Invalidate(ctx, options...)
}

// Clear resets all cache data
Expand Down
54 changes: 23 additions & 31 deletions cache/cache_test.go
Expand Up @@ -35,23 +35,21 @@ func TestCacheSet(t *testing.T) {

ctx := context.Background()

options := &store.Options{
Expiration: 5 * time.Second,
}

value := &struct {
Hello string
}{
Hello: "world",
}

store := mocksStore.NewMockStoreInterface(ctrl)
store.EXPECT().Set(ctx, "my-key", value, options).Return(nil)
mockedStore := mocksStore.NewMockStoreInterface(ctrl)
mockedStore.EXPECT().Set(ctx, "my-key", value, store.OptionsMatcher{
Expiration: 5 * time.Second,
}).Return(nil)

cache := New[any](store)
cache := New[any](mockedStore)

// When
err := cache.Set(ctx, "my-key", value, options)
err := cache.Set(ctx, "my-key", value, store.WithExpiration(5*time.Second))
assert.Nil(t, err)
}

Expand All @@ -61,10 +59,6 @@ func TestCacheSetWhenErrorOccurs(t *testing.T) {

ctx := context.Background()

options := &store.Options{
Expiration: 5 * time.Second,
}

value := &struct {
Hello string
}{
Expand All @@ -73,13 +67,15 @@ func TestCacheSetWhenErrorOccurs(t *testing.T) {

storeErr := errors.New("An error has occurred while inserting data into store")

store := mocksStore.NewMockStoreInterface(ctrl)
store.EXPECT().Set(ctx, "my-key", value, options).Return(storeErr)
mockedStore := mocksStore.NewMockStoreInterface(ctrl)
mockedStore.EXPECT().Set(ctx, "my-key", value, store.OptionsMatcher{
Expiration: 5 * time.Second,
}).Return(storeErr)

cache := New[any](store)
cache := New[any](mockedStore)

// When
err := cache.Set(ctx, "my-key", value, options)
err := cache.Set(ctx, "my-key", value, store.WithExpiration(5*time.Second))
assert.Equal(t, storeErr, err)
}

Expand Down Expand Up @@ -291,17 +287,15 @@ func TestCacheInvalidate(t *testing.T) {

ctx := context.Background()

options := store.InvalidateOptions{
mockedStore := mocksStore.NewMockStoreInterface(ctrl)
mockedStore.EXPECT().Invalidate(ctx, store.InvalidateOptionsMatcher{
Tags: []string{"tag1"},
}

store := mocksStore.NewMockStoreInterface(ctrl)
store.EXPECT().Invalidate(ctx, options).Return(nil)
}).Return(nil)

cache := New[any](store)
cache := New[any](mockedStore)

// When
err := cache.Invalidate(ctx, options)
err := cache.Invalidate(ctx, store.WithInvalidateTags([]string{"tag1"}))

// Then
assert.Nil(t, err)
Expand All @@ -313,19 +307,17 @@ func TestCacheInvalidateWhenError(t *testing.T) {

ctx := context.Background()

options := store.InvalidateOptions{
Tags: []string{"tag1"},
}

expectedErr := errors.New("Unexpected error during invalidation")

store := mocksStore.NewMockStoreInterface(ctrl)
store.EXPECT().Invalidate(ctx, options).Return(expectedErr)
mockedStore := mocksStore.NewMockStoreInterface(ctrl)
mockedStore.EXPECT().Invalidate(ctx, store.InvalidateOptionsMatcher{
Tags: []string{"tag1"},
}).Return(expectedErr)

cache := New[any](store)
cache := New[any](mockedStore)

// When
err := cache.Invalidate(ctx, options)
err := cache.Invalidate(ctx, store.WithInvalidateTags([]string{"tag1"}))

// Then
assert.Equal(t, expectedErr, err)
Expand Down
10 changes: 5 additions & 5 deletions cache/chain.go
Expand Up @@ -46,7 +46,7 @@ func (c *ChainCache[T]) setter() {
break
}

cache.Set(context.Background(), item.key, item.value, &store.Options{Expiration: item.ttl})
cache.Set(context.Background(), item.key, item.value, store.WithExpiration(item.ttl))
}
}
}
Expand All @@ -71,9 +71,9 @@ func (c *ChainCache[T]) Get(ctx context.Context, key any) (T, error) {
}

// Set sets a value in available caches
func (c *ChainCache[T]) Set(ctx context.Context, key any, object T, options *store.Options) error {
func (c *ChainCache[T]) Set(ctx context.Context, key any, object T, options ...store.Option) error {
for _, cache := range c.caches {
err := cache.Set(ctx, key, object, options)
err := cache.Set(ctx, key, object, options...)
if err != nil {
storeType := cache.GetCodec().GetStore().GetType()
return fmt.Errorf("Unable to set item into cache with store '%s': %v", storeType, err)
Expand All @@ -93,9 +93,9 @@ func (c *ChainCache[T]) Delete(ctx context.Context, key any) error {
}

// Invalidate invalidates cache item from given options
func (c *ChainCache[T]) Invalidate(ctx context.Context, options store.InvalidateOptions) error {
func (c *ChainCache[T]) Invalidate(ctx context.Context, options ...store.InvalidateOption) error {
for _, cache := range c.caches {
cache.Invalidate(ctx, options)
cache.Invalidate(ctx, options...)
}

return nil
Expand Down

0 comments on commit 1a47e5f

Please sign in to comment.