# Upgrading to v3.1

Nebulex v3.1 adds the `Nebulex.Adapter.CompositeKV` behaviour and changes
what `get_and_update/3` does with `nil`. If you only use the cache, update
the adapters and check the two changes below. If you maintain an adapter,
see the last section.

---

## Update the adapters

All adapters must implement `Nebulex.Adapter.CompositeKV`, and
`use Nebulex.Cache` checks it at compile time. An adapter built for v3.0
does not compile against v3.1; the error tells you which behaviour is
missing. Update the adapters along with core:

```elixir
defp deps do
  [
    {:nebulex, "~> 3.1"},
    {:nebulex_local, "~> 3.1"},
    ...
  ]
end
```

---

## `get_and_update/3` stores `nil`

In v3, `nil` is a valid cache value, but `get_and_update/3` still followed
the v2 rule where a `nil` new value meant "do not write". Now, when the
function returns `{current, nil}`, the cache stores `nil`:

```elixir
# v3.0
iex> MyCache.get_and_update!(:key, fn current -> {current, nil} end)
{6, 6}
iex> MyCache.get!(:key)
6

# v3.1
iex> MyCache.get_and_update!(:key, fn current -> {current, nil} end)
{6, nil}
iex> MyCache.get!(:key)
nil
```

To remove the entry, return `:pop`. It now also removes an entry whose
value is `nil`. Before, it treated a cached `nil` as a missing key.

---

## Update Telemetry handlers that match on `:command`

Composite operations now emit their own command span, besides the spans of
the primitive commands they run. Handlers get four new `:command` values:
`:get_and_update`, `:update`, `:fetch_or_store`, and `:get_or_store`. If
your handler matches `:command` exhaustively, add a clause for them or a
fallback clause. Otherwise it raises and Telemetry detaches it:

```diff
  def handle_event(_event, _measurements, %{command: :put}, _config), do: ...
  def handle_event(_event, _measurements, %{command: :fetch}, _config), do: ...
+ def handle_event(_event, _measurements, _metadata, _config), do: :ok
```

---

## For adapter authors

### Implement `Nebulex.Adapter.CompositeKV`

Add the behaviour to your adapter. `use Nebulex.Adapter.CompositeKV` gives
you the default implementation, which runs the given function on the
calling node using the adapter's `fetch`, `put`, and `delete` callbacks:

```diff
  defmodule MyAdapter do
    @behaviour Nebulex.Adapter
    @behaviour Nebulex.Adapter.KV
+
+   use Nebulex.Adapter.CompositeKV
```

To change where the function runs or what atomicity it has, override
`get_and_update/6`, `update/7`, `fetch_or_store/6`, or `get_or_store/6`.
See `Nebulex.Adapter.CompositeKV`.

### `__before_compile__/1` is required

It was listed as optional, but `Nebulex.Cache` has always called it. An
adapter without it never worked, so nothing changes if yours has it.
