Skip to content

Commit 71c1ec1

Browse files
committed
feat: Add Incr and Decr convenience methods for numeric cache operations.
1 parent 16e4774 commit 71c1ec1

4 files changed

Lines changed: 146 additions & 0 deletions

File tree

cache.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,18 @@ func (c *NumericCache[N]) ModifyNumeric(k string, operand N, isIncrement bool) (
437437
return newVal, nil
438438
}
439439

440+
// Incr increments a numeric item in the cache by the specified operand.
441+
// This is a convenience method that calls ModifyNumeric with isIncrement=true.
442+
func (c *NumericCache[N]) Incr(k string, operand N) (N, error) {
443+
return c.ModifyNumeric(k, operand, true)
444+
}
445+
446+
// Decr decrements a numeric item in the cache by the specified operand.
447+
// This is a convenience method that calls ModifyNumeric with isIncrement=false.
448+
func (c *NumericCache[N]) Decr(k string, operand N) (N, error) {
449+
return c.ModifyNumeric(k, operand, false)
450+
}
451+
440452
// Delete an item from the cache. Does nothing if the key is not in the cache.
441453
func (c *cache[V]) Delete(k string) {
442454
c.mu.Lock()

cache_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,67 @@ func TestModifyNumericTypeMismatch(t *testing.T) {
423423
t.Log("Skipping direct type mismatch test for ModifyNumeric on NumericCache[N] as it implies cache stores N.")
424424
}
425425

426+
func TestIncrDecr(t *testing.T) {
427+
nc := newNumericTestCache[int](t, DefaultExpiration, 0)
428+
nc.Set("val", 10, DefaultExpiration)
429+
430+
// Test Incr
431+
newVal, err := nc.Incr("val", 5)
432+
if err != nil {
433+
t.Fatalf("Incr failed: %v", err)
434+
}
435+
if newVal != 15 {
436+
t.Errorf("Expected 15 after Incr, got %d", newVal)
437+
}
438+
439+
// Test Decr
440+
newVal, err = nc.Decr("val", 3)
441+
if err != nil {
442+
t.Fatalf("Decr failed: %v", err)
443+
}
444+
if newVal != 12 {
445+
t.Errorf("Expected 12 after Decr, got %d", newVal)
446+
}
447+
}
448+
449+
func TestIncrOverflow(t *testing.T) {
450+
nc := newNumericTestCache[int8](t, DefaultExpiration, 0)
451+
nc.Set("int8", int8(127), DefaultExpiration)
452+
453+
newVal, err := nc.Incr("int8", 1)
454+
if err != nil {
455+
t.Fatalf("Incr failed: %v", err)
456+
}
457+
if newVal != -128 {
458+
t.Errorf("Expected -128 after overflow, got %d", newVal)
459+
}
460+
}
461+
462+
func TestDecrUnderflow(t *testing.T) {
463+
nc := newNumericTestCache[uint8](t, DefaultExpiration, 0)
464+
nc.Set("uint8", uint8(0), DefaultExpiration)
465+
466+
newVal, err := nc.Decr("uint8", 1)
467+
if err != nil {
468+
t.Fatalf("Decr failed: %v", err)
469+
}
470+
if newVal != 255 {
471+
t.Errorf("Expected 255 after underflow, got %d", newVal)
472+
}
473+
}
474+
475+
func TestIncrWithoutSet(t *testing.T) {
476+
nc := newNumericTestCache[int](t, DefaultExpiration, 0)
477+
478+
newVal, err := nc.Incr("newval", 5)
479+
if err != nil {
480+
t.Fatalf("Incr failed: %v", err)
481+
}
482+
if newVal != 5 {
483+
t.Errorf("Expected 5 after Incr on empty key, got %d", newVal)
484+
}
485+
}
486+
426487
// --- End of ModifyNumeric Tests ---
427488

428489
func TestAdd(t *testing.T) {

sharded.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,18 @@ func (sc *ShardedNumericCache[N]) ModifyNumeric(k string, operand N, isIncrement
236236
return nc.ModifyNumeric(k, operand, isIncrement)
237237
}
238238

239+
// Incr increments a numeric item in the cache by the specified operand.
240+
// This is a convenience method that calls ModifyNumeric with isIncrement=true.
241+
func (sc *ShardedNumericCache[N]) Incr(k string, operand N) (N, error) {
242+
return sc.ModifyNumeric(k, operand, true)
243+
}
244+
245+
// Decr decrements a numeric item in the cache by the specified operand.
246+
// This is a convenience method that calls ModifyNumeric with isIncrement=false.
247+
func (sc *ShardedNumericCache[N]) Decr(k string, operand N) (N, error) {
248+
return sc.ModifyNumeric(k, operand, false)
249+
}
250+
239251
// Helper function to create a new ShardedNumericCache
240252
func NewShardedNumeric[N Number](shards int, defaultExpiration, cleanupInterval time.Duration) *ShardedNumericCache[N] {
241253
// Create the underlying shardedCache

sharded_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,67 @@ func TestShardedModifyNumeric(t *testing.T) {
128128
}
129129
}
130130

131+
func TestShardedIncrDecr(t *testing.T) {
132+
snc := NewShardedNumeric[int](5, DefaultExpiration, 0)
133+
snc.Set("val", 10, DefaultExpiration)
134+
135+
// Test Incr
136+
newVal, err := snc.Incr("val", 5)
137+
if err != nil {
138+
t.Fatalf("Incr failed: %v", err)
139+
}
140+
if newVal != 15 {
141+
t.Errorf("Expected 15 after Incr, got %d", newVal)
142+
}
143+
144+
// Test Decr
145+
newVal, err = snc.Decr("val", 3)
146+
if err != nil {
147+
t.Fatalf("Decr failed: %v", err)
148+
}
149+
if newVal != 12 {
150+
t.Errorf("Expected 12 after Decr, got %d", newVal)
151+
}
152+
}
153+
154+
func TestShardedIncrOverflow(t *testing.T) {
155+
snc := NewShardedNumeric[int8](5, DefaultExpiration, 0)
156+
snc.Set("int8", int8(127), DefaultExpiration)
157+
158+
newVal, err := snc.Incr("int8", 1)
159+
if err != nil {
160+
t.Fatalf("Incr failed: %v", err)
161+
}
162+
if newVal != -128 {
163+
t.Errorf("Expected -128 after overflow, got %d", newVal)
164+
}
165+
}
166+
167+
func TestShardedDecrUnderflow(t *testing.T) {
168+
snc := NewShardedNumeric[uint8](5, DefaultExpiration, 0)
169+
snc.Set("uint8", uint8(0), DefaultExpiration)
170+
171+
newVal, err := snc.Decr("uint8", 1)
172+
if err != nil {
173+
t.Fatalf("Decr failed: %v", err)
174+
}
175+
if newVal != 255 {
176+
t.Errorf("Expected 255 after underflow, got %d", newVal)
177+
}
178+
}
179+
180+
func TestShardedIncrWithoutSet(t *testing.T) {
181+
snc := NewShardedNumeric[int](5, DefaultExpiration, 0)
182+
183+
newVal, err := snc.Incr("newval", 5)
184+
if err != nil {
185+
t.Fatalf("Incr failed: %v", err)
186+
}
187+
if newVal != 5 {
188+
t.Errorf("Expected 5 after Incr on empty key, got %d", newVal)
189+
}
190+
}
191+
131192
func BenchmarkShardedCacheGetExpiring(b *testing.B) {
132193
benchmarkShardedCacheGet(b, 5*time.Minute)
133194
}

0 commit comments

Comments
 (0)