func (s *Store) Import(rawmessage json.RawMessage, opts ImportOpts) error {
	var sjson StoreJSON
	if err := json.Unmarshal(rawmessage, &sjson); err != nil {
		return err
	}
	s.mu.Lock()
	for k := range sjson {
		if err := s.keyExists(k); err != nil {
			if !opts.AddKeys && !opts.ErrOnInvalidKey {
				continue
			}
			if !opts.AddKeys && opts.ErrOnInvalidKey {
				s.mu.Unlock()
				return err
			}
			if opts.AddKeys {
				if er := s.AddKey(k, ValueType(sjson[k].Type)); er != nil {
					s.mu.Unlock()
					return er
				}
			}
		}
		v := s.kv[k]
		v.mu.Lock()
		if sjson[k].Type != string(v.val.Type()) {
			if !opts.UpdateTypes {
				v.mu.Unlock()
				s.mu.Unlock()
				return fmt.Errorf("value type in JSON and store schema do not match")
			}
			if er := s.UpdateKey(k, ValueType(sjson[k].Type)); er != nil {
				v.mu.Unlock()
				s.mu.Unlock()
				return er
			}
		}
		if err := s.FromJSON(k, sjson[k].Data); err != nil {
			v.mu.Unlock()
			s.mu.Unlock()
			return err
		}
		v.mu.Unlock()
	}
	s.mu.Unlock()
	return nil
}
Import loads store from the data.

The default behavior is that the store takes the data from the JSON and
if an unknown key exists, i.e., a key that is not already added to the
store, it silently skips the value associated with it. This can be
configured using the ImportOpts.

The data is in the format (StoreJSON):

{
"key_1": {
"type": "str",
"data": "hello"
},
"key_2": {
"type": "hash",
"data": {
"a": "b",
"c": "d"
}
}
}
package kiwi
import (
	"encoding/json"
	"fmt"
	"strings"
	"sync"
)
var (
	ErrKeyExists   = fmt.Errorf("key already exists")
	ErrKeyNotExist = fmt.Errorf("key does not exist")
)
func newKeyErr(err error, key string) error {
	return fmt.Errorf("%w: %s", err, key)
}
type Store struct {
	kv map[string]valWrapper
	mu sync.RWMutex
}
func NewStore() *Store {
	return &Store{
		kv: make(map[string]valWrapper),
		mu: sync.RWMutex{},
	}
}
func NewStoreFromSchema(schema Schema) (*Store, error) {
	s := NewStore()
	for key, val := range schema {
		if err := s.AddKey(key, val); err != nil {
			return nil, err
		}
	}
	return s, nil
}
func (s *Store) KeyExists(key string) bool {
	s.mu.RLock()
	exists := s.keyExists(key) == nil
	s.mu.RUnlock()
	return exists
}
func (s *Store) AddKey(key string, typ ValueType) error {
	s.mu.Lock()
	if err := s.keyNotExist(key); err != nil {
		s.mu.Unlock()
		return err
	}
	v, err := newValue(typ)
	if err != nil {
		s.mu.Unlock()
		return err
	}
	s.setValWrapper(key, v)
	s.mu.Unlock()
	return nil
}
func (s *Store) UpdateKey(key string, typ ValueType) error {
	s.mu.Lock()
	if err := s.keyExists(key); err != nil {
		s.mu.Unlock()
		return err
	}
	v, err := newValue(typ)
	if err != nil {
		s.mu.Unlock()
		return err
	}
	old := s.kv[key]
	old.mu.Lock()
	s.setValWrapper(key, v)
	old.mu.Unlock()
	s.mu.Unlock()
	return nil
}
func (s *Store) setValWrapper(key string, val Value) {
	s.kv[key] = valWrapper{
		val:         val,
		mu:          &sync.RWMutex{},
		doMapCached: val.DoMap(),
	}
}
func (s *Store) DeleteKey(key string) error {
	s.mu.Lock()
	if err := s.keyExists(key); err != nil {
		s.mu.Unlock()
		return err
	}
	old := s.kv[key]
	old.mu.Lock()
	delete(s.kv, key)
	old.mu.Unlock()
	s.mu.Unlock()
	return nil
}
func (s *Store) GetValueType(key string) (ValueType, error) {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return "", err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	v.mu.RLock()
	typ := v.val.Type()
	v.mu.RUnlock()
	return typ, nil
}
func (s *Store) GetSchema() Schema {
	s.mu.RLock()
	schema := s.getSchema()
	s.mu.RUnlock()
	return schema
}
func (s *Store) getSchema() Schema {
	schema := make(Schema)
	for k := range s.kv {
		schema[k] = s.kv[k].val.Type()
	}
	return schema
}
func (s *Store) Do(key string, action Action, params ...interface{}) (interface{}, error) {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return nil, err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	doFunc, ok := v.doMapCached[action]
	if !ok {
		return nil, fmt.Errorf("%w: %v", ErrInvalidAction, action)
	}
	v.mu.Lock()
	res, err := doFunc(params...)
	v.mu.Unlock()
	return res, err
}
func (s *Store) ToJSON(key string) (json.RawMessage, error) {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return nil, err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	v.mu.RLock()
	jsonval, err := s.toJSON(&v)
	v.mu.RUnlock()
	return jsonval, err
}
func (s *Store) toJSON(v *valWrapper) (json.RawMessage, error) {
	res, err := v.val.ToJSON()
	if err != nil {
		return nil, fmt.Errorf("error in ToJSON: %v", err)
	}
	return res, nil
}
func (s *Store) FromJSON(key string, rawmessage json.RawMessage) error {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	v.mu.Lock()
	err := s.fromJSON(&v, rawmessage)
	v.mu.Unlock()
	return err
}
func (s *Store) fromJSON(v *valWrapper, rawmessage json.RawMessage) error {
	if err := v.val.FromJSON(rawmessage); err != nil {
		return fmt.Errorf("error in FromJSON: %v", err)
	}
	return nil
}
type ValJSON struct {
	Type string          `json:"type"`
	Data json.RawMessage `json:"data"`
}
type StoreJSON = map[string]ValJSON
func (s *Store) Export() (json.RawMessage, error) {
	s.mu.RLock()
	schema := s.getSchema()
	sjson := make(StoreJSON, len(schema))
	for k, v := range schema {
		vw := s.kv[k]
		vw.mu.RLock()
		data, err := s.toJSON(&vw)
		vw.mu.Unlock()
		if err != nil {
			s.mu.RUnlock()
			return nil, fmt.Errorf("error exporting for %q key: %v", k, err)
		}
		sjson[k] = ValJSON{
			Type: string(v),
			Data: data,
		}
	}
	s.mu.RUnlock()
	c, err := json.Marshal(sjson)
	if err != nil {
		return nil, err
	}
	return c, nil
}
type ImportOpts struct {
	AddKeys bool
	UpdateTypes bool
	ErrOnInvalidKey bool
}