Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cache feat & cache refactor #14

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 0 additions & 68 deletions cache/manager_test.go
Original file line number Diff line number Diff line change
@@ -1,81 +1,13 @@
package cache

import (
"context"
"sync"
"testing"
"time"

"github.com/go-packagist/go-kratos-components/contract/cache"
"github.com/stretchr/testify/assert"
)

type mockStore struct {
items map[string]interface{}
rw sync.RWMutex
}

func newMockStore() cache.Store {
return &mockStore{
items: make(map[string]interface{}),
}
}

func (m *mockStore) Has(ctx context.Context, key string) bool {
m.rw.RLock()
defer m.rw.RUnlock()

_, ok := m.items[key]

return ok
}

func (m *mockStore) Get(ctx context.Context, key string, dest interface{}) error {
m.rw.RLock()
defer m.rw.RUnlock()

if item, ok := m.items[key]; ok {
return valueOf(item, dest)
}

return cache.ErrKeyNotFound
}

func (m *mockStore) Put(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
m.rw.Lock()
defer m.rw.Unlock()

m.items[key] = value

return nil
}

func (m *mockStore) Increment(ctx context.Context, key string, value int) (int, error) {
panic("implement me")
}

func (m *mockStore) Decrement(ctx context.Context, key string, value int) (int, error) {
panic("implement me")
}

func (m *mockStore) Forever(ctx context.Context, key string, value interface{}) error {
panic("implement me")
}

func (m *mockStore) Forget(ctx context.Context, key string) error {
panic("implement me")
}

func (m *mockStore) Flush(ctx context.Context) error {
panic("implement me")
}

func (m *mockStore) GetPrefix() string {
panic("implement me")
}

var _ cache.Store = (*mockStore)(nil)

func TestManager(t *testing.T) {
m := NewManager(&Config{
Default: "test1",
Expand All @@ -88,7 +20,7 @@
var test1, test2, test3, test4 string

// use default
assert.NoError(t, m.Connect().Put(ctx, "test", "test", time.Second*10))

Check failure on line 23 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.18.x, ubuntu-latest)

multiple-value m.Connect().Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context

Check failure on line 23 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.19.x, ubuntu-latest)

multiple-value m.Connect().Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context

Check failure on line 23 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

multiple-value m.Connect().Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context

Check failure on line 23 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

multiple-value m.Connect().Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context
assert.NoError(t, m.Connect().Get(ctx, "test", &test1))
assert.Equal(t, "test", test1)

Expand All @@ -100,7 +32,7 @@
assert.Error(t, m.Connect("test2").Get(ctx, "test", &test3))
assert.NotEqual(t, "test", test3)

assert.NoError(t, m.Connect("test2").Put(ctx, "test", "test", time.Second*10))

Check failure on line 35 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.18.x, ubuntu-latest)

multiple-value m.Connect("test2").Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context

Check failure on line 35 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.19.x, ubuntu-latest)

multiple-value m.Connect("test2").Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context

Check failure on line 35 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

multiple-value m.Connect("test2").Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context

Check failure on line 35 in cache/manager_test.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

multiple-value m.Connect("test2").Put(ctx, "test", "test", time.Second * 10) (value of type (bool, error)) in single-value context
assert.NoError(t, m.Connect("test2").Get(ctx, "test", &test4))
assert.Equal(t, "test", test4)

Expand Down
42 changes: 28 additions & 14 deletions cache/redis/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ func New(opts ...Option) cache.Store {
}
}

func (s *Store) Has(ctx context.Context, key string) bool {
if result := s.opt.redis.Exists(ctx, s.opt.prefix+key); result.Err() == nil && result.Val() == 1 {
return true
func (s *Store) Has(ctx context.Context, key string) (bool, error) {
if result := s.opt.redis.Exists(ctx, s.opt.prefix+key); result.Err() != nil {
return false, result.Err()
} else if result.Val() == 1 {
return true, nil
}

return false
return false, nil
}

func (s *Store) Get(ctx context.Context, key string, dest interface{}) error {
Expand All @@ -86,11 +88,13 @@ func (s *Store) Get(ctx context.Context, key string, dest interface{}) error {
return s.opt.serializer.Unserialize([]byte(result.Val()), dest)
}

func (s *Store) Put(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
func (s *Store) Put(ctx context.Context, key string, value interface{}, ttl time.Duration) (bool, error) {
if data, err := s.opt.serializer.Serialize(value); err != nil {
return err
return false, err
} else if ok, err := s.opt.redis.SetEx(ctx, s.opt.prefix+key, data, ttl).Result(); err != nil {
return false, err
} else {
return s.opt.redis.SetEx(ctx, s.opt.prefix+key, data, ttl).Err()
return ok == "OK", nil
}
}

Expand All @@ -110,20 +114,30 @@ func (s *Store) Decrement(ctx context.Context, key string, value int) (int, erro
}
}

func (s *Store) Forever(ctx context.Context, key string, value interface{}) error {
func (s *Store) Forever(ctx context.Context, key string, value interface{}) (bool, error) {
if data, err := s.opt.serializer.Serialize(value); err != nil {
return err
return false, err
} else if ok, err := s.opt.redis.Set(ctx, s.opt.prefix+key, data, redis.KeepTTL).Result(); err != nil {
return false, err
} else {
return s.opt.redis.Set(ctx, s.opt.prefix+key, data, redis.KeepTTL).Err()
return ok == "OK", nil
}
}

func (s *Store) Forget(ctx context.Context, key string) error {
return s.opt.redis.Del(ctx, s.opt.prefix+key).Err()
func (s *Store) Forget(ctx context.Context, key string) (bool, error) {
if deleted, err := s.opt.redis.Del(ctx, s.opt.prefix+key).Result(); err != nil {
return false, err
} else {
return deleted == 1, nil
}
}

func (s *Store) Flush(ctx context.Context) error {
return s.opt.redis.FlushAll(ctx).Err()
func (s *Store) Flush(ctx context.Context) (bool, error) {
if ok, err := s.opt.redis.FlushAll(ctx).Result(); err != nil {
return false, err
} else {
return ok == "OK", nil
}
}

func (s *Store) GetPrefix() string {
Expand Down
23 changes: 16 additions & 7 deletions cache/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"time"

"github.com/go-packagist/go-kratos-components/contract/cache"
"github.com/go-packagist/go-kratos-components/helper"
)

type Repository struct {
Expand All @@ -12,21 +13,25 @@
}

func NewRepository(store cache.Store) cache.Repository {
return &Repository{

Check failure on line 16 in cache/repository.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

cannot use &Repository{…} (value of type *Repository) as "github.com/go-packagist/go-kratos-components/contract/cache".Repository value in return statement: *Repository does not implement "github.com/go-packagist/go-kratos-components/contract/cache".Repository (wrong type for method Delete)

Check failure on line 16 in cache/repository.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

cannot use &Repository{…} (value of type *Repository) as "github.com/go-packagist/go-kratos-components/contract/cache".Repository value in return statement: *Repository does not implement "github.com/go-packagist/go-kratos-components/contract/cache".Repository (wrong type for method Delete)
Store: store,
}
}

func (r *Repository) Missing(ctx context.Context, key string) bool {
return !r.Store.Has(ctx, key)
func (r *Repository) Missing(ctx context.Context, key string) (bool, error) {
if hatted, err := r.Store.Has(ctx, key); err != nil {
return false, err
} else {
return hatted, nil
}
}

func (r *Repository) Delete(ctx context.Context, key string) error {
return r.Store.Forget(ctx, key)

Check failure on line 30 in cache/repository.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

too many return values

Check failure on line 30 in cache/repository.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

too many return values
}

func (r *Repository) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
return r.Store.Put(ctx, key, value, ttl)

Check failure on line 34 in cache/repository.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

too many return values

Check failure on line 34 in cache/repository.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

too many return values
}

func (r *Repository) Add(ctx context.Context, key string, value interface{}, ttl time.Duration) (bool, error) {
Expand All @@ -34,7 +39,9 @@
return addable.Add(ctx, key, value, ttl)
}

if r.Missing(ctx, key) {
if missed, err := r.Missing(ctx, key); err != nil {
return false, err
} else if !missed {
if err := r.Set(ctx, key, value, ttl); err != nil {
return false, err
} else {
Expand All @@ -46,14 +53,16 @@
}

func (r *Repository) Remember(ctx context.Context, key string, dest interface{}, value func() interface{}, ttl time.Duration) error {
if r.Missing(ctx, key) {
v := value()
if missed, err := r.Missing(ctx, key); err != nil {
return err
} else if missed {
valued := value()

if err := r.Set(ctx, key, v, ttl); err != nil {
if err := r.Set(ctx, key, valued, ttl); err != nil {
return err
}

return valueOf(v, dest)
return helper.ValueOf(valued, dest)
}

return r.Get(ctx, key, dest)
Expand Down
92 changes: 77 additions & 15 deletions cache/respository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,94 @@

import (
"context"
"sync"
"testing"
"time"

redisCache "github.com/go-packagist/go-kratos-components/cache/redis"
"github.com/go-packagist/go-kratos-components/contract/cache"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
)

var ctx = context.Background()

func createRedisRepository() cache.Repository {
return NewRepository(
redisCache.New(
redisCache.Prefix("repository"),
redisCache.Redis(
redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
}),
),
),
)
type mockStore struct {
items map[string]interface{}
rw sync.RWMutex
}

func newMockStore() cache.Store {
return &mockStore{

Check failure on line 21 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.18.x, ubuntu-latest)

cannot use &mockStore{…} (value of type *mockStore) as type "github.com/go-packagist/go-kratos-components/contract/cache".Store in return statement:

Check failure on line 21 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.19.x, ubuntu-latest)

cannot use &mockStore{…} (value of type *mockStore) as type "github.com/go-packagist/go-kratos-components/contract/cache".Store in return statement:

Check failure on line 21 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

cannot use &mockStore{…} (value of type *mockStore) as "github.com/go-packagist/go-kratos-components/contract/cache".Store value in return statement: *mockStore does not implement "github.com/go-packagist/go-kratos-components/contract/cache".Store (wrong type for method Flush)

Check failure on line 21 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

cannot use &mockStore{…} (value of type *mockStore) as "github.com/go-packagist/go-kratos-components/contract/cache".Store value in return statement: *mockStore does not implement "github.com/go-packagist/go-kratos-components/contract/cache".Store (wrong type for method Flush)
items: make(map[string]interface{}),
}
}

func (m *mockStore) Has(ctx context.Context, key string) (bool, error) {
m.rw.RLock()
defer m.rw.RUnlock()

_, ok := m.items[key]

return ok, nil
}

func (m *mockStore) Get(ctx context.Context, key string, dest interface{}) error {
m.rw.RLock()
defer m.rw.RUnlock()

if item, ok := m.items[key]; ok {
return valueOf(item, dest)

Check failure on line 40 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.18.x, ubuntu-latest)

undefined: valueOf

Check failure on line 40 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.19.x, ubuntu-latest)

undefined: valueOf

Check failure on line 40 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

undefined: valueOf

Check failure on line 40 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

undefined: valueOf
}

return cache.ErrKeyNotFound
}

func (m *mockStore) Put(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
m.rw.Lock()
defer m.rw.Unlock()

m.items[key] = value

return nil
}

func (m *mockStore) Increment(ctx context.Context, key string, value int) (int, error) {
panic("implement me")
}

func (m *mockStore) Decrement(ctx context.Context, key string, value int) (int, error) {
panic("implement me")
}

func (m *mockStore) Forever(ctx context.Context, key string, value interface{}) error {
panic("implement me")
}

func (m *mockStore) Forget(ctx context.Context, key string) error {
panic("implement me")
}

func (m *mockStore) Flush(ctx context.Context) error {
panic("implement me")
}

func (m *mockStore) GetPrefix() string {
panic("implement me")
}

var _ cache.Store = (*mockStore)(nil)

Check failure on line 79 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.18.x, ubuntu-latest)

cannot use (*mockStore)(nil) (value of type *mockStore) as type "github.com/go-packagist/go-kratos-components/contract/cache".Store in variable declaration:

Check failure on line 79 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.19.x, ubuntu-latest)

cannot use (*mockStore)(nil) (value of type *mockStore) as type "github.com/go-packagist/go-kratos-components/contract/cache".Store in variable declaration:

Check failure on line 79 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.20.x, ubuntu-latest)

cannot use (*mockStore)(nil) (value of type *mockStore) as "github.com/go-packagist/go-kratos-components/contract/cache".Store value in variable declaration: *mockStore does not implement "github.com/go-packagist/go-kratos-components/contract/cache".Store (wrong type for method Flush)

Check failure on line 79 in cache/respository_test.go

View workflow job for this annotation

GitHub Actions / go test (1.21.x, ubuntu-latest)

cannot use (*mockStore)(nil) (value of type *mockStore) as "github.com/go-packagist/go-kratos-components/contract/cache".Store value in variable declaration: *mockStore does not implement "github.com/go-packagist/go-kratos-components/contract/cache".Store (wrong type for method Flush)

func newMockRepository() cache.Repository {
return NewRepository(newMockStore())
}

func TestRepository_Has(t *testing.T) {
r := newMockRepository()

r.Has(ctx, "test")
}

func TestRepository_Add(t *testing.T) {
r := createRedisRepository()
r := newMockRepository()

added, err := r.Add(ctx, "test", 1, time.Second*30)
assert.NoError(t, err)
Expand All @@ -39,7 +101,7 @@
}

func TestRepository_Remember(t *testing.T) {
r := createRedisRepository()
r := newMockRepository()

var value string
err1 := r.Remember(ctx, "remember", &value, func() interface{} {
Expand Down
27 changes: 0 additions & 27 deletions cache/util.go

This file was deleted.

9 changes: 4 additions & 5 deletions contract/cache/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import (
)

var (
ErrKeyAlreadyExists = errors.New("cache: key already exists")
ErrKeyNotFound = errors.New("cache: key not found")
ErrKeyNotFound = errors.New("cache: key not found")
)

type Repository interface {
Store
Addable

Missing(ctx context.Context, key string) bool
Delete(ctx context.Context, key string) error
Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error
Missing(ctx context.Context, key string) (bool, error)
Delete(ctx context.Context, key string) (bool, error)
Set(ctx context.Context, key string, value interface{}, ttl time.Duration) (bool, error)
Remember(ctx context.Context, key string, dest interface{}, value func() interface{}, ttl time.Duration) error
}
Loading
Loading