/
nil.ex
140 lines (103 loc) · 3.79 KB
/
nil.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
defmodule Nebulex.Adapters.Nil do
@moduledoc """
The **Nil adapter** is a special cache adapter that disables the cache;
it loses all the items saved on it and it returns `nil` for all the read
and `true` for all save operations. This adapter is mostly useful for tests.
## Example
Suppose you have an application using Ecto for database access and Nebulex
for caching. Then, you have defined a cache and a repo within it. Since you
are using a database, there might be some cases you may want to disable the
cache to avoid issues when running the test, for example, in some test cases,
when accessing the database you expect no data at all, but you could retrieve
the data from cache anyway because maybe it was cached in a previous test.
Therefore, you have to delete all entries from the cache before to run each
test to make sure the cache is always empty. This is where the Nil adapter
comes in, instead of adding code to flush the cache before each test, you
could define a test cache using the Nil adapter for the tests.
One one hand, you have defined the cache in your application within
`lib/my_app/cache.ex`:
defmodule MyApp.Cache do
use Nebulex.Cache,
otp_app: :my_app,
adapter: Nebulex.Adapters.Local
end
And on the other hand, in the tests you have defined the test cache within
`test/support/test_cache.ex`:
defmodule MyApp.TestCache do
use Nebulex.Cache,
otp_app: :my_app,
adapter: Nebulex.Adapters.Nil
end
Now, we have to tell the app what cache to use depending on the environment,
for tests we want `MyApp.TestCache`, otherwise it is always `MyApp.Cache`.
We can do this very easy by introducing a new config parameter to decide
what cache module to use. For tests you can define the config
`config/test.exs`:
config :my_app,
nebulex_cache: MyApp.TestCache,
...
The final piece is to read the config parameter and start the cache properly.
Within `lib/my_app/application.ex` you could have:
def start(_type, _args) do
children = [
{Application.get_env(:my_app, :nebulex_cache, MyApp.Cache), []},
]
...
As you can see, by default `MyApp.Cache` is always used, unless the
`:nebulex_cache` option points to a different module, which will be
when tests are executed (`:test` env).
"""
# Provide Cache Implementation
@behaviour Nebulex.Adapter
@behaviour Nebulex.Adapter.Entry
@behaviour Nebulex.Adapter.Queryable
@behaviour Nebulex.Adapter.Persistence
@behaviour Nebulex.Adapter.Stats
# Inherit default transaction implementation
use Nebulex.Adapter.Transaction
## Nebulex.Adapter
@impl true
defmacro __before_compile__(_env), do: :ok
@impl true
def init(_opts) do
child_spec = Supervisor.child_spec({Agent, fn -> :ok end}, id: {Agent, 1})
{:ok, child_spec, %{}}
end
## Nebulex.Adapter.Entry
@impl true
def get(_, _, _), do: nil
@impl true
def get_all(_, _, _), do: %{}
@impl true
def put(_, _, _, _, _, _), do: true
@impl true
def put_all(_, _, _, _, _), do: true
@impl true
def delete(_, _, _), do: :ok
@impl true
def take(_, _, _), do: nil
@impl true
def has_key?(_, _), do: false
@impl true
def ttl(_, _), do: nil
@impl true
def expire(_, _, _), do: true
@impl true
def touch(_, _), do: true
@impl true
def update_counter(_, _, amount, _, default, _), do: default + amount
## Nebulex.Adapter.Queryable
@impl true
def execute(_, :all, _, _), do: []
def execute(_, _, _, _), do: 0
@impl true
def stream(_, _, _), do: Stream.each([], & &1)
## Nebulex.Adapter.Persistence
@impl true
def dump(_, _, _), do: :ok
@impl true
def load(_, _, _), do: :ok
## Nebulex.Adapter.Stats
@impl true
def stats(_), do: %Nebulex.Stats{}
end