diff --git a/pkg/cache/cacheopt.go b/pkg/cache/cacheopt.go new file mode 100644 index 0000000..836c12a --- /dev/null +++ b/pkg/cache/cacheopt.go @@ -0,0 +1,49 @@ +package cache + +import "time" + +const ( + defaultExpiry = time.Hour * 24 * 7 + defaultNotFoundExpiry = time.Minute +) + +type ( + // Options is used to store the cache options. + Options struct { + Expiry time.Duration + NotFoundExpiry time.Duration + } + + // Option defines the method to customize an Options. + Option func(o *Options) +) + +func newOptions(opts ...Option) Options { + var o Options + for _, opt := range opts { + opt(&o) + } + + if o.Expiry <= 0 { + o.Expiry = defaultExpiry + } + if o.NotFoundExpiry <= 0 { + o.NotFoundExpiry = defaultNotFoundExpiry + } + + return o +} + +// WithExpiry returns a func to customize an Options with given expiry. +func WithExpiry(expiry time.Duration) Option { + return func(o *Options) { + o.Expiry = expiry + } +} + +// WithNotFoundExpiry returns a func to customize an Options with given not found expiry. +func WithNotFoundExpiry(expiry time.Duration) Option { + return func(o *Options) { + o.NotFoundExpiry = expiry + } +} diff --git a/pkg/cache/cacheopt_test.go b/pkg/cache/cacheopt_test.go new file mode 100644 index 0000000..7b7d82c --- /dev/null +++ b/pkg/cache/cacheopt_test.go @@ -0,0 +1,28 @@ +package cache + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestCacheOptions(t *testing.T) { + t.Run("default options", func(t *testing.T) { + o := newOptions() + assert.Equal(t, defaultExpiry, o.Expiry) + assert.Equal(t, defaultNotFoundExpiry, o.NotFoundExpiry) + }) + + t.Run("with expiry", func(t *testing.T) { + o := newOptions(WithExpiry(time.Second)) + assert.Equal(t, time.Second, o.Expiry) + assert.Equal(t, defaultNotFoundExpiry, o.NotFoundExpiry) + }) + + t.Run("with not found expiry", func(t *testing.T) { + o := newOptions(WithNotFoundExpiry(time.Second)) + assert.Equal(t, defaultExpiry, o.Expiry) + assert.Equal(t, time.Second, o.NotFoundExpiry) + }) +} diff --git a/pkg/cache/gorm.go b/pkg/cache/gorm.go index 23552de..0fd2805 100644 --- a/pkg/cache/gorm.go +++ b/pkg/cache/gorm.go @@ -5,12 +5,16 @@ import ( "database/sql" "encoding/json" "errors" + "time" "github.com/redis/go-redis/v9" "gorm.io/gorm" ) -var ErrNotFound = redis.Nil +var ( + // ErrNotFound is the error when cache not found. + ErrNotFound = redis.Nil +) type ( // ExecCtxFn defines the sql exec method. @@ -23,16 +27,21 @@ type ( QueryCtxFn func(conn *gorm.DB, v interface{}) error CachedConn struct { - db *gorm.DB - cache *redis.Client + db *gorm.DB + cache *redis.Client + expiry time.Duration + notFoundExpiry time.Duration } ) // NewConn returns a CachedConn with a redis cluster cache. -func NewConn(db *gorm.DB, c *redis.Client) CachedConn { +func NewConn(db *gorm.DB, c *redis.Client, opts ...Option) CachedConn { + o := newOptions(opts...) return CachedConn{ - db: db, - cache: c, + db: db, + cache: c, + expiry: o.Expiry, + notFoundExpiry: o.NotFoundExpiry, } } @@ -65,7 +74,7 @@ func (cc CachedConn) SetCache(key string, v interface{}) error { return err } // set redis key - return cc.cache.Set(context.Background(), key, val, 0).Err() + return cc.cache.Set(context.Background(), key, val, cc.expiry).Err() } // ExecCtx runs given exec on given keys, and returns execution result.