summaryrefslogtreecommitdiffstats
path: root/cache
diff options
context:
space:
mode:
authorsiddharth ravikumar <s@ricketyspace.net>2022-06-06 19:03:08 -0400
committersiddharth ravikumar <s@ricketyspace.net>2022-06-06 19:03:29 -0400
commit0c6d8c7fa966ab548a1f25c1c85d45e22eb44770 (patch)
tree2c8edbb1abeb136f802a12eecd3d5322cde94226 /cache
parentfb09c968ee49e2257bcb4edbf954548d5f08ba16 (diff)
add `cache` package
A simple key-value store.
Diffstat (limited to 'cache')
-rw-r--r--cache/cache.go54
-rw-r--r--cache/cache_test.go72
2 files changed, 126 insertions, 0 deletions
diff --git a/cache/cache.go b/cache/cache.go
new file mode 100644
index 0000000..fbc763e
--- /dev/null
+++ b/cache/cache.go
@@ -0,0 +1,54 @@
+// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net>
+// SPDX-License-Identifier: ISC
+
+// A simple in-memory cache store.
+package cache
+
+import "time"
+
+// An item in the key-value cache store.
+type item struct {
+ value string
+ expires time.Time // Time when the key-value expires
+}
+
+// A key-value cache store.
+type Cache struct {
+ store map[string]item
+}
+
+// Returns a new empty cache store.
+func NewCache() *Cache {
+ c := new(Cache)
+ c.store = make(map[string]item)
+ return c
+}
+
+// Set the (key,value) item to the cache store. This item will be
+// considered expired after time `expires`.
+//
+// Cache.Get will return an empty string once `expires` is past the
+// current time.
+func (c *Cache) Set(key, value string, expires time.Time) {
+ c.store[key] = item{
+ value: value,
+ expires: expires,
+ }
+}
+
+// Get an (key,value) item from the cache store by key.
+//
+// An empty string will be returned when if the key does not exist or
+// if the item corresponding to the key has expired. An expired
+// (key,value) item will be removed from the cache store.
+func (c *Cache) Get(key string) string {
+ if _, ok := c.store[key]; !ok {
+ return ""
+ }
+ // Check if the item expired.
+ if time.Until(c.store[key].expires).Seconds() < 0 {
+ delete(c.store, key)
+ return ""
+ }
+ return c.store[key].value
+}
diff --git a/cache/cache_test.go b/cache/cache_test.go
new file mode 100644
index 0000000..41e0d25
--- /dev/null
+++ b/cache/cache_test.go
@@ -0,0 +1,72 @@
+// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net>
+// SPDX-License-Identifier: ISC
+
+package cache
+
+import (
+ "testing"
+ "time"
+)
+
+func TestNewCache(t *testing.T) {
+ c := NewCache()
+ if c == nil {
+ t.Errorf("cache is nil")
+ return
+ }
+ if c.store == nil {
+ t.Errorf("cache.store is nil")
+ return
+ }
+ // Try manually adding an item.
+ c.store["foo"] = item{
+ value: "bar",
+ expires: time.Now().Add(time.Second * 10),
+ }
+ if c.store["foo"].value != "bar" {
+ t.Errorf("cache.store['foo'] is not bar")
+ return
+ }
+}
+
+func TestCacheSet(t *testing.T) {
+ c := NewCache()
+ if c == nil {
+ t.Errorf("cache is nil")
+ return
+ }
+ exp := time.Now().Add(time.Second * 10)
+ c.Set("foo", "bar", exp)
+ if c.store["foo"].value != "bar" {
+ t.Errorf("cache.store['foo'] is not bar")
+ return
+ }
+ if c.store["foo"].expires.Unix() != exp.Unix() {
+ t.Errorf("cache.store['foo'].expires no set correctly")
+ return
+ }
+}
+
+func TestCacheGet(t *testing.T) {
+ c := NewCache()
+ if c == nil {
+ t.Errorf("cache is nil")
+ return
+ }
+
+ // Test 1
+ exp := time.Now().Add(time.Second * 10)
+ c.Set("foo", "bar", exp)
+ if c.Get("foo") != "bar" {
+ t.Errorf("cache.Get(foo) is not bar")
+ return
+ }
+
+ // Test 2
+ exp = time.Now().Add(time.Second * -10)
+ c.Set("sna", "fu", exp)
+ if c.Get("sna") != "" {
+ t.Errorf("cache.Get(sna) is not empty: %s", c.Get("sna"))
+ return
+ }
+}