absinthe_loaded? = RequestCache.Application.dependency_found?(:absinthe) and
RequestCache.Application.dependency_found?(:absinthe_plug)
if absinthe_loaded? do
defmodule RequestCache.Middleware do
alias RequestCache.Util
@behaviour Absinthe.Middleware
@impl Absinthe.Middleware
def call(%Absinthe.Resolution{} = resolution, opts) when is_list(opts) do
opts = ensure_valid_ttl(opts)
enable_cache_for_resolution(resolution, opts)
end
@impl Absinthe.Middleware
def call(%Absinthe.Resolution{} = resolution, ttl) when is_integer(ttl) do
enable_cache_for_resolution(resolution, ttl: ttl)
end
defp ensure_valid_ttl(opts) do
ttl = opts[:ttl] || RequestCache.Config.default_ttl()
Keyword.put(opts, :ttl, ttl)
end
defp enable_cache_for_resolution(%Absinthe.Resolution{} = resolution, opts) do
resolution = resolve_resolver_func_middleware(resolution, opts)
if resolution.context[RequestCache.Config.conn_private_key()][:enabled?] do
Util.verbose_log("[RequestCache.Middleware] Enabling cache for resolution")
root_resolution_path_item = List.last(resolution.path)
cache_request? = !!root_resolution_path_item &&
root_resolution_path_item.schema_node.name === "RootQueryType" &&
query_name_whitelisted?(root_resolution_path_item.name, opts)
%{resolution |
value: resolution.value || opts[:value],
context: Map.update!(
resolution.context,
RequestCache.Config.conn_private_key(),
&Util.deep_merge(&1,
request: opts,
cache_request?: cache_request?
)
)
}
else
Util.log_cache_disabled_message()
resolution
end
end
defp resolve_resolver_func_middleware(resolution, opts) do
if resolver_middleware?(opts) do
%{resolution | state: :resolved}
else
resolution
end
end
defp resolver_middleware?(opts), do: opts[:value]
defp query_name_whitelisted?(query_name, opts) do
is_nil(opts[:whitelisted_query_names]) or query_name in opts[:whitelisted_query_names]
end
@spec store_result(
result :: any,
opts_or_ttl :: RequestCache.opts | pos_integer
) :: {:middleware, module, RequestCache.opts}
def store_result(result, ttl) when is_integer(ttl) do
store_result(result, [ttl: ttl])
end
def store_result(result, opts) when is_list(opts) do
{:middleware, RequestCache.Middleware, Keyword.put(opts, :value, result)}
end
end
end