You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
2.8 KiB

3 years ago
package cache
import (
"encoding/json"
"fmt"
"strconv"
"time"
"gitoa.ru/go-4devs/encoding"
)
var _ fmt.Stringer = (*Key)(nil)
// Option ffor the configuration item.
type Option func(*Item)
// WithNamespace sets prefix and separator.
func WithNamespace(prefix, sep string) Option {
return func(d *Item) {
d.Key.Prefix = prefix
d.Key.Separator = sep
}
}
// WithTTL sets ttl.
func WithTTL(ttl time.Duration) Option {
return func(d *Item) {
d.TTL = ttl
}
}
// WithMarshal sets marshal and unmarshal.
func WithMarshal(unmarshal encoding.Unmarshal, marshal encoding.Marshal) Option {
return func(d *Item) {
d.unmarshal = unmarshal
d.marshal = marshal
}
}
// NewItem creates and configure new item.
func NewItem(key, value interface{}, opts ...Option) *Item {
item := &Item{
Key: Key{
Key: key,
Prefix: "",
Separator: "",
},
Value: value,
TTL: 0,
unmarshal: json.Unmarshal,
marshal: json.Marshal,
}
for _, opt := range opts {
opt(item)
}
return item
}
// Item to pass to the provider.
type Item struct {
Key Key
Value interface{}
TTL time.Duration
unmarshal encoding.Unmarshal
marshal encoding.Marshal
}
func (i *Item) With(key, val interface{}, opts ...Option) *Item {
return NewItem(key, val, append(i.Options(), opts...)...)
}
// IsExpired checks expired item.
func (i *Item) IsExpired() bool {
return i.TTL < 0
}
func (i *Item) Marshal() ([]byte, error) {
return i.marshal(i.Value)
}
func (i *Item) Unmarshal(data []byte) error {
return i.unmarshal(data, i.Value)
}
// Options gets item options.
func (i *Item) Options() []Option {
opts := []Option{WithTTL(i.TTL), WithMarshal(i.unmarshal, i.marshal)}
if i.Key.Prefix != "" {
opts = append(opts, WithNamespace(i.Key.Prefix, i.Key.Separator))
}
return opts
}
// TTLInSecond to set the ttl in seconds.
func (i *Item) TTLInSecond(in int64) {
i.TTL = time.Second * time.Duration(in)
}
// Expired get the time when the ttl is outdated.
func (i *Item) Expired() time.Time {
return time.Now().Add(i.TTL)
}
// Key with prefix and separator.
type Key struct {
Key interface{}
Prefix string
Separator string
}
func (k Key) Value() interface{} {
if v, ok := k.Key.(interface{ Value() interface{} }); ok {
return v.Value()
}
return k.Key
}
// String returns a formatted key.
func (k Key) String() string {
if k.Prefix != "" {
return fmt.Sprint(k.Prefix, k.Separator, k.Key)
}
switch v := k.Key.(type) {
case int:
return strconv.Itoa(v)
case int32:
return strconv.FormatInt(int64(v), 10)
case int64:
return strconv.FormatInt(v, 10)
case uint:
return strconv.FormatUint(uint64(v), 10)
case uint32:
return strconv.FormatUint(uint64(v), 10)
case uint64:
return strconv.FormatUint(v, 10)
case string:
return v
default:
return fmt.Sprint(v)
}
}