Skip to content

Commit

Permalink
Split Get with Loader function, introduce SimpleCache
Browse files Browse the repository at this point in the history
  • Loading branch information
Rene Kroon committed May 22, 2021
1 parent 2843e1e commit fa22f63
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 4 deletions.
33 changes: 32 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,39 @@ Note (issue #25): by default, due to historic reasons, the TTL will be reset on

## Usage

You can copy it as a full standalone demo program.
You can copy it as a full standalone demo program. The first snippet is basic usage, where the second exploits more options in the cache.

Basic:
```go
package main

import (
"fmt"
"time"

"github.com/ReneKroon/ttlcache/v2"
)

var notFound = ttlcache.ErrNotFound

func main() {
var cache ttlcache.SimpleCache = ttlcache.NewCache()

cache.SetTTL(time.Duration(10 * time.Second))
cache.Set("MyKey", "MyValue")
cache.Set("MyNumber", 1000)

if val, err := cache.Get("MyKey"); err != notFound {
fmt.Printf("Got it: %s\n", val)
}

cache.Remove("MyNumber")
cache.Purge()
cache.Close()
}
```

Advanced:
```go
package main

Expand Down
21 changes: 18 additions & 3 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ type ExpireReasonCallback func(key string, reason EvictionReason, value interfac
// LoaderFunction can be supplied to retrieve an item where a cache miss occurs. Supply an item specific ttl or Duration.Zero
type LoaderFunction func(key string) (data interface{}, ttl time.Duration, err error)

// SimpleCache interface enables a quick-start. Interface for basic usage.
type SimpleCache interface {
Get(key string) (interface{}, error)
Set(key string, data interface{}) error
SetTTL(ttl time.Duration) error
SetWithTTL(key string, data interface{}, ttl time.Duration) error
Remove(key string) error
Close() error
Purge() error
}

// Cache is a synchronized map of items that can auto-expire once stale
type Cache struct {
mutex sync.Mutex
Expand Down Expand Up @@ -263,9 +274,13 @@ func (cache *Cache) SetWithTTL(key string, data interface{}, ttl time.Duration)
return nil
}

func (cache *Cache) Get(key string) (interface{}, error) {
return cache.GetByLoader(key, nil)
}

// Get is a thread-safe way to lookup items
// Every lookup, also touches the item, hence extending it's life
func (cache *Cache) Get(key string, customLoaderFunction ...LoaderFunction) (interface{}, error) {
func (cache *Cache) GetByLoader(key string, customLoaderFunction LoaderFunction) (interface{}, error) {
cache.mutex.Lock()
if cache.isShutDown {
cache.mutex.Unlock()
Expand All @@ -288,8 +303,8 @@ func (cache *Cache) Get(key string, customLoaderFunction ...LoaderFunction) (int
}

loaderFunction := cache.loaderFunction
if len(customLoaderFunction) > 0 {
loaderFunction = customLoaderFunction[0]
if customLoaderFunction != nil {
loaderFunction = customLoaderFunction
}

if loaderFunction == nil || exists {
Expand Down
51 changes: 51 additions & 0 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,57 @@ func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}

// The SimpleCache interface enables quick-start.
func TestCache_SimpleCache(t *testing.T) {
t.Parallel()
var cache SimpleCache = NewCache()

cache.SetTTL(time.Second)
cache.Set("k", "v")
cache.Get("k")
cache.Purge()
cache.Close()

}

// Issue / PR #39: add customer loader function for each Get() #
// some middleware prefers to define specific context's etc per Get.
// This is faciliated by supplying a loder function with Get's.
func TestCache_GetByLoader(t *testing.T) {
t.Parallel()
cache := NewCache()
defer cache.Close()

globalLoader := func(key string) (data interface{}, ttl time.Duration, err error) {
return "global", 0, nil
}
cache.SetLoaderFunction(globalLoader)

localLoader := func(key string) (data interface{}, ttl time.Duration, err error) {
return "local", 0, nil
}

key, _ := cache.Get("test")
assert.Equal(t, "global", key)

cache.Remove("test")

localKey, _ := cache.GetByLoader("test", localLoader)
assert.Equal(t, "local", localKey)

cache.Remove("test")

globalKey, _ := cache.GetByLoader("test", globalLoader)
assert.Equal(t, "global", globalKey)

cache.Remove("test")

defaultKey, _ := cache.GetByLoader("test", nil)
assert.Equal(t, "global", defaultKey)

cache.Remove("test")
}

// Issue #38: Feature request: ability to know why an expiry has occurred
func TestCache_textExpirationReasons(t *testing.T) {
t.Parallel()
Expand Down

0 comments on commit fa22f63

Please sign in to comment.