README

Kiwi Logo

A minimalistic in-memory key value store.

Go CI Docs CI Docs CD PkgGoDev

Overview

You can think of Kiwi as thread safe global variables. This kind of library comes in helpful when you need to manage state accross your application which can be mutated with multiple threads. Kiwi protects your keys with mutex locks so you don't have to.

Head over to kiwi.sdslabs.co for more details and documentation.

Installation

Kiwi requires Go >= 1.14

Kiwi can be integrated with your application just like any other go library.

go get -u github.com/sdslabs/kiwi

Now you can import kiwi any where in your code.

import "github.com/sdslabs/kiwi"

Basic usage

Create a store, add key and play with it. It's that easy!

store := stdkiwi.NewStore()

if err := store.AddKey("my_string", "str"); err != nil {
  // handle error
}

myString := store.Str("my_string")

if err := myString.Update("Hello, World!"); err != nil {
  // handle error
}

str, err := myString.Get()
if err != nil {
  // handle error
}

fmt.Println(str) // Hello, World!

Check out the tutorial to learn how to use Kiwi.

Benchmarks

Following are the benchmarks comparing Kiwi with BuntDB on a MacBook Pro (8th gen Intel i5 2.4GHz processor, 8GB RAM).

❯ go test -bench=. -test.benchmem ./benchmark
goos: darwin
goarch: amd64
pkg: github.com/sdslabs/kiwi/benchmark
BenchmarkBuntDB_Update-8        11777931                96.6 ns/op            48 B/op          1 allocs/op
BenchmarkBuntDB_View-8          23310963                47.1 ns/op            48 B/op          1 allocs/op
BenchmarkKiwi_Update-8          10356004               115 ns/op              48 B/op          3 allocs/op
BenchmarkKiwi_Get-8             21910110                53.2 ns/op             0 B/op          0 allocs/op
PASS
ok      github.com/sdslabs/kiwi/benchmark       6.216s

Following are the key differences due to which Kiwi is a little slow:

  1. BuntDB supports transactions, i.e., it locks the database once to apply all the operations (and this is what is tested).
  2. Kiwi supports dynamic data-types, which means, allocation on heap at runtime (interface{}) whereas BuntDB is statically typed.

The above two differences are what makes Kiwi unique and suitable to use on many occasions. Due to the aforementioned reasons, Kiwi can support typed values and not everything is just another "string".

There are places where we could improve more. Some performance issues also lie in the implementation of values. For example, when updating a string, not returning the updated string avoids an extra allocation.

Contributing

We are always open for contributions. If you find any feature missing, or just want to report a bug, feel free to open an issue and/or submit a pull request regarding the same.

For more information on contribution, check out our docs.

Contact

If you have a query regarding the product or just want to say hello then feel free to visit chat.sdslabs.co or drop a mail at contact@sdslabs.co.in


Made by SDSLabs

Expand ▾ Collapse ▴

Documentation

Overview

Package kiwi implements a minimalistic in-memory key value store.

Each key is thread safe as it is protected by its own mutex, though different keys can be accessed by various threads.

To get started, create a store with the NewStore function and add keys to it using AddKey. Each key is associated with a value which has a specific type. These types are extendible and can be created by implementing the Value interface.

Store can also be initialized with a schema, which is basically a map of keys and value types.

Get Started

Create a store, add key and play with it. It's that easy!

store := kiwi.NewStore()

if err := store.AddKey("my_string", "str"); err != nil {
  // handle error
}

if _, err := store.Do("my_string", "UPDATE", "Hello, World!"); err != nil {
  // handle error
}

v, err := store.Do("my_string", "GET")
if err != nil {
  // handle error
}

fmt.Println(v.(string)) // Hello, World!

For documentation visit https://kiwi.sdslabs.co/docs/

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrKeyExists   = fmt.Errorf("key already exists")
	ErrKeyNotExist = fmt.Errorf("key does not exist")
)

    Various errors related to keys.

    View Source
    var (
    	ErrValueRegistered    = fmt.Errorf("value already registered")
    	ErrValueNotRegistered = fmt.Errorf("value not registered")
    )

      Errors related to values.

      View Source
      var (
      	ErrInvalidAction = fmt.Errorf("invalid action")
      )

        Errors related to actions.

        Functions

        func ListRegisteredValues

        func ListRegisteredValues() []string

          ListRegisteredValues lists all the values registered with the package.

          func RegisterValue

          func RegisterValue(newFn func() Value)

            RegisterValue registers a new value type with the package.

            It takes in two params: the type of the value and a function to create a new value.

            Types

            type Action

            type Action string

              Action is required to invoke (or "Do") an action.

              type DoFunc

              type DoFunc func(params ...interface{}) (interface{}, error)

                DoFunc is a function that can be executed when an action is invoked.

                type ImportOpts

                type ImportOpts struct {
                	// AddKeys specifies whether to add keys that do not exist.
                	AddKeys bool
                
                	// UpdateTypes specifies if the type of key in JSON doesn't match the one
                	// with already-defined key, should the type of key be updated or not.
                	UpdateTypes bool
                
                	// ErrOnInvalidKey specifies whether to throw error if the key in the JSON
                	// does not exist in the actual schema of the Store.
                	// This option is considered only when `AddKeys` is false.
                	ErrOnInvalidKey bool
                }

                  ImportOpts are the options that can be used to configure how to import data into the store from raw JSON.

                  type Schema

                  type Schema map[string]ValueType

                    Schema contains the value types corresponding to their keys.

                    func (Schema) String

                    func (s Schema) String() string

                      String implements the fmt.Stringer interface.

                      type Store

                      type Store struct {
                      	// contains filtered or unexported fields
                      }

                        Store is the main element that contains and manages all the key value pairs.

                        func NewStore

                        func NewStore() *Store

                          NewStore creates an empty store without any key value pairs initialized.

                          func NewStoreFromSchema

                          func NewStoreFromSchema(schema Schema) (*Store, error)

                            NewStoreFromSchema creates a new store from the provided schema.

                            func (*Store) AddKey

                            func (s *Store) AddKey(key string, typ ValueType) error

                              AddKey adds a new key to the store. It throws an error if the key already exists.

                              func (*Store) DeleteKey

                              func (s *Store) DeleteKey(key string) error

                                DeleteKey deletes the key if it exists. Throws an error if it doesn't.

                                func (*Store) Do

                                func (s *Store) Do(key string, action Action, params ...interface{}) (interface{}, error)

                                  Do executes the action for the value associated with the key.

                                  func (*Store) Export

                                  func (s *Store) Export() (json.RawMessage, error)

                                    Export returns JSON data for the store.

                                    The data is in the format (StoreJSON):

                                    {
                                    	"key_1": {
                                    		"type": "str",
                                    		"data": "hello"
                                    	},
                                    	"key_2": {
                                    		"type": "hash",
                                    		"data": {
                                    			"a": "b",
                                    			"c": "d"
                                    		}
                                    	}
                                    }
                                    

                                    func (*Store) FromJSON

                                    func (s *Store) FromJSON(key string, rawmessage json.RawMessage) error

                                      FromJSON takes the raw JSON form of data and loads it into the value.

                                      func (*Store) GetSchema

                                      func (s *Store) GetSchema() Schema

                                        GetSchema returns the schema of the store.

                                        func (*Store) GetValueType

                                        func (s *Store) GetValueType(key string) (ValueType, error)

                                          GetValueType returns the type of value corresponding to the key.

                                          func (*Store) Import

                                          func (s *Store) Import(rawmessage json.RawMessage, opts ImportOpts) error

                                            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"
                                            		}
                                            	}
                                            }
                                            

                                            func (*Store) KeyExists

                                            func (s *Store) KeyExists(key string) bool

                                              KeyExists tells if the key exists or not.

                                              func (*Store) ToJSON

                                              func (s *Store) ToJSON(key string) (json.RawMessage, error)

                                                ToJSON converts the data associated with the value into JSON format.

                                                func (*Store) UpdateKey

                                                func (s *Store) UpdateKey(key string, typ ValueType) error

                                                  UpdateKey updates the key if it exists. Throws an error if it doesn't.

                                                  type StoreJSON

                                                  type StoreJSON = map[string]ValJSON

                                                    StoreJSON is the type which includes all the data for the store.

                                                    type ValJSON

                                                    type ValJSON struct {
                                                    	Type string          `json:"type"`
                                                    	Data json.RawMessage `json:"data"`
                                                    }

                                                      ValJSON is the JSON object for each value.

                                                      type Value

                                                      type Value interface {
                                                      	// Type returns the type of the value.
                                                      	Type() ValueType
                                                      
                                                      	// DoMap returns a map which associates actions with a do function.
                                                      	DoMap() map[Action]DoFunc
                                                      
                                                      	// ToJSON returns a raw byte array of the data.
                                                      	ToJSON() (json.RawMessage, error)
                                                      
                                                      	// FromJSON returns the data in golang from a raw byte array.
                                                      	FromJSON(json.RawMessage) error
                                                      }

                                                        Value is something that can be associated with a "key".

                                                        A value implements its own methods and can be accessed by type assertion. To add a value type to the register simply call RegisterValue. All the default values are already registered with the package.

                                                        type ValueType

                                                        type ValueType string

                                                          ValueType is the name of type of value.

                                                          Directories

                                                          Path Synopsis
                                                          Package stdkiwi implements an API with standard values.
                                                          Package stdkiwi implements an API with standard values.
                                                          values
                                                          hash
                                                          Package hash implements a kiwi.Value which can store a string-string hashmap.
                                                          Package hash implements a kiwi.Value which can store a string-string hashmap.
                                                          list
                                                          Package list implements a kiwi.Value which can store an array of strings.
                                                          Package list implements a kiwi.Value which can store an array of strings.
                                                          set
                                                          Package set implements a kiwi.Value which can store a set of strings.
                                                          Package set implements a kiwi.Value which can store a set of strings.
                                                          str
                                                          Package str implements a kiwi.Value which can store a simple string.
                                                          Package str implements a kiwi.Value which can store a simple string.
                                                          zhash
                                                          Package zhash implements a kiwi.Value which can store a hash with each element having a value and a score.
                                                          Package zhash implements a kiwi.Value which can store a hash with each element having a value and a score.
                                                          zset
                                                          Package zset implements a kiwi.Value which can store a set with each element having score.
                                                          Package zset implements a kiwi.Value which can store a set with each element having score.