Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add match option to Nebulex.Caching #56

Merged
merged 2 commits into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions lib/nebulex/caching.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ defmodule Nebulex.Caching do
* `:opts` - Defines the cache options that will be passed as argument
to the invoked cache function (optional).

* `:match` - Defines a function that takes one argument and will be used to decide if the
cabol marked this conversation as resolved.
Show resolved Hide resolved
cache should be updated or not (optional). If this option is not present,
the value will always be updated. Does not have any effect upon eviction
since values are always evicted before executing the function logic.

## Example

Suppose we are using `Ecto` and we want to define some caching functions in
Expand All @@ -46,6 +51,10 @@ defmodule Nebulex.Caching do
Repo.all(query)
end

defcacheable get_newest_user(), cache: Cache, key: {User, :latest}, match: &(not is_nil(&1)) do
Repo.get_newest(User)
end

defupdatable update_user!(%User{} = user, attrs), cache: Cache, key: {User, user.id} do
user
|> User.changeset(attrs)
Expand Down Expand Up @@ -88,6 +97,10 @@ defmodule Nebulex.Caching do
defcacheable all(query), cache: Cache do
# your logic (maybe the loader to retrieve the value from the SoR)
end

defcacheable get_newest_user(), cache: Cache, key: {User, :latest}, match: &(not is_nil(&1)) do
Repo.get_newest(User)
end
end

The **Read-through** pattern is supported by this macro. The loader to
Expand Down Expand Up @@ -172,6 +185,14 @@ defmodule Nebulex.Caching do
defupdatable update_with_ttl(name), cache: Cache, opts: [ttl: 3600] do
# your logic (maybe write data to the SoR)
end

defcacheable update_when_not_nil(), cache: Cache, match: &match_function/1 do
# your logic (maybe write data to the SoR)
end

defp match_function(value) do
# your condition to skip updating the cache
edn
end

The **Write-through** pattern is supported by this macro. Your function
Expand Down Expand Up @@ -213,6 +234,7 @@ defmodule Nebulex.Caching do
key_var = Keyword.get(opts, :key)
keys_var = Keyword.get(opts, :keys)
opts_var = Keyword.get(opts, :opts, [])
match_var = Keyword.get(opts, :match)
action_logic = action_logic(action, block, opts)

quote do
Expand All @@ -221,6 +243,7 @@ defmodule Nebulex.Caching do
key = unquote(key_var) || :erlang.phash2({unquote(name), unquote(as_args)})
keys = unquote(keys_var)
opts = unquote(opts_var)
match = unquote(match_var) || fn _ -> true end

unquote(action_logic)
end
Expand All @@ -233,7 +256,12 @@ defmodule Nebulex.Caching do
value
else
value = unquote(block)
cache.set(key, value, opts)

if apply(match, [value]) do
cache.set(key, value, opts)
else
value
end
end
end
end
Expand All @@ -250,7 +278,12 @@ defmodule Nebulex.Caching do
defp action_logic(:defupdatable, block, _opts) do
quote do
value = unquote(block)
cache.set(key, value, opts)

if apply(match, [value]) do
cache.set(key, value, opts)
else
value
end
end
end

Expand Down
26 changes: 26 additions & 0 deletions test/nebulex/caching_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ defmodule Nebulex.CachingTest do
refute Cache.get(1)
end

test "cacheable with match" do
refute Cache.get(:x)
assert :x == get_with_match(:x)
refute Cache.get(:x)

refute Cache.get(:y)
assert :y == get_with_match(:y)
assert Cache.get(:y)
end

test "cacheable with default key" do
key = :erlang.phash2({:get_with_default_key, [123, {:foo, "bar"}]})

Expand Down Expand Up @@ -143,6 +153,14 @@ defmodule Nebulex.CachingTest do
refute Cache.get(:y)
end

test "updatable with match" do
assert :ok == set_keys(x: 0, y: 0, z: 0)
assert :x == cache_put_with_match(:x)
assert :y == cache_put_with_match(:y)
assert 0 == Cache.get(:x)
assert :y == Cache.get(:y)
end

## Caching Functions

defcacheable get_by_x(x, y \\ "y"), cache: Cache, key: x do
Expand All @@ -153,6 +171,10 @@ defmodule Nebulex.CachingTest do
x
end

defcacheable get_with_match(x), cache: Cache, key: x, match: fn x -> x != :x end do
x
end

defcacheable get_by_xy(x, y), cache: Cache, key: {x, y} do
{x, y}
end
Expand Down Expand Up @@ -189,6 +211,10 @@ defmodule Nebulex.CachingTest do
x
end

defupdatable cache_put_with_match(x), cache: Cache, key: x, match: fn x -> x != :x end do
x
end

## Private Functions

defp set_keys(entries) do
Expand Down