Skip to content

Commit 348aa51

Browse files
committed
[#3] Nebulex.Adapter.Transaction behaviour
[#5] `Nebulex.Adapter.Persistence` behaviour
1 parent a7eda39 commit 348aa51

5 files changed

Lines changed: 126 additions & 30 deletions

File tree

lib/nebulex/adapters/cachex.ex

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@ defmodule Nebulex.Adapters.Cachex do
66
# Provide Cache Implementation
77
@behaviour Nebulex.Adapter
88
@behaviour Nebulex.Adapter.Queryable
9+
@behaviour Nebulex.Adapter.Persistence
10+
11+
# Inherit default transaction implementation
12+
use Nebulex.Adapter.Transaction
913

1014
import Nebulex.Helpers
1115

1216
alias Cachex.Query
17+
alias Nebulex.Entry
1318

1419
@compile {:inline, to_ttl: 1}
1520

@@ -178,12 +183,49 @@ defmodule Nebulex.Adapters.Cachex do
178183
end
179184

180185
def stream(%{name: name}, query, opts) do
181-
Cachex.stream!(name, query, batch_size: opts[:page_size] || 100)
186+
query = maybe_return_entry(query, opts[:return])
187+
Cachex.stream!(name, query, batch_size: opts[:page_size] || 20)
182188
rescue
183189
e in Cachex.ExecutionError ->
184190
reraise Nebulex.QueryError, [message: e.message, query: query], __STACKTRACE__
185191
end
186192

193+
defp maybe_return_entry([{pattern, conds, _ret}], :key) do
194+
[{pattern, conds, [:"$1"]}]
195+
end
196+
197+
defp maybe_return_entry([{pattern, conds, _ret}], :value) do
198+
[{pattern, conds, [:"$4"]}]
199+
end
200+
201+
defp maybe_return_entry([{pattern, conds, _ret}], {:key, :value}) do
202+
[{pattern, conds, [{{:"$1", :"$4"}}]}]
203+
end
204+
205+
defp maybe_return_entry([{pattern, conds, _ret}], :entry) do
206+
[{pattern, conds, [%Entry{key: :"$1", value: :"$4", touched: :"$2", ttl: :"$3"}]}]
207+
end
208+
209+
defp maybe_return_entry(query, _return), do: query
210+
211+
## Persistence
212+
213+
@impl true
214+
def dump(%{name: name}, path, opts) do
215+
case Cachex.dump(name, path, opts) do
216+
{:ok, true} -> :ok
217+
{:error, _} = error -> error
218+
end
219+
end
220+
221+
@impl true
222+
def load(%{name: name}, path, opts) do
223+
case Cachex.load(name, path, opts) do
224+
{:ok, true} -> :ok
225+
{:error, _} = error -> error
226+
end
227+
end
228+
187229
## Private Functions
188230

189231
defp to_ttl(:infinity), do: nil

test/shared/cachex_test.exs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ defmodule Nebulex.Adapters.CachexTest do
77
quote do
88
use Nebulex.Cache.EntryTest
99
use Nebulex.Cache.EntryExpirationTest
10+
use Nebulex.Cache.TransactionTest
11+
use Nebulex.Cache.PersistenceTest
1012
use Nebulex.Adapters.Cachex.QueryableTest
13+
use Nebulex.Adapters.Cachex.PersistenceErrorTest
1114
end
1215
end
1316
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
defmodule Nebulex.Adapters.Cachex.PersistenceErrorTest do
2+
import Nebulex.CacheCase
3+
4+
deftests "persistence error" do
5+
test "dump: invalid path", %{cache: cache} do
6+
assert {:error, reason} = cache.dump("/invalid/path")
7+
assert reason in [:unreachable_file, :enoent]
8+
end
9+
10+
test "load: invalid path", %{cache: cache} do
11+
assert {:error, reason} = cache.load("wrong_file")
12+
assert reason in [:unreachable_file, :enoent]
13+
end
14+
end
15+
end

test/shared/queryable_test.exs

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,84 @@
11
defmodule Nebulex.Adapters.Cachex.QueryableTest do
22
import Nebulex.CacheCase
33

4-
deftests "queryable" do
4+
deftests do
55
import Nebulex.CacheHelpers
66

77
alias Cachex.Query
88

9-
test "all", %{cache: cache} do
10-
set1 = cache_put(cache, 1..50)
11-
set2 = cache_put(cache, 51..100)
9+
describe "all" do
10+
test "returns all keys in cache", %{cache: cache} do
11+
set1 = cache_put(cache, 1..50)
12+
set2 = cache_put(cache, 51..100)
1213

13-
for x <- 1..100, do: assert(cache.get(x) == x)
14-
expected = set1 ++ set2
14+
for x <- 1..100, do: assert(cache.get(x) == x)
15+
expected = set1 ++ set2
1516

16-
assert :lists.usort(cache.all()) == expected
17+
assert :lists.usort(cache.all()) == expected
1718

18-
set3 = Enum.to_list(20..60)
19-
:ok = Enum.each(set3, &cache.delete(&1))
20-
expected = :lists.usort(expected -- set3)
19+
set3 = Enum.to_list(20..60)
20+
:ok = Enum.each(set3, &cache.delete(&1))
21+
expected = :lists.usort(expected -- set3)
2122

22-
assert :lists.usort(cache.all()) == expected
23+
assert :lists.usort(cache.all()) == expected
24+
end
2325
end
2426

25-
test "stream", %{cache: cache} do
26-
entries = for x <- 1..10, into: %{}, do: {x, x * 2}
27-
assert cache.put_all(entries) == :ok
27+
describe "stream" do
28+
@entries for x <- 1..10, into: %{}, do: {x, x * 2}
29+
30+
test "returns all keys in cache", %{cache: cache} do
31+
:ok = cache.put_all(@entries)
32+
33+
assert nil
34+
|> cache.stream()
35+
|> Enum.to_list()
36+
|> :lists.usort() == Map.keys(@entries)
37+
end
38+
39+
test "returns all values in cache", %{cache: cache} do
40+
:ok = cache.put_all(@entries)
2841

29-
expected = Map.keys(entries)
42+
assert true
43+
|> Query.create(:key)
44+
|> cache.stream(return: :value, page_size: 3)
45+
|> Enum.to_list()
46+
|> :lists.usort() == Map.values(@entries)
47+
end
3048

31-
assert true
32-
|> Query.create(:key)
33-
|> cache.stream()
34-
|> Enum.to_list()
35-
|> :lists.usort() == expected
49+
test "returns all key/value pairs in cache", %{cache: cache} do
50+
:ok = cache.put_all(@entries)
3651

37-
assert true
38-
|> Query.create(:key)
39-
|> cache.stream(page_size: 3)
40-
|> Enum.to_list()
41-
|> :lists.usort() == expected
52+
assert true
53+
|> Query.create(:key)
54+
|> cache.stream(return: {:key, :value}, page_size: 3)
55+
|> Enum.to_list()
56+
|> :lists.usort() == :maps.to_list(@entries)
57+
end
58+
59+
test "returns what is dictated by the built query", %{cache: cache} do
60+
:ok = cache.put_all(@entries)
61+
62+
expected =
63+
:lists.zip3(
64+
Map.keys(@entries),
65+
Map.values(@entries),
66+
List.duplicate(nil, map_size(@entries))
67+
)
68+
69+
assert true
70+
|> Query.create({:key, :value, :ttl})
71+
|> cache.stream(page_size: 3)
72+
|> Enum.to_list()
73+
|> :lists.usort() == expected
74+
end
4275

43-
assert_raise Nebulex.QueryError, fn ->
44-
:invalid_query
45-
|> cache.stream()
46-
|> Enum.to_list()
76+
test "raises when query is invalid", %{cache: cache} do
77+
assert_raise Nebulex.QueryError, fn ->
78+
:invalid_query
79+
|> cache.stream()
80+
|> Enum.to_list()
81+
end
4782
end
4883
end
4984
end

test_cache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
�j

0 commit comments

Comments
 (0)