Skip to content

Commit

Permalink
feat: make decorator use variadic arguments as config
Browse files Browse the repository at this point in the history
  • Loading branch information
ahuigo committed Dec 8, 2023
1 parent e3ed254 commit 835fbe4
Show file tree
Hide file tree
Showing 12 changed files with 447 additions and 67 deletions.
4 changes: 2 additions & 2 deletions cache-map-mem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestCacheFuncWithNoParam(t *testing.T) {
getUserInfoFromDbWithCache := CacheFn0Err(getUserInfoFromDb, &Config{TTL: 400 * time.Millisecond}) // getFunc can only accept zero parameter
_ = getUserInfoFromDbWithCache

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
userinfo, err := getUserInfoFromDbWithCache()
fmt.Println(userinfo, err)
Expand Down Expand Up @@ -72,7 +72,7 @@ func TestCacheFuncWith2Param(t *testing.T) {
TTL: time.Hour,
}) // getFunc can only accept 2 parameter

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
ctx := context.Background()
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(ctx, map[int]int{0: 1})
Expand Down
34 changes: 21 additions & 13 deletions decorator.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ type cachedFn[K1 any, K2 any, V any] struct {
getFunc func(K1, K2) (V, error)
}

func (c *cachedFn[K1, K2, V]) setConfigs(configs ...*Config) *cachedFn[K1, K2, V] {
if len(configs) > 0 {
return c.setConfig(configs[0])
} else {
return c.setConfig(nil)
}
}

func (c *cachedFn[K1, K2, V]) setConfig(config *Config) *cachedFn[K1, K2, V] {
// default value
if config == nil {
Expand Down Expand Up @@ -77,74 +85,74 @@ func (c *cachedFn[K1, K2, V]) setConfig(config *Config) *cachedFn[K1, K2, V] {
// Cache Function with 2 parameter
func CacheFn2Err[K1 any, K2 any, V any](
getFunc func(K1, K2) (V, error),
config *Config,
configs ...*Config,
) func(K1, K2) (V, error) {
ins := &cachedFn[K1, K2, V]{getFunc: getFunc, keyLen: 2}
ins.setConfig(config)
ins.setConfigs(configs...)
return ins.invoke2err
}

// Cache Function with 2 parameter
func CacheFn2[K1 any, K2 any, V any](
getFunc func(K1, K2) V,
config *Config,
configs ...*Config,
) func(K1, K2) V {
getFunc0 := func(ctx K1, key K2) (V, error) {
return getFunc(ctx, key), nil
}
ins := &cachedFn[K1, K2, V]{getFunc: getFunc0, keyLen: 2}
ins.setConfig(config)
ins.setConfigs(configs...)
return ins.invoke2
}

// Cache Function with 1 parameter
func CacheFn1Err[K any, V any](
getFunc func(K) (V, error),
config *Config,
configs ...*Config,
) func(K) (V, error) {
getFunc0 := func(ctx context.Context, key K) (V, error) {
return getFunc(key)
}
ins := &cachedFn[context.Context, K, V]{getFunc: getFunc0, keyLen: 1}
ins.setConfig(config)
ins.setConfigs(configs...)
return ins.invoke1
}

func CacheFn1[K any, V any](
getFunc func(K) V,
config *Config,
configs ...*Config,
) func(K) V {
getFunc0 := func(ctx context.Context, key K) (V, error) {
return getFunc(key), nil
}
ins := &cachedFn[context.Context, K, V]{getFunc: getFunc0, keyLen: 1}
ins.setConfig(config)
ins.setConfigs(configs...)
return ins.invoke1err
}

// Cache Function with 0 parameter
func CacheFn0Err[V any](
getFunc func() (V, error),
config *Config,
configs ...*Config,
) func() (V, error) {
getFunc0 := func(ctx context.Context, i int8) (V, error) {
return getFunc()
}
ins := &cachedFn[context.Context, int8, V]{getFunc: getFunc0, keyLen: 0}
ins.setConfig(config)
ins.setConfigs(configs...)
return ins.invoke0err
}

// Cache Function with 0 parameter
func CacheFn0[V any](
getFunc func() V,
config *Config,
configs ...*Config,
) func() V {
getFunc0 := func(ctx context.Context, i int8) (V, error) {
return getFunc(), nil
}
ins := &cachedFn[context.Context, int8, V]{getFunc: getFunc0, keyLen: 0}
ins.setConfig(config)
ins.setConfigs(configs...)
return ins.invoke0
}

Expand Down Expand Up @@ -274,7 +282,7 @@ checkCache:
}

// 4. Execute getFunc(only once)
if !hasCache{
if !hasCache {
// 4.1 try lock
// If 100 goroutines call the same function at the same time,
// only one goroutine can execute the getFunc.
Expand Down
2 changes: 1 addition & 1 deletion examples/decorator-key-custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestCacheFuncKeyCustom(t *testing.T) {
HashKeyFunc: hashKeyFunc,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(&UserInfo{id: 1}, true)
if score != 99 {
Expand Down
4 changes: 2 additions & 2 deletions examples/decorator-key-ptr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestCacheFuncKeyPointerAddr(t *testing.T) {
HashKeyPointerAddr: true,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(&UserInfo{id: 1})
if score != 99 {
Expand Down Expand Up @@ -56,7 +56,7 @@ func TestCacheFuncKeyPointerCycle(t *testing.T) {
// Cacheable Function
getUserScoreCached := gofnext.CacheFn1Err(getUserScore, &gofnext.Config{})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
u := &UserInfo{id: 1}
u.User = u
score, _ := getUserScoreCached(u)
Expand Down
12 changes: 6 additions & 6 deletions examples/decorator-key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestCacheFuncKeyStruct(t *testing.T) {
TTL: time.Hour,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(UserInfo{id: 1})
if score != 99 {
Expand Down Expand Up @@ -59,7 +59,7 @@ func TestCacheFuncKeyMap(t *testing.T) {
TTL: time.Hour,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(usermap{"id": 1})
if score != 99 {
Expand Down Expand Up @@ -92,7 +92,7 @@ func TestCacheFuncKeyDeepMap(t *testing.T) {
TTL: time.Hour,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(Params{m: map[string]int{"id": 1}})
if score != 99 {
Expand Down Expand Up @@ -126,7 +126,7 @@ func TestCacheFuncKeySlice(t *testing.T) {
TTL: time.Hour,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache([]UserInfo{{id: 1}})
if score != 99 {
Expand Down Expand Up @@ -161,7 +161,7 @@ func TestCacheFuncKeyPointer(t *testing.T) {
TTL: time.Hour,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(&UserInfo{id: 1})
if score != 99 {
Expand Down Expand Up @@ -200,7 +200,7 @@ func TestCacheFuncKeyInnerPointer(t *testing.T) {
NeedDumpKey: true,
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(ExtUserInfo{u: &UserInfo{id: 1}})
if score != 99 {
Expand Down
2 changes: 1 addition & 1 deletion examples/decorator-lru_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestCacheFuncWithOneParamLRU(t *testing.T) {
CacheMap: gofnext.NewCacheLru(maxCacheSize),
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
for i := 0; i < 10; i++ {
score, err := getUserScoreFromDbWithLruCache(1)
fmt.Println(score, err)
Expand Down
2 changes: 1 addition & 1 deletion examples/decorator-redis-err_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestRedisCacheFuncErr(t *testing.T) {
CacheMap: gofnext.NewCacheRedis("redis-cache-key").ClearAll(),
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
for i := 0; i < 10; i++ {
score, err := getUserScoreFromDbWithCache(1)
if err == nil {
Expand Down
10 changes: 5 additions & 5 deletions examples/decorator-redis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestRedisCacheFuncWithTTL(t *testing.T) {
CacheMap: gofnext.NewCacheRedis("redis-cache-key").ClearAll(),
})

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
for i := 0; i < 10; i++ {
score, err := getUserScoreFromDbWithCache(1)
if err != nil || score != 99 {
Expand Down Expand Up @@ -77,7 +77,7 @@ func TestRedisCacheFuncWithNoTTL(t *testing.T) {
},
) // getFunc can only accept 1 parameter

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score, err := getUserScoreFromDbWithCache(1, true)
if err != nil || score != 99 {
Expand Down Expand Up @@ -107,8 +107,8 @@ func TestRedisCacheFuncWithTTLTimeout(t *testing.T) {
CacheMap: gofnext.NewCacheRedis("redis-cache-key").ClearAll(),
})

// Parallel invocation of multiple functions.
for i := 0; i < 5; i++ {//2+4=6 times
// Execute the function multi times in parallel.
for i := 0; i < 5; i++ { //2+4=6 times
getUserScoreFromDbWithCache(1)
time.Sleep(time.Millisecond * 500)
getUserScoreFromDbWithCache(1)
Expand All @@ -117,4 +117,4 @@ func TestRedisCacheFuncWithTTLTimeout(t *testing.T) {
if executeCount != 6 {
t.Errorf("executeCount should be 6, but get %d", executeCount)
}
}
}
41 changes: 27 additions & 14 deletions examples/decorator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,65 @@ package examples

import (
"context"
"errors"
"fmt"
"testing"
"time"

"github.com/ahuigo/gofnext"
)

func getUser(age int) UserInfo {
func getUser() UserInfo {
time.Sleep(10 * time.Millisecond)
return UserInfo{Name: "Alex", Age: age}
return UserInfo{Name: "Alex", Age: 20}
}

var (
// Cacheable Function with 1 param and no error
getUserInfoFromDb = gofnext.CacheFn1(getUser, nil)
getUserInfoFromDb = gofnext.CacheFn0(getUser)
)

func TestCacheFuncWith0Param(t *testing.T) {
// Parallel invocation of multiple functions.
times := 10
// Execute the function 10 times in parallel.
parallelCall(func() {
userinfo := getUserInfoFromDb()
fmt.Println(userinfo)
}, 10) //10 times
}

func TestCacheFuncWith1Param(t *testing.T) {
getUser := func(age int) UserInfo {
time.Sleep(10 * time.Millisecond)
return UserInfo{Name: "Alex", Age: age}
}

// cacheable function
getUserInfoFromDb := gofnext.CacheFn1(getUser)

parallelCall(func() {
userinfo := getUserInfoFromDb(20)
fmt.Println(userinfo)
}, times)
}, 10)
}

func TestCacheFuncWith2Params(t *testing.T) {
// Original function
executeCount := 0
getUserScore := func(c context.Context, id int) (int, error) {
getUserScore := func(c context.Context, id int) int {
executeCount++
fmt.Println("select score from db where id=", id, time.Now())
time.Sleep(10 * time.Millisecond)
return 98 + id, errors.New("db error")
return 98 + id
}

// Cacheable Function
getUserScoreFromDbWithCache := gofnext.CacheFn2Err(getUserScore, &gofnext.Config{
getUserScoreFromDbWithCache := gofnext.CacheFn2(getUserScore, &gofnext.Config{
TTL: time.Hour,
}) // getFunc can only accept 2 parameter

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
ctx := context.Background()
parallelCall(func() {
score, _ := getUserScoreFromDbWithCache(ctx, 1)
score := getUserScoreFromDbWithCache(ctx, 1)
if score != 99 {
t.Errorf("score should be 99, but get %d", score)
}
Expand Down Expand Up @@ -87,9 +100,9 @@ func TestCacheFuncWithMoreParams(t *testing.T) {
}

// Cacheable Function
fnCached := gofnext.CacheFn1(fnWrap, nil)
fnCached := gofnext.CacheFn1(fnWrap)

// Parallel invocation of multiple functions.
// Execute the function multi times in parallel.
parallelCall(func() {
score := fnCached(Stu{"Alex", 20, 1})
if score != 10 {
Expand Down
Loading

0 comments on commit 835fbe4

Please sign in to comment.