Skip to content

Commit

Permalink
feat: support customized package key (#14)
Browse files Browse the repository at this point in the history
Co-authored-by: viney-shih <[email protected]>
  • Loading branch information
VineyAT and viney-shih committed Jun 25, 2022
1 parent 375a308 commit 254f4db
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 65 deletions.
2 changes: 1 addition & 1 deletion event.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func init() {

// Topic generates the topic for specified event.
func (x eventType) Topic() string {
return customKey(topicDelim, packageKey, topicKey, x.String())
return getTopic(x.String())
}

type event struct {
Expand Down
4 changes: 2 additions & 2 deletions factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ var (
uuidString = uuid.New().String
)

func newFactory(sharedCache Adapter, localCache Adapter, options ...ServiceOptions) Factory {
func newFactory(sharedCache Adapter, localCache Adapter, options ...FactoryOptions) Factory {
// load options
o := loadServiceOptions(options...)
o := loadFactoryOptions(options...)
// need to specify marshalFunc and unmarshalFunc at the same time
if o.marshalFunc == nil && o.unmarshalFunc != nil {
panic(errors.New("both of Marshal and Unmarshal functions need to be specified"))
Expand Down
37 changes: 0 additions & 37 deletions factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -249,39 +248,3 @@ func (s *factorySuite) TestNewCacheWithOnlyUnmarshal() {
},
})
}

func (s *factorySuite) TestGetPrefixAndKey() {
tests := []struct {
Desc string
CacheKey string
ExpPfx string
ExpKey string
}{
{
Desc: "invalid cache key without delimiter",
CacheKey: "12345",
ExpPfx: "12345",
ExpKey: "",
},
{
Desc: "invalid cache key with only one delimiter",
CacheKey: fmt.Sprintf("%s%s%s", "123", cacheDelim, "abc"),
ExpPfx: "abc",
ExpKey: "",
},
{
Desc: "normal case",
CacheKey: getCacheKey("prefix", "key"),
ExpPfx: "prefix",
ExpKey: "key",
},
}

for _, t := range tests {
pfx, key := getPrefixAndKey(t.CacheKey)
s.Require().Equal(t.ExpPfx, pfx, t.Desc)
s.Require().Equal(t.ExpKey, key, t.Desc)

s.TearDownTest()
}
}
7 changes: 6 additions & 1 deletion interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type Factory interface {
}

// NewFactory returns the Factory initialized in the main.go.
func NewFactory(sharedCache Adapter, localCache Adapter, options ...ServiceOptions) Factory {
func NewFactory(sharedCache Adapter, localCache Adapter, options ...FactoryOptions) Factory {
return newFactory(sharedCache, localCache, options...)
}

Expand Down Expand Up @@ -110,3 +110,8 @@ type Result interface {
func ClearPrefix() {
usedPrefixs = map[string]struct{}{}
}

// Register registers customized parameters in the package.
func Register(packageKey string) {
registerKey(packageKey)
}
36 changes: 32 additions & 4 deletions key.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cache

import "strings"
import (
"strings"
"sync"
)

const (
packageKey = "ca"
Expand All @@ -11,12 +14,32 @@ const (
topicDelim = "#"
)

var (
regPkgKey = packageKey
// regKeyOnce limits key registeration happening once
regKeyOnce = sync.Once{}
)

func registerKey(pkgKey string) {
regKeyOnce.Do(func() {
regPkgKey = pkgKey
})
}

func customKey(delimiter string, components ...string) string {
return strings.Join(components, delimiter)
}

func getTopic(topic string) string {
return customKey(topicDelim, regPkgKey, topicKey, topic)
}

func getCacheKey(pfx, key string) string {
return customKey(cacheDelim, packageKey, pfx, key)
if regPkgKey == "" {
return customKey(cacheDelim, pfx, key)
}

return customKey(cacheDelim, regPkgKey, pfx, key)
}

func getCacheKeys(pfx string, keys []string) []string {
Expand All @@ -29,10 +52,15 @@ func getCacheKeys(pfx string, keys []string) []string {
}

func getPrefixAndKey(cacheKey string) (string, string) {
// cacheKey = packageKey + prefix + key
// 1) cacheKey = regPkgKey + prefix + key (normal case)
// 2) cacheKey = prefix + key (if customized package key is empty)
idx := strings.Index(cacheKey, cacheDelim)
if idx < 0 {
return cacheKey, ""
return cacheKey, "" // should not happen
}

if regPkgKey == "" {
return cacheKey[:idx], cacheKey[idx+len(cacheDelim):]
}

// mixedKey = prefix + key
Expand Down
107 changes: 107 additions & 0 deletions key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package cache

import (
"fmt"
"sync"
"testing"

"github.com/stretchr/testify/suite"
)

type keySuite struct {
suite.Suite
}

func (s *keySuite) SetupSuite() {}

func (s *keySuite) TearDownSuite() {}

func (s *keySuite) SetupTest() {}

func (s *keySuite) TearDownTest() {
clearRegisteredKey()
}

func TestKeySuite(t *testing.T) {
suite.Run(t, new(keySuite))
}

func clearRegisteredKey() {
regPkgKey = packageKey
regKeyOnce = sync.Once{}
}

func (s *keySuite) TestGetPrefixAndKey() {
tests := []struct {
Desc string
CacheKey string
ExpPfx string
ExpKey string
}{
{
Desc: "invalid cache key without delimiter",
CacheKey: "12345",
ExpPfx: "12345",
ExpKey: "",
},
{
Desc: "invalid cache key with only one delimiter",
CacheKey: fmt.Sprintf("%s%s%s", "123", cacheDelim, "abc"),
ExpPfx: "abc",
ExpKey: "",
},
{
Desc: "normal case",
CacheKey: getCacheKey("prefix", "key"),
ExpPfx: "prefix",
ExpKey: "key",
},
}

for _, t := range tests {
pfx, key := getPrefixAndKey(t.CacheKey)
s.Require().Equal(t.ExpPfx, pfx, t.Desc)
s.Require().Equal(t.ExpKey, key, t.Desc)

s.TearDownTest()
}
}

func (s *keySuite) TestRegister() {
s.Require().Equal(packageKey, regPkgKey)

Register("specified")
s.Require().Equal("specified", regPkgKey)

Register("another")
s.Require().Equal("specified", regPkgKey) // no change

clearRegisteredKey()
s.Require().Equal(packageKey, regPkgKey) // set to default

Register("another")
s.Require().Equal("another", regPkgKey) // set to another
}

func (s *keySuite) TestRegisterAndGetCacheKey() {
var cKey, pfx, key string

s.Require().Equal(fmt.Sprintf("%s:pfx:key", packageKey), getCacheKey("pfx", "key"))

Register("my")
cKey = getCacheKey("pfx", "key")
s.Require().Equal("my:pfx:key", cKey)
pfx, key = getPrefixAndKey(cKey)
s.Require().Equal(pfx, "pfx")
s.Require().Equal(key, "key")

clearRegisteredKey()
s.Require().Equal(fmt.Sprintf("%s:pfx:key", packageKey), getCacheKey("pfx", "key")) // set to default

Register("") // empty package key
cKey = getCacheKey("pfx", "key")
s.Require().Equal("pfx:key", cKey)
pfx, key = getPrefixAndKey(cKey)
s.Require().Equal(pfx, "pfx")
s.Require().Equal(key, "key")
}
40 changes: 20 additions & 20 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ type MarshalFunc func(interface{}) ([]byte, error)
// The default is json.Unmarshal
type UnmarshalFunc func([]byte, interface{}) error

// ServiceOptions is an alias for functional argument.
type ServiceOptions func(opts *serviceOptions)
// FactoryOptions is an alias for functional argument.
type FactoryOptions func(opts *factoryOptions)

// serviceOptions contains all options which will be applied when calling New().
type serviceOptions struct {
// factoryOptions contains all options which will be applied when calling NewFactory().
type factoryOptions struct {
marshalFunc MarshalFunc
unmarshalFunc UnmarshalFunc
onCacheHit func(prefix string, key string, count int)
Expand All @@ -24,57 +24,57 @@ type serviceOptions struct {

// WithMarshalFunc sets up the specified marshal function.
// Needs to consider with unmarshal function at the same time.
func WithMarshalFunc(f MarshalFunc) ServiceOptions {
return func(opts *serviceOptions) {
func WithMarshalFunc(f MarshalFunc) FactoryOptions {
return func(opts *factoryOptions) {
opts.marshalFunc = f
}
}

// WithUnmarshalFunc sets up the specified unmarshal function.
// Needs to consider with marshal function at the same time.
func WithUnmarshalFunc(f UnmarshalFunc) ServiceOptions {
return func(opts *serviceOptions) {
func WithUnmarshalFunc(f UnmarshalFunc) FactoryOptions {
return func(opts *factoryOptions) {
opts.unmarshalFunc = f
}
}

// WithPubSub is used to evict keys in local cache
func WithPubSub(pb Pubsub) ServiceOptions {
return func(opts *serviceOptions) {
func WithPubSub(pb Pubsub) FactoryOptions {
return func(opts *factoryOptions) {
opts.pubsub = pb
}
}

// OnCacheHitFunc sets up the callback function on cache hitted
func OnCacheHitFunc(f func(prefix string, key string, count int)) ServiceOptions {
return func(opts *serviceOptions) {
func OnCacheHitFunc(f func(prefix string, key string, count int)) FactoryOptions {
return func(opts *factoryOptions) {
opts.onCacheHit = f
}
}

// OnCacheMissFunc sets up the callback function on cache missed
func OnCacheMissFunc(f func(prefix string, key string, count int)) ServiceOptions {
return func(opts *serviceOptions) {
func OnCacheMissFunc(f func(prefix string, key string, count int)) FactoryOptions {
return func(opts *factoryOptions) {
opts.onCacheMiss = f
}
}

// OnLocalCacheCostAddFunc sets up the callback function on adding the cost of key in local cache
func OnLocalCacheCostAddFunc(f func(prefix string, key string, cost int)) ServiceOptions {
return func(opts *serviceOptions) {
func OnLocalCacheCostAddFunc(f func(prefix string, key string, cost int)) FactoryOptions {
return func(opts *factoryOptions) {
opts.onLCCostAdd = f
}
}

// OnLocalCacheCostEvictFunc sets up the callback function on evicting the cost of key in local cache
func OnLocalCacheCostEvictFunc(f func(prefix string, key string, cost int)) ServiceOptions {
return func(opts *serviceOptions) {
func OnLocalCacheCostEvictFunc(f func(prefix string, key string, cost int)) FactoryOptions {
return func(opts *factoryOptions) {
opts.onLCCostEvict = f
}
}

func loadServiceOptions(options ...ServiceOptions) *serviceOptions {
opts := &serviceOptions{}
func loadFactoryOptions(options ...FactoryOptions) *factoryOptions {
opts := &factoryOptions{}
for _, option := range options {
option(opts)
}
Expand Down

0 comments on commit 254f4db

Please sign in to comment.