# `Money.ExchangeRates.Cache`
[🔗](https://github.com/ex-money/money/blob/v6.2.0/lib/money/exchange_rates/cache.ex#L1)

Defines the cache behaviour for exchange rates.

Most callbacks receive a `t:cache/0` term - the value returned by `c:init/1` -
identifying which retriever's storage to operate on. This allows a single
cache module (such as the bundled `Money.ExchangeRates.Cache.Ets` and
`Money.ExchangeRates.Cache.Dets`) to be shared safely by multiple named
retrievers, each backed by its own separated storage.

## Migrating from the deprecated singleton callbacks

Older cache modules implemented `init/0`, `terminate/0`, `latest_rates/0`,
`historic_rates/1`, `last_updated/0`, `store_latest_rates/2` and
`store_historic_rates/2`, storing rates as fixed, module-wide state. These
still work, but named retrievers sharing such a module overwrite each other's
rates.

To migrate, add the `t:cache/0` value returned by `init/1` as the leading
argument to every other callback, and key storage off the `name` given to
`init/1` instead of a fixed identifier:

    def init(name), do: :ets.new(name, [:named_table, :public])
    def latest_rates(cache), do: :ets.lookup(cache, :latest_rates)
    def store_latest_rates(cache, rates, retrieved_at) do
      :ets.insert(cache, {:latest_rates, rates})
      :ets.insert(cache, {:last_updated, retrieved_at})
    end

`terminate/1`, `historic_rates/2` and `store_historic_rates/3` follow the
same pattern.

# `cache`

```elixir
@type cache() :: any()
```

A reference to a retriever's cache storage, returned by `c:init/1`.

# `historic_rates`
*optional* 

> This callback is deprecated. Use historic_rates/2 instead.

```elixir
@callback historic_rates(Date.t()) ::
  {:ok, Money.ExchangeRates.t()} | {:error, {Exception.t(), String.t()}}
```

# `historic_rates`
*optional* 

```elixir
@callback historic_rates(cache(), Date.t()) ::
  {:ok, Money.ExchangeRates.t()} | {:error, {Exception.t(), String.t()}}
```

Retrieve the exchange rates for a given
date.

# `init`
*optional* 

> This callback is deprecated. Use init/1 instead.

```elixir
@callback init() :: any()
```

# `init`
*optional* 

```elixir
@callback init(name :: term()) :: cache()
```

Initialize the cache when the exchange rates
retriever is started

Called with the retriever's `:name`, so that a cache module can maintain
separate storage per retriever. Must return a `t:cache/0` value that is
passed to every other callback.

# `last_updated`
*optional* 

> This callback is deprecated. Use last_updated/1 instead.

```elixir
@callback last_updated() :: {:ok, DateTime.t()} | {:error, {Exception.t(), String.t()}}
```

# `last_updated`
*optional* 

```elixir
@callback last_updated(cache()) ::
  {:ok, DateTime.t()} | {:error, {Exception.t(), String.t()}}
```

Return the timestamp when the exchange rates were last updated.

# `latest_rates`
*optional* 

> This callback is deprecated. Use latest_rates/1 instead.

```elixir
@callback latest_rates() ::
  {:ok, Money.ExchangeRates.t()} | {:error, {Exception.t(), String.t()}}
```

# `latest_rates`
*optional* 

```elixir
@callback latest_rates(cache()) ::
  {:ok, Money.ExchangeRates.t()} | {:error, {Exception.t(), String.t()}}
```

Retrieve the latest exchange rates from the
cache.

# `store_historic_rates`
*optional* 

> This callback is deprecated. Use store_historic_rates/3 instead.

```elixir
@callback store_historic_rates(Money.ExchangeRates.t(), Date.t()) :: :ok
```

# `store_historic_rates`
*optional* 

```elixir
@callback store_historic_rates(cache(), Money.ExchangeRates.t(), Date.t()) :: :ok
```

Store the historic exchange rates for a given
date in the cache.

# `store_latest_rates`
*optional* 

> This callback is deprecated. Use store_latest_rates/3 instead.

```elixir
@callback store_latest_rates(Money.ExchangeRates.t(), DateTime.t()) :: :ok
```

# `store_latest_rates`
*optional* 

```elixir
@callback store_latest_rates(cache(), Money.ExchangeRates.t(), DateTime.t()) :: :ok
```

Store the latest exchange rates in the cache.

# `terminate`
*optional* 

> This callback is deprecated. Use terminate/1 instead.

```elixir
@callback terminate() :: any()
```

# `terminate`
*optional* 

```elixir
@callback terminate(cache()) :: any()
```

Terminate the cache when the retriever process
stops normally

---

*Consult [api-reference.md](api-reference.md) for complete listing*
