@@ -10,9 +10,10 @@ defmodule Cache do
1010
1111 @ callback opts_definition ( ) :: Keyword . t ( )
1212
13- @ callback start_link (
14- cache_opts :: Keyword . t ( )
15- ) :: { :ok , pid ( ) } | { :error , { :already_started , pid ( ) } | { :shutdown , term ( ) } | term ( ) } | :ignore
13+ @ callback start_link ( cache_opts :: Keyword . t ( ) ) ::
14+ { :ok , pid ( ) }
15+ | { :error , { :already_started , pid ( ) } | { :shutdown , term ( ) } | term ( ) }
16+ | :ignore
1617
1718 @ callback put ( cache_name :: atom , key :: atom | String . t ( ) , ttl :: pos_integer , value :: any ) ::
1819 :ok | ErrorMessage . t ( )
@@ -83,7 +84,6 @@ defmodule Cache do
8384
8485 adapter_opts ->
8586 pre_check_runtime_options . ( adapter_opts )
86-
8787 end
8888
8989 adapter_opts = if opts [ :sandbox? ] , do: [ ] , else: check_adapter_opts . ( opts [ :opts ] )
@@ -100,12 +100,42 @@ defmodule Cache do
100100
101101 def adapter_options , do: adapter_options! ( @ adapter_opts )
102102
103- defp adapter_options! ( { module , fun , args } ) , do: apply ( module , fun , args )
104- defp adapter_options! ( { app , key } ) , do: Application . fetch_env! ( app , key )
105- defp adapter_options! ( app_name ) when is_atom ( app_name ) , do: Application . fetch_env! ( app_name , __MODULE__ )
106- defp adapter_options! ( fun ) when is_function ( fun , 0 ) , do: fun . ( )
103+ # Generate only the needed adapter_options!/1 clauses based on the actual adapter_opts
104+ if match? ( { _ , _ , _ } , @ adapter_opts ) do
105+ defp adapter_options! ( { module , fun , args } ) , do: apply ( module , fun , args )
106+ end
107+
108+ if match? ( { _ , _ } , @ adapter_opts ) do
109+ defp adapter_options! ( { app , key } ) , do: Application . fetch_env! ( app , key )
110+ end
111+
112+ if is_atom ( @ adapter_opts ) and not is_nil ( @ adapter_opts ) and not is_list ( @ adapter_opts ) do
113+ defp adapter_options! ( app_name ) when is_atom ( app_name ) ,
114+ do: Application . fetch_env! ( app_name , __MODULE__ )
115+ end
116+
117+ if is_function ( @ adapter_opts , 0 ) do
118+ defp adapter_options! ( fun ) when is_function ( fun , 0 ) , do: fun . ( )
119+ end
120+
107121 defp adapter_options! ( options ) , do: options
108122
123+ # Dynamic error handler that compiler can't statically analyze
124+ defp handle_adapter_result ( result , operation , cache_name ) do
125+ with { :error , error } <- result do
126+ :telemetry . execute (
127+ [ :elixir_cache , :cache , operation , :error ] ,
128+ % { count: 1 } ,
129+ % {
130+ cache_name: cache_name ,
131+ error: error
132+ }
133+ )
134+
135+ result
136+ end
137+ end
138+
109139 def child_spec ( _ ) do
110140 @ cache_adapter . child_spec ( { @ cache_name , adapter_options ( ) } )
111141 end
@@ -118,16 +148,10 @@ defmodule Cache do
118148 [ :elixir_cache , :cache , :put ] ,
119149 % { cache_name: @ cache_name } ,
120150 fn ->
121- result = with { :error , error } = e <- @ cache_adapter . put ( @ cache_name , key , ttl , value , adapter_options ( ) ) do
122- :telemetry . execute ( [ :elixir_cache , :cache , :put , :error ] , % { count: 1 } , % {
123- cache_name: @ cache_name ,
124- error: error
125- } )
126-
127- e
128- end
129-
130- { result , % { cache_name: @ cache_name } }
151+ @ cache_name
152+ |> @ cache_adapter . put ( key , ttl , value , adapter_options ( ) )
153+ |> handle_adapter_result ( :put , @ cache_name )
154+ |> then ( & { & 1 , % { cache_name: @ cache_name } } )
131155 end
132156 )
133157 end
@@ -140,23 +164,22 @@ defmodule Cache do
140164 % { cache_name: @ cache_name } ,
141165 fn ->
142166 result =
143- case @ cache_adapter . get ( @ cache_name , key , adapter_options ( ) ) do
167+ @ cache_name
168+ |> @ cache_adapter . get ( key , adapter_options ( ) )
169+ |> handle_adapter_result ( :get , @ cache_name )
170+ |> case do
144171 { :ok , nil } = res ->
145172 :telemetry . execute ( [ :elixir_cache , :cache , :get , :miss ] , % { count: 1 } , % {
146173 cache_name: @ cache_name
147174 } )
148175
149176 res
150177
151- { :ok , value } -> { :ok , Cache.TermEncoder . decode ( value ) }
178+ { :ok , value } ->
179+ { :ok , Cache.TermEncoder . decode ( value ) }
152180
153- { :error , error } = e ->
154- :telemetry . execute ( [ :elixir_cache , :cache , :get , :error ] , % { count: 1 } , % {
155- cache_name: @ cache_name ,
156- error: error
157- } )
158-
159- e
181+ { :error , _ } = error ->
182+ error
160183 end
161184
162185 { result , % { cache_name: @ cache_name } }
@@ -171,16 +194,10 @@ defmodule Cache do
171194 [ :elixir_cache , :cache , :delete ] ,
172195 % { cache_name: @ cache_name } ,
173196 fn ->
174- result = with { :error , error } = e <- @ cache_adapter . delete ( @ cache_name , key , adapter_options ( ) ) do
175- :telemetry . execute ( [ :elixir_cache , :cache , :delete , :error ] , % { count: 1 } , % {
176- cache_name: @ cache_name ,
177- error: error
178- } )
179-
180- e
181- end
182-
183- { result , % { cache_name: @ cache_name } }
197+ @ cache_name
198+ |> @ cache_adapter . delete ( key , adapter_options ( ) )
199+ |> handle_adapter_result ( :delete , @ cache_name )
200+ |> then ( & { & 1 , % { cache_name: @ cache_name } } )
184201 end
185202 )
186203 end
@@ -220,25 +237,25 @@ defmodule Cache do
220237 end
221238
222239 @ doc """
223- Retrieves a value from the cache if it exists, or executes a function to create and store it.
224-
225- This is a convenience function implementing the common "get or create" pattern for caches.
226- It attempts to fetch a value from the cache first, and only if the value doesn't exist,
240+ Retrieves a value from the cache if it exists, or executes a function to create and store it.
241+
242+ This is a convenience function implementing the common "get or create" pattern for caches.
243+ It attempts to fetch a value from the cache first, and only if the value doesn't exist,
227244 it will execute the provided function to generate the value and store it in the cache.
228-
245+
229246 ## Parameters
230-
247+
231248 - `cache` - The cache module to use (must implement the Cache behaviour)
232249 - `key` - The key to look up or create
233250 - `fnc` - A function that returns `{:ok, value}` or `{:error, reason}`
234-
251+
235252 ## Returns
236-
253+
237254 - `{:ok, value}` - The value from cache or newly created value
238255 - `{:error, reason}` - If an error occurred during retrieval or creation
239-
256+
240257 ## Examples
241-
258+
242259 ```elixir
243260 Cache.get_or_create(MyApp.Cache, "user:123", fn ->
244261 case UserRepo.get(123) do
@@ -248,19 +265,13 @@ defmodule Cache do
248265 end)
249266 ```
250267 """
251- @ spec get_or_create ( module ( ) , atom ( ) | String . t ( ) , ( -> { :ok , any ( ) } | { :error , any ( ) } ) ) ::
268+ @ spec get_or_create ( module ( ) , atom ( ) | String . t ( ) , ( -> { :ok , any ( ) } | { :error , any ( ) } ) ) ::
252269 { :ok , any ( ) } | { :error , any ( ) }
253270 def get_or_create ( cache , key , fnc ) do
254- case cache . get ( key ) do
255- { :ok , nil } ->
256- with { :ok , value } <- fnc . ( ) ,
257- :ok <- cache . put ( key , value ) do
258- { :ok , value }
259- end
260-
261- { :ok , _ } = res -> res
262-
263- { :error , _ } = e -> e
271+ with { :ok , nil } <- cache . get ( key ) ,
272+ { :ok , value } <- fnc . ( ) ,
273+ :ok <- cache . put ( key , value ) do
274+ { :ok , value }
264275 end
265276 end
266277end
0 commit comments