From 470baf8d598c2c483b82e903675762c804f084b4 Mon Sep 17 00:00:00 2001 From: Gleb Vasylenko Date: Wed, 9 Feb 2022 18:21:16 +0200 Subject: [PATCH] Add GetWithFallback method to fallback non existent or expired keys --- bigcache.go | 20 ++++++++++++++++++++ bigcache_test.go | 34 ++++++++++++++++++++++++++++++++++ examples_test.go | 12 ++++++++++++ 3 files changed, 66 insertions(+) diff --git a/bigcache.go b/bigcache.go index 7ae1f124..b08c37cc 100644 --- a/bigcache.go +++ b/bigcache.go @@ -123,6 +123,26 @@ func (c *BigCache) Get(key string) ([]byte, error) { return shard.get(key, hashedKey) } +// Get reads entry for the key and if it is not exists +// call second argument callback function to resolve actual value. +func (c *BigCache) GetWithFallback(key string, fn func() ([]byte, error)) ([]byte, error) { + entry, err := c.Get(key) + if err == nil { + return entry, nil + } + + if err != ErrEntryNotFound { + return nil, err + } + + entry, err = fn() + if err != nil { + return nil, err + } + + return entry, nil +} + // GetWithInfo reads entry for the key with Response info. // It returns an ErrEntryNotFound when // no entry exists for the given key. diff --git a/bigcache_test.go b/bigcache_test.go index 5cd01de4..6a4eba08 100644 --- a/bigcache_test.go +++ b/bigcache_test.go @@ -2,6 +2,7 @@ package bigcache import ( "bytes" + "errors" "fmt" "math" "math/rand" @@ -28,6 +29,39 @@ func TestWriteAndGetOnCache(t *testing.T) { assertEqual(t, value, cachedValue) } +func TestGetWithFallbackOnCache(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(DefaultConfig(5 * time.Second)) + value := []byte("value") + + // when + cachedValue, err := cache.GetWithFallback("key", func() ([]byte, error) { + return value, nil + }) + + // then + noError(t, err) + assertEqual(t, value, cachedValue) +} + +func TestGetWithFallbackOnCacheWithError(t *testing.T) { + t.Parallel() + + // given + cache, _ := NewBigCache(DefaultConfig(5 * time.Second)) + errStub := errors.New("some error") + + // when + _, err := cache.GetWithFallback("key", func() ([]byte, error) { + return nil, errStub + }) + + // then + assertEqual(t, errStub, err) +} + func TestAppendAndGetOnCache(t *testing.T) { t.Parallel() diff --git a/examples_test.go b/examples_test.go index ccc513a9..c50432aa 100644 --- a/examples_test.go +++ b/examples_test.go @@ -18,6 +18,18 @@ func Example() { // Output: value } +func Example_getWithFallback() { + cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute)) + + entry, _ := cache.GetWithFallback("my-unique-key", func() ([]byte, error) { + /* Some amount of code for resolving value... */ + return []byte("value"), nil + }) + + fmt.Println(string(entry)) + // Output: value +} + func Example_custom() { // When cache load can be predicted in advance then it is better to use custom initialization // because additional memory allocation can be avoided in that way.