src.dualinventive.com/go/lib/kv/ramkv/ramkv.go

179 lines
3.6 KiB
Go

package ramkv
import (
"encoding/json"
"errors"
"sync"
"time"
"src.dualinventive.com/go/lib/kv/rediskv"
)
// ErrNotFound is returned when a value is not found
var ErrNotFound = rediskv.ErrNotFound
// Ramkv stores the values that is set or retrieved in RAM
type Ramkv struct {
lock sync.RWMutex
storage map[string]map[string]string
}
// New creates a Ram key value instance
func New() (*Ramkv, error) {
return &Ramkv{
storage: make(map[string]map[string]string),
}, nil
}
// Close closes the RAM KV
func (r *Ramkv) Close() error {
return nil
}
// Get returns the value from the requested key.
func (r *Ramkv) Get(key string) (string, error) {
r.lock.RLock()
value, found := r.storage[key]
r.lock.RUnlock()
if found && value != nil {
value, err := json.Marshal(value)
if err != nil {
return "", err
}
return string(value), nil
}
return "", ErrNotFound
}
// Set stores the value with the given key
func (r *Ramkv) Set(key string, value interface{}) error {
r.lock.Lock()
if r.storage[key] == nil {
r.storage[key] = make(map[string]string)
}
r.lock.Unlock()
if strValue, ok := value.(string); ok {
var jsonValue map[string]string
err := json.Unmarshal([]byte(strValue), &jsonValue)
if err != nil {
return err
}
r.lock.Lock()
r.storage[key] = jsonValue
r.lock.Unlock()
}
return nil
}
// SetExp stores the value with the given key with expiration, not implemented for now
func (r *Ramkv) SetExp(key string, value interface{}, expiration time.Duration) error {
return errors.New("not implemented")
}
//Exists return whether the key is existing or not
func (r *Ramkv) Exists(key string) (bool, error) {
_, ok := r.storage[key]
return ok, nil
}
// Del removes the value with the given key
func (r *Ramkv) Del(key string) (bool, error) {
r.lock.Lock()
_, ok := r.storage[key]
delete(r.storage, key)
r.lock.Unlock()
return ok, nil
}
// Keys returns a list of all keys, pattern is ignored
func (r *Ramkv) Keys(pattern string) ([]string, error) { //nolint: unparam
var keys []string
r.lock.RLock()
for k := range r.storage {
keys = append(keys, k)
}
r.lock.RUnlock()
return keys, nil
}
// HKeys returns all keys in a hash
func (r *Ramkv) HKeys(key string) ([]string, error) {
var keys []string
r.lock.RLock()
s, ok := r.storage[key]
r.lock.RUnlock()
if !ok {
return nil, ErrNotFound
}
for k := range s {
keys = append(keys, k)
}
return keys, nil
}
// HGetAll returns all key-values in a hash as a map
func (r *Ramkv) HGetAll(key string) (map[string]string, error) {
r.lock.RLock()
s, ok := r.storage[key]
r.lock.RUnlock()
if !ok {
return nil, ErrNotFound
}
return s, nil
}
// HGet retrieve the value from the given field in the given key
func (r *Ramkv) HGet(key, field string) (string, error) {
r.lock.RLock()
if r.storage[key] == nil {
r.lock.RUnlock()
return "", ErrNotFound
}
value, found := r.storage[key][field]
r.lock.RUnlock()
if found {
return value, nil
}
return "", ErrNotFound
}
// HSet sets the value in the given field in the given key
func (r *Ramkv) HSet(key, field string, value interface{}) error {
r.lock.Lock()
if r.storage[key] == nil {
r.storage[key] = make(map[string]string)
}
if s, ok := value.(string); ok {
r.storage[key][field] = s
r.lock.Unlock()
return nil
}
ret, err := json.Marshal(value)
if err != nil {
r.lock.Unlock()
return err
}
r.storage[key][field] = string(ret)
r.lock.Unlock()
return nil
}
// HDel removes the value in the given field in the given key
func (r *Ramkv) HDel(key, field string) error {
r.lock.Lock()
if r.storage[key] != nil {
delete(r.storage[key], field)
}
r.lock.Unlock()
return nil
}