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 }