Git Product home page Git Product logo

kvx's Introduction

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.

kvx's People

Contributors

cabol avatar sergiotapia avatar

Watchers

Fabian Frei avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.