README.md

# Visor

Visor adds VSR (View Stamped Replication) on top of GenServer.

If you want easy process supervision, add a Supervisor.

If you want easy replication, add Visor!

## Usage

Create a module, use `Visor`, and implement the callbacks.
Let's create a replicated cache.

Define a module called `Cache`, set the `initial_state` to an empty map (`%{}`) and implement the
`handle_commit` callback which returns `nil` and merges the passed in data with the existing state.

```elixir
defmodule Cache do
  use Visor

  @impl Visor
  def initial_state(_opts), do: %{}

  @impl Visor
  def handle_commit({:add, item}, state) do
    {:ok, nil, Map.merge(state, item)}
  end
end
```

Now, add Cache to your application's supervision tree, and configure your `cluster_size`
(how many nodes you want this to replicate across)

```elixir

  def start(_type, _args) do
    children = [
      {Cache, cluster_size: 3}
    ]

    opts = [strategy: :one_for_one, name: Cache.Supervisor]
    Supervisor.start_link(children, opts)
  end
```

And that's it. You now have a cache that's replicated across 3 nodes. 
It handles replication, leader election, and recovery. 

To add an item to your cache, commit the data:

```elixir
Cache.commit({:add, %{user1: %{email: "advisor1@example.com"}}})
#=> nil

Cache.commit({:add, %{user2: %{email: "advisor2@example.com"}}})
#=> nil
```

Get the full state of your cache with:

```elixir
Cache.get()

#=> %{email: "advisor@example.com"}
%{
  user1: %{email: "advisor1@example.com"},
  user2: %{email: "advisor1@example.com"}
}
```


Pass in an accessor list to `get_in` your cache for quicker access:

```elixir
Cache.get_in([:user1, :email])

#=> "advisor1@example.com"
```