Skip to content

Commit

Permalink
v4.0.2 prep (#28)
Browse files Browse the repository at this point in the history
Adds dialyxir, addresses dialyzer warnings, credo fixes, adds code_quality alias, updates documentation with info about latest local DDB version.
  • Loading branch information
darrenklein authored Dec 24, 2021
1 parent 460521c commit 32a3be3
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 63 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## v4.0.2 - 2021-12-24

- Add :consistent_read option in scan_opts spec
- Add `code_quality` alias
- Adds dialyxir to dev dependencies
- Various credo and dialyzer fixes
- Fixes typos in documentation and README

## v4.0.1 - 2021-04-26

- Update dependencies
Expand Down
9 changes: 7 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ Contributions to ExAws.Dynamo are always welcome! For contributions to this part
Before submitting any PR, please make sure that the code is adequately tested, formatted, and checked for other issues... in other words, please run

```bash
mix format
mix credo
# a convenient alias for runnin `mix format`, `mix credo --strict`, and `mix dialyzer`
mix code_quality
```

and

```bash
mix test
```

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Documentation for **ExAwsDynamo** can be found at [https://hexdocs.pm/ex_aws_dyn

### DynamoDB Local

If you are running this module against a local development instance of DynamoDB, you'll want to make sure that you have installed the latest version, `1.15.0` (released 2021-02-08). You can find links to download the latest version [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html).
If you are running this module against a local development instance of DynamoDB, you'll want to make sure that you have installed the latest version, `1.17.2` (released 2021-12-16). You can find links to download the latest version [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html).

## Configuration

Expand Down
90 changes: 46 additions & 44 deletions lib/ex_aws/dynamo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ defmodule ExAws.Dynamo do

import ExAws.Utils, only: [camelize: 1, camelize_keys: 1, camelize_keys: 2, upcase: 1]
alias __MODULE__
alias ExAws.Dynamo.{Decoder, Lazy}
alias ExAws.Operation.JSON

@nested_opts [:exclusive_start_key, :expression_attribute_values, :expression_attribute_names]
@upcase_opts [:return_values, :return_item_collection_metrics, :select, :total_segments]
Expand Down Expand Up @@ -125,8 +127,8 @@ defmodule ExAws.Dynamo do
|> Dynamo.decode_item(as: User)
```
"""
@spec decode_item(Map.t()) :: Map.t()
@spec decode_item(Map.t(), as: atom) :: Map.t()
@spec decode_item(map()) :: map()
@spec decode_item(map(), as: atom) :: map()
def decode_item(item, opts \\ [])

def decode_item(%{"Items" => items}, opts) do
Expand All @@ -138,12 +140,12 @@ defmodule ExAws.Dynamo do
end

def decode_item(item, opts) do
ExAws.Dynamo.Decoder.decode(item, opts)
Decoder.decode(item, opts)
end

@doc "List tables"
@spec list_tables() :: ExAws.Operation.JSON.t()
def list_tables() do
@spec list_tables() :: JSON.t()
def list_tables do
request(:list_tables, %{})
end

Expand All @@ -163,7 +165,7 @@ defmodule ExAws.Dynamo do
read_capacity :: pos_integer,
write_capacity :: pos_integer,
billing_mode :: dynamo_billing_types
) :: ExAws.Operation.JSON.t()
) :: JSON.t()
def create_table(
name,
primary_key,
Expand Down Expand Up @@ -252,10 +254,10 @@ defmodule ExAws.Dynamo do
key_definitions :: key_definitions,
read_capacity :: pos_integer,
write_capacity :: pos_integer,
global_indexes :: [Map.t()],
local_indexes :: [Map.t()],
global_indexes :: [map()],
local_indexes :: [map()],
billing_mode :: dynamo_billing_types
) :: ExAws.ExAws.Operation.JSON.t()
) :: JSON.t()
def create_table(
name,
key_schema,
Expand Down Expand Up @@ -303,7 +305,7 @@ defmodule ExAws.Dynamo do
read_capacity :: pos_integer,
write_capacity :: pos_integer,
billing_mode :: dynamo_billing_types
) :: Map.t()
) :: map()
defp build_billing_mode(read_capacity, write_capacity, :provisioned) do
%{
"BillingMode" => "PROVISIONED",
Expand All @@ -320,14 +322,14 @@ defmodule ExAws.Dynamo do
end

@doc "Describe table"
@spec describe_table(name :: binary) :: ExAws.Operation.JSON.t()
@spec describe_table(name :: binary) :: JSON.t()
def describe_table(name) do
request(:describe_table, %{"TableName" => name})
end

@doc "Update Table"
@spec update_table(name :: binary, attributes :: Keyword.t() | Map.t()) ::
ExAws.Operation.JSON.t()
@spec update_table(name :: binary, attributes :: Keyword.t() | map()) ::
JSON.t()
def update_table(name, attributes) do
data =
attributes
Expand All @@ -338,46 +340,46 @@ defmodule ExAws.Dynamo do
request(:update_table, data)
end

@spec maybe_convert_billing_mode(attributes :: Keyword.t() | Map.t()) :: Keyword.t() | Map.t()
@spec maybe_convert_billing_mode(attributes :: Keyword.t() | map()) :: Keyword.t() | map()
defp maybe_convert_billing_mode(attributes) do
case attributes[:billing_mode] do
nil -> attributes
_ -> convert_billing_mode(attributes, attributes[:billing_mode])
end
end

@spec convert_billing_mode(attributes :: Keyword.t() | Map.t(), dynamo_billing_types) ::
Keyword.t() | Map.t()
@spec convert_billing_mode(attributes :: Keyword.t() | map(), dynamo_billing_types) ::
Keyword.t() | map()
defp convert_billing_mode(attributes, :provisioned),
do: do_convert_billing_mode(attributes, "PROVISIONED")

defp convert_billing_mode(attributes, :pay_per_request),
do: do_convert_billing_mode(attributes, "PAY_PER_REQUEST")

@spec do_convert_billing_mode(attributes :: Keyword.t() | Map.t(), value :: String.t()) ::
Keyword.t() | Map.t()
@spec do_convert_billing_mode(attributes :: Keyword.t() | map(), value :: String.t()) ::
Keyword.t() | map()
defp do_convert_billing_mode(attributes, value) when is_map(attributes),
do: Map.replace!(attributes, :billing_mode, value)

defp do_convert_billing_mode(attributes, value) when is_list(attributes),
do: Keyword.replace!(attributes, :billing_mode, value)

@doc "Delete Table"
@spec delete_table(table :: binary) :: ExAws.Operation.JSON.t()
@spec delete_table(table :: binary) :: JSON.t()
def delete_table(table) do
request(:delete_table, %{"TableName" => table})
end

@doc "Update time to live"
@spec update_time_to_live(table :: binary, ttl_attribute :: binary, enabled :: boolean) ::
ExAws.Operation.JSON.t()
JSON.t()
def update_time_to_live(table, ttl_attribute, enabled) do
data = build_time_to_live(ttl_attribute, enabled) |> Map.merge(%{"TableName" => table})

request(:update_time_to_live, data)
end

@spec build_time_to_live(ttl_attribute :: binary, enabled :: boolean) :: Map.t()
@spec build_time_to_live(ttl_attribute :: binary, enabled :: boolean) :: map()
defp build_time_to_live("", _enabled) do
%{}
end
Expand All @@ -396,7 +398,7 @@ defmodule ExAws.Dynamo do
end

@doc "Describe time to live"
@spec describe_time_to_live(table :: binary) :: ExAws.Operation.JSON.t()
@spec describe_time_to_live(table :: binary) :: JSON.t()
def describe_time_to_live(table) do
request(:describe_time_to_live, %{"TableName" => table})
end
Expand Down Expand Up @@ -437,15 +439,15 @@ defmodule ExAws.Dynamo do
| {:select, select_vals}
| {:total_segments, pos_integer}
]
@spec scan(table_name :: table_name) :: ExAws.Operation.JSON.t()
@spec scan(table_name :: table_name, opts :: scan_opts) :: ExAws.Operation.JSON.t()
@spec scan(table_name :: table_name) :: JSON.t()
@spec scan(table_name :: table_name, opts :: scan_opts) :: JSON.t()
def scan(name, opts \\ []) do
data =
opts
|> build_opts()
|> Map.merge(%{"TableName" => name})

request(:scan, data, %{stream_builder: &ExAws.Dynamo.Lazy.stream_scan(name, opts, &1)})
request(:scan, data, %{stream_builder: &Lazy.stream_scan(name, opts, &1)})
end

@doc """
Expand Down Expand Up @@ -477,15 +479,15 @@ defmodule ExAws.Dynamo do
| {:scan_index_forward, boolean}
| {:select, select_vals}
]
@spec query(table_name :: table_name) :: ExAws.Operation.JSON.t()
@spec query(table_name :: table_name, opts :: query_opts) :: ExAws.Operation.JSON.t()
@spec query(table_name :: table_name) :: JSON.t()
@spec query(table_name :: table_name, opts :: query_opts) :: JSON.t()
def query(name, opts \\ []) do
data =
opts
|> build_opts()
|> Map.merge(%{"TableName" => name})

request(:query, data, %{stream_builder: &ExAws.Dynamo.Lazy.stream_query(name, opts, &1)})
request(:query, data, %{stream_builder: &Lazy.stream_query(name, opts, &1)})
end

@doc """
Expand Down Expand Up @@ -529,9 +531,9 @@ defmodule ExAws.Dynamo do
| {:expression_attribute_names, expression_attribute_names_vals}
| {:projection_expression, binary}
]
@spec batch_get_item(%{table_name => get_item}) :: ExAws.Operation.JSON.t()
@spec batch_get_item(%{table_name => get_item}) :: JSON.t()
@spec batch_get_item(%{table_name => get_item}, opts :: batch_get_item_opts) ::
ExAws.Operation.JSON.t()
JSON.t()
def batch_get_item(data, opts \\ []) do
request_items =
data
Expand Down Expand Up @@ -571,9 +573,9 @@ defmodule ExAws.Dynamo do
| {:return_item_collection_metrics, return_item_collection_metrics_vals}
| {:return_values, return_values_vals}
]
@spec put_item(table_name :: table_name, record :: map()) :: ExAws.Operation.JSON.t()
@spec put_item(table_name :: table_name, record :: map()) :: JSON.t()
@spec put_item(table_name :: table_name, record :: map(), opts :: put_item_opts) ::
ExAws.Operation.JSON.t()
JSON.t()
def put_item(name, record, opts \\ []) do
data =
opts
Expand Down Expand Up @@ -603,9 +605,9 @@ defmodule ExAws.Dynamo do
{:return_consumed_capacity, return_consumed_capacity_vals}
| {:return_item_collection_metrics, return_item_collection_metrics_vals}
]
@spec batch_write_item(%{table_name => [write_item]}) :: ExAws.Operation.JSON.t()
@spec batch_write_item(%{table_name => [write_item]}) :: JSON.t()
@spec batch_write_item(%{table_name => [write_item]}, opts :: batch_write_item_opts) ::
ExAws.Operation.JSON.t()
JSON.t()
def batch_write_item(data, opts \\ []) do
request_items =
data
Expand Down Expand Up @@ -638,9 +640,9 @@ defmodule ExAws.Dynamo do
| {:projection_expression, binary}
| {:return_consumed_capacity, return_consumed_capacity_vals}
]
@spec get_item(table_name :: table_name, primary_key :: primary_key) :: ExAws.Operation.JSON.t()
@spec get_item(table_name :: table_name, primary_key :: primary_key) :: JSON.t()
@spec get_item(table_name :: table_name, primary_key :: primary_key, opts :: get_item_opts) ::
ExAws.Operation.JSON.t()
JSON.t()
def get_item(name, primary_key, opts \\ []) do
data =
opts
Expand Down Expand Up @@ -672,7 +674,7 @@ defmodule ExAws.Dynamo do
table_name :: table_name,
primary_key :: primary_key,
opts :: update_item_opts
) :: ExAws.Operation.JSON.t()
) :: JSON.t()
def update_item(table_name, primary_key, update_opts) do
data =
update_opts
Expand All @@ -695,12 +697,12 @@ defmodule ExAws.Dynamo do
| {:return_values, return_values_vals}
]
@spec delete_item(table_name :: table_name, primary_key :: primary_key) ::
ExAws.Operation.JSON.t()
JSON.t()
@spec delete_item(
table_name :: table_name,
primary_key :: primary_key,
opts :: delete_item_opts
) :: ExAws.Operation.JSON.t()
) :: JSON.t()
def delete_item(name, primary_key, opts \\ []) do
data =
opts
Expand All @@ -727,8 +729,8 @@ defmodule ExAws.Dynamo do
]

@spec transact_get_items(items :: [transact_get_item], transact_get_items_opts) ::
ExAws.Operation.JSON.t()
@spec transact_get_items(items :: [transact_get_item]) :: ExAws.Operation.JSON.t()
JSON.t()
@spec transact_get_items(items :: [transact_get_item]) :: JSON.t()

@doc """
A synchronous operation that retrieves multiple items from one or more tables (but not from indexes) in a single account and region
Expand Down Expand Up @@ -801,8 +803,8 @@ defmodule ExAws.Dynamo do
A synchronous write operation that groups up to 25 action requests
"""
@spec transact_write_items(items :: [transact_write_item], transact_write_items_opts) ::
ExAws.Operation.JSON.t()
@spec transact_write_items(items :: [transact_write_item]) :: ExAws.Operation.JSON.t()
JSON.t()
@spec transact_write_items(items :: [transact_write_item]) :: JSON.t()
def transact_write_items(items, opts \\ []) do
data =
opts
Expand Down Expand Up @@ -896,7 +898,7 @@ defmodule ExAws.Dynamo do
|> Atom.to_string()
|> Macro.camelize()

ExAws.Operation.JSON.new(
JSON.new(
:dynamodb,
%{
data: data,
Expand Down
13 changes: 7 additions & 6 deletions lib/ex_aws/dynamo/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ defmodule ExAws.Dynamo.Decoder do
This is important for handling nested maps if you wanted the nested maps
to have atom keys.
"""

alias ExAws.Dynamo.Decodable

def decode(item, as: struct_module) do
item
|> decode
|> binary_map_to_struct(struct_module)
|> ExAws.Dynamo.Decodable.decode()
|> Decodable.decode()
end

@doc """
Expand Down Expand Up @@ -57,11 +60,9 @@ defmodule ExAws.Dynamo.Decoder do

@doc "Attempts to convert a number to a float, and then an integer"
def binary_to_number(binary) when is_binary(binary) do
try do
String.to_float(binary)
rescue
ArgumentError -> String.to_integer(binary)
end
String.to_float(binary)
rescue
ArgumentError -> String.to_integer(binary)
end

def binary_to_number(binary), do: binary
Expand Down
10 changes: 5 additions & 5 deletions lib/ex_aws/dynamo/encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ defmodule ExAws.Dynamo.Encoder do
This is handled via the ExAws.Dynamo.Encodable protocol.
"""

alias ExAws.Dynamo.Encodable

# These functions exist to ensure that encoding is idempotent.
def encode(value), do: encode(value, [])
def encode(%{"B" => _} = val, _), do: val
Expand All @@ -29,19 +31,17 @@ defmodule ExAws.Dynamo.Encoder do
def encode(%{"S" => _} = val, _), do: val
def encode(%{"SS" => _} = val, _), do: val

def encode(value, options) do
ExAws.Dynamo.Encodable.encode(value, options)
end
def encode(value, options), do: Encodable.encode(value, options)

# Use this in case you want to encode something already in Dynamo format
# for some reason I cannot fathom. If you find yourself using this, please open an issue
# so I can find out why and better support this.
def encode!(value, options \\ []) do
ExAws.Dynamo.Encodable.encode(value, options)
Encodable.encode(value, options)
end

def encode_root(value, options \\ []) do
case ExAws.Dynamo.Encodable.encode(value, options) do
case Encodable.encode(value, options) do
%{"M" => value} -> value
%{"L" => value} -> value
end
Expand Down
Loading

0 comments on commit 32a3be3

Please sign in to comment.