Packages
ecto_adapters_dynamodb
0.4.5
3.6.1
3.6.0
3.5.0
3.4.1
3.4.0
3.3.7
3.3.6
3.3.5
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.0
3.1.3
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-beta.1
2.0.0-beta.0
2.0.0-alpha.4
2.0.0-alpha.3
2.0.0-alpha.2
2.0.0-alpha.1
2.0.0-alpha.0
1.3.0
1.2.1
1.2.0
1.1.3
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.3
0.2.2
0.2.1
0.1.2
0.1.1
A DynamoDB adapter for Ecto supporting basic queries. See https://github.com/circles-learning-labs/ecto_adapters_dynamodb for detailed instructions.
Current section
Files
Jump to
Current section
Files
lib/ecto_adapters_dynamodb/cache.ex
defmodule Ecto.Adapters.DynamoDB.Cache do
@moduledoc """
An Elixir agent to cache DynamoDB table schemas and the first page of results for selected tables
"""
@typep table_name_t :: String.t
@typep dynamo_response_t :: %{required(String.t) => term}
@spec start_link() :: Agent.on_start
def start_link do
cached_table_list = Application.get_env(:ecto_adapters_dynamodb, :cached_tables)
Agent.start_link(fn -> %{
schemas: %{},
tables: (for table_name <- cached_table_list, into: %{}, do: {table_name, nil})
} end, name: __MODULE__)
end
@doc """
Returns the cached value for a call to DynamoDB, describe-table. Performs a DynamoDB scan if not yet cached and raises any errors as a result of the request. The raw json is presented as an elixir map.
"""
@spec describe_table!(table_name_t) :: dynamo_response_t | no_return
def describe_table!(table_name) do
case describe_table(table_name) do
{:ok, schema} -> schema
{:error, error} -> raise error.type, message: error.message
end
end
@spec describe_table(table_name_t) :: {:ok, dynamo_response_t} | {:error, term}
def describe_table(table_name),
do: Agent.get_and_update(__MODULE__, &do_describe_table(&1, table_name))
@doc """
Performs a DynamoDB, describe-table, and caches (without returning) the result. Raises any errors as a result of the request
"""
@spec update_table_info!(table_name_t) :: :ok | no_return
def update_table_info!(table_name) do
case update_table_info(table_name) do
:ok -> :ok
{:error, error} -> raise error.type, message: error.message
end
end
@spec update_table_info(table_name_t) :: :ok | {:error, term}
def update_table_info(table_name),
do: Agent.get_and_update(__MODULE__, &do_update_table_info(&1, table_name))
@doc """
Returns the cached first page of results for a table. Performs a DynamoDB scan if not yet cached and raises any errors as a result of the request
"""
@spec scan!(table_name_t) :: dynamo_response_t | no_return
def scan!(table_name) do
case scan(table_name) do
{:ok, scan_result} -> scan_result
{:error, error} -> raise error.type, message: error.message
end
end
@spec scan(table_name_t) :: {:ok, dynamo_response_t} | {:error, term}
def scan(table_name),
do: Agent.get_and_update(__MODULE__, &do_scan(&1, table_name))
@doc """
Performs a DynamoDB scan and caches (without returning) the first page of results. Raises any errors as a result of the request
"""
@spec update_cached_table!(table_name_t) :: :ok | no_return
def update_cached_table!(table_name) do
case update_cached_table(table_name) do
:ok -> :ok
{:error, error} -> raise error.type, message: error.message
end
end
@spec update_cached_table(table_name_t) :: :ok | {:error, term}
def update_cached_table(table_name),
do: Agent.get_and_update(__MODULE__, &do_update_cached_table(&1, table_name))
@doc """
Returns the current cache of table schemas, and cache of first page of results for selected tables, as an Elixir map
"""
# For testing and debugging use only:
def get_cache,
do: Agent.get(__MODULE__, &(&1))
defp do_describe_table(cache, table_name) do
case cache.schemas[table_name] do
nil ->
result = ExAws.Dynamo.describe_table(table_name) |> ExAws.request
case result do
{:ok, %{"Table" => schema}} ->
updated_cache = put_in(cache.schemas[table_name], schema)
{{:ok, schema}, updated_cache}
{:error, error} ->
{{:error, %{type: ExAws.Error, message: "ExAws Request Error! #{inspect error}"}}, cache}
end
schema ->
{{:ok, schema}, cache}
end
end
defp do_update_table_info(cache, table_name) do
result = ExAws.Dynamo.describe_table(table_name) |> ExAws.request
case result do
{:ok, %{"Table" => schema}} ->
updated_cache = put_in(cache.schemas[table_name], schema)
{:ok, updated_cache}
{:error, error} ->
{{:error, %{type: ExAws.Error, message: "ExAws Request Error! #{inspect error}"}}, cache}
end
end
defp do_scan(cache, table_name) do
table_name_in_config = Map.has_key?(cache.tables, table_name)
case cache.tables[table_name] do
nil when table_name_in_config ->
result = ExAws.Dynamo.scan(table_name) |> ExAws.request
case result do
{:ok, scan_result} ->
updated_cache = put_in(cache.tables[table_name], scan_result)
{{:ok, scan_result}, updated_cache}
{:error, error} ->
{{:error, %{type: ExAws.Error, message: "ExAws Request Error! #{inspect error}"}}, cache}
end
nil ->
{{:error, %{type: ArgumentError, message: "Could not confirm the table, #{inspect table_name}, as listed for caching in the application's configuration. Please see README file for details."}}, cache}
cached_scan ->
{{:ok, cached_scan}, cache}
end
end
defp do_update_cached_table(cache, table_name) do
table_name_in_config = Map.has_key?(cache.tables, table_name)
case cache.tables[table_name] do
nil when not table_name_in_config ->
{{:error, %{type: ArgumentError, message: "Could not confirm the table, #{inspect table_name}, as listed for caching in the application's configuration. Please see README file for details."}}, cache}
_ ->
result = ExAws.Dynamo.scan(table_name) |> ExAws.request
case result do
{:ok, scan_result} ->
updated_cache = put_in(cache.tables[table_name], scan_result)
{:ok, updated_cache}
{:error, error} ->
{{:error, %{type: ExAws.Error, message: "ExAws Request Error! #{inspect error}"}}, cache}
end
end
end
end