Skip to content

Commit bec8daf

Browse files
committed
[cache] fix typed value unmarshaling
1 parent eef9522 commit bec8daf

File tree

3 files changed

+35
-20
lines changed

3 files changed

+35
-20
lines changed

pkg/cache/memory.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type memoryItem struct {
2727
validUntil time.Time
2828
}
2929

30-
func newItem(value []byte, opts options) *memoryItem {
30+
func newMemoryItem(value []byte, opts options) *memoryItem {
3131
item := &memoryItem{
3232
value: value,
3333
validUntil: opts.validUntil,
@@ -152,7 +152,7 @@ func (m *memoryCache) newItem(value []byte, opts ...Option) *memoryItem {
152152
}
153153
o.apply(opts...)
154154

155-
return newItem(value, o)
155+
return newMemoryItem(value, o)
156156
}
157157

158158
func (m *memoryCache) getItem(getter func() (*memoryItem, bool)) (*memoryItem, error) {

pkg/cache/redis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ if deleteFlag then
3737
end
3838
3939
if ttlTs > 0 then
40-
redis.call('HExpireAt', KEYS[1], ttlTs, field)
40+
redis.call('HExpireAt', KEYS[1], ttlTs, 'FIELDS', '1', field)
4141
elseif ttlDelta > 0 then
4242
local ttl = redis.call('HTTL', KEYS[1], field)
4343
local newTtl = ttl + ttlDelta

pkg/cache/typed.go

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cache
33
import (
44
"context"
55
"fmt"
6+
"reflect"
67
)
78

89
type Item interface {
@@ -40,30 +41,24 @@ func (c *Typed[T]) SetOrFail(ctx context.Context, key string, value T, opts ...O
4041

4142
func (c *Typed[T]) Get(ctx context.Context, key string, opts ...GetOption) (T, error) {
4243
data, err := c.storage.Get(ctx, key, opts...)
44+
var zero T
4345
if err != nil {
44-
return *new(T), fmt.Errorf("failed to get value from cache: %w", err)
46+
return zero, fmt.Errorf("failed to get value from cache: %w", err)
4547
}
4648

47-
var value T
49+
value, err := newItem[T]()
50+
if err != nil {
51+
return zero, err
52+
}
4853
if err := value.Unmarshal(data); err != nil {
49-
return *new(T), fmt.Errorf("failed to unmarshal value from cache: %w", err)
54+
return zero, fmt.Errorf("failed to unmarshal value from cache: %w", err)
5055
}
5156

5257
return value, nil
5358
}
5459

5560
func (c *Typed[T]) GetAndDelete(ctx context.Context, key string) (T, error) {
56-
data, err := c.storage.GetAndDelete(ctx, key)
57-
if err != nil {
58-
return *new(T), fmt.Errorf("failed to get value from cache: %w", err)
59-
}
60-
61-
var value T
62-
if err := value.Unmarshal(data); err != nil {
63-
return *new(T), fmt.Errorf("failed to unmarshal value from cache: %w", err)
64-
}
65-
66-
return value, nil
61+
return c.Get(ctx, key, AndDelete())
6762
}
6863

6964
func (c *Typed[T]) Delete(ctx context.Context, key string) error {
@@ -81,9 +76,12 @@ func (c *Typed[T]) Drain(ctx context.Context) (map[string]T, error) {
8176
}
8277

8378
items := make(map[string]T, len(data))
84-
for key, value := range data {
85-
var item T
86-
if err := item.Unmarshal(value); err != nil {
79+
for key, raw := range data {
80+
item, err := newItem[T]()
81+
if err != nil {
82+
return nil, err
83+
}
84+
if err := item.Unmarshal(raw); err != nil {
8785
return nil, fmt.Errorf("failed to unmarshal value from cache: %w", err)
8886
}
8987

@@ -96,3 +94,20 @@ func (c *Typed[T]) Drain(ctx context.Context) (map[string]T, error) {
9694
func (c *Typed[T]) Close() error {
9795
return c.storage.Close()
9896
}
97+
98+
func newItem[T Item]() (T, error) {
99+
var zero T
100+
101+
t := reflect.TypeOf((*T)(nil)).Elem()
102+
if t.Kind() != reflect.Ptr {
103+
return zero, fmt.Errorf("cache: type %s must be a pointer", t.String())
104+
}
105+
106+
v := reflect.New(t.Elem())
107+
item, ok := v.Interface().(T)
108+
if !ok {
109+
return zero, fmt.Errorf("cache: cannot create value of type %s", t.String())
110+
}
111+
112+
return item, nil
113+
}

0 commit comments

Comments
 (0)