Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

cabol/kvx

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KVX Build Status

This is a simple/basic in-memory Key/Value Store written in Elixir and using ExShards as default adapter.

Again, KVX is a simple library, most of the work is done by ExShards, and its typical use case might be as a Cache.

Usage

Add kvx to your Mix dependencies:

defp deps do
  [{:kvx, "~> 0.1"}]
end

In an existing or new module:

defmodule MyTestMod do
  use KVX.Bucket
end

Getting Started!

Let's try it out, compile your project and start an interactive console:

$ mix deps.get
$ mix compile
$ iex -S mix

Now let's play with kvx:

> MyTestMod.new(:mybucket)
:mybucket

> MyTestMod.set(:mybucket, :fruit, "banana")
:mybucket

> MyTestMod.mset(:mybucket, male_users: 200, female_users: 150)
:mybucket

> MyTestMod.get(:mybucket, :female_users)
150

> MyTestMod.mget(:mybucket, [:male_users, :female_users])
[200, 150]

> MyTestMod.find_all(:mybucket)
[fruit: "banana", male_users: 200, female_users: 150]

> MyTestMod.delete(:mybucket, :male_users)
:mybucket

> MyTestMod.get(:mybucket, :male_users)
nil

> MyTestMod.flush!(:mybucket)
:mybucket

> MyTestMod.find_all(:mybucket)
[]

Configuration

Most of the configuration that goes into the config is specific to the adapter. But there are some common/shared options such as: :adapter and :ttl. E.g.:

config :kvx,
  adapter: KVX.Bucket.ExShards,
  ttl: 1  # the ttl in seconds

Now, in case of the adapter KVX.Bucket.ExShards, it has some extra options like module. E.g.:

config :kvx,
  adapter: KVX.Bucket.ExShards,
  ttl: 1,  # the ttl in seconds
  module: ExShards.Local

Besides, you can define bucket options in the config:

config :kvx,
  adapter: KVX.Bucket.ExShards,
  ttl: 43200, # the ttl in seconds
  module: ExShards,
  buckets: [
    mybucket1: [
      n_shards: 4
    ],
    mybucket2: [
      n_shards: 8
    ]
  ]

In case of ExShards adapter, run-time options when calling new/2 function, are the same as ExShards.new/2. E.g.:

MyModule.new(:mybucket, [n_shards: 4])

NOTE: For more information check KVX.Bucket.ExShards.

Running Tests

$ mix test

Coverage

$ mix coveralls

NOTE: For more coverage options check excoveralls.

Example

As we mentioned before, one of the most typical use case might be use KVX as a Cache. Now, let's suppose you're working with Ecto, and you want to be able to cache data when you call Ecto.Repo.get/3, and on other hand, be able to handle eviction, remove/update cached data when they change or mutate – typically when you call Ecto.Repo.insert/2, Ecto.Repo.update/2, etc.

To do so, let's implement our own CacheableRepo to encapsulate data access and caching logic. First let's create our bucket and the Ecto.Repo in two separated modules:

defmodule MyApp.Bucket do
 use KVX.Bucket
end

defmodule MyApp.Repo do
 use Ecto.Repo, otp_app: :myapp
end

Now, let's code our CacheableRepo, re-implementing some Ecto.Repo functions but adding caching. It is as simple as this:

defmodule MyApp.CacheableRepo do
  alias MyApp.Repo
  alias MyApp.Bucket

  require Logger

  def get(queryable, id, opts \\ []) do
    get(&Repo.get/3, queryable, id, opts)
  end

  def get!(queryable, id, opts \\ []) do
    get(&Repo.get!/3, queryable, id, opts)
  end

  def get_by(queryable, clauses, opts \\ []) do
    get(&Repo.get_by/3, queryable, clauses, opts)
  end

  def get_by!(queryable, clauses, opts \\ []) do
    get(&Repo.get_by!/3, queryable, clauses, opts)
  end

  defp get(fun, queryable, key, opts) do
    b = bucket(queryable)
    case Bucket.get(b, key) do
      nil ->
        value = fun.(queryable, key, opts)
        if value != nil do
          Logger.debug "CACHING <get>: #{inspect key} => #{inspect value}"
          Bucket.set(b, key, value)
        end
        value
      value ->
        Logger.debug "CACHED <get>: #{inspect key} => #{inspect value}"
        value
    end
  end

  def insert(struct, opts \\ []) do
    case Repo.insert(struct, opts) do
      {:ok, schema} = rs ->
        schema
        |> bucket
        |> Bucket.delete(schema.id)
        rs
      error ->
        error
    end
  end

  def insert!(struct, opts \\ []) do
    rs = Repo.insert!(struct, opts)
    rs
    |> bucket
    |> Bucket.delete(rs.id)
    rs
  end

  def update(struct, opts \\ []) do
    case Repo.update(struct, opts) do
      {:ok, schema} = rs ->
        schema
        |> bucket
        |> Bucket.set(schema.id, schema)
        rs
      error ->
        error
    end
  end

  def update!(struct, opts \\ []) do
    rs = Repo.update!(struct, opts)
    rs
    |> bucket
    |> Bucket.set(rs.id, rs)
    rs
  end

  def delete(struct, opts \\ []) do
    case Repo.delete(struct, opts) do
      {:ok, schema} = rs ->
        schema
        |> bucket
        |> Bucket.delete(schema.id)
        rs
      error ->
        error
    end
  end

  def delete!(struct, opts \\ []) do
    rs = Repo.delete!(struct, opts)
    rs
    |> bucket
    |> Bucket.delete(rs.id)
    rs
  end

  # function to resolve what bucket depending on the given schema
  defp bucket(%{__struct__: struct}), do: Bucket.new(struct)
  defp bucket(struct) when is_atom(struct), do: Bucket.new(struct)
  defp bucket(_), do: Bucket.new(:default)
end

Now that we have our CacheableRepo, it can be used instead of Ecto.Repo (since it is a wrapper on top of it, but it adds caching) for data you consider can be cached, for example, you can use it from your Phoenix Controllers – in case you're using Phoenix.

Copyright and License

Copyright (c) 2016 Carlos Andres Bolaños R.A.

KVX source code is licensed under the MIT License.

About

Simple in-memory Key/Value Store written in Elixir using `cabol/ex_shards`

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.