defmodule ExAws.Dynamo.Encoder do
@moduledoc """
Takes an Elixir value and converts it into a Dynamo-style map.
```elixir
MapSet.new [1,2,3] |> #{__MODULE__}.encode
#=> %{"NS" => ["1", "2", "3"]}
MapSet.new ["A","B","C"] |> #{__MODULE__}.encode
#=> %{"SS" => ["A", "B", "C"]}
"bubba" |> ExAws.Dynamo.Encoder.encode
#=> %{"S" => "bubba"}
```
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
def encode(%{"BOOL" => _} = val, _), do: val
def encode(%{"BS" => _} = val, _), do: val
def encode(%{"L" => _} = val, _), do: val
def encode(%{"M" => _} = val, _), do: val
def encode(%{"NS" => _} = val, _), do: val
def encode(%{"NULL" => _} = val, _), do: val
def encode(%{"N" => _} = val, _), do: val
def encode(%{"S" => _} = val, _), do: val
def encode(%{"SS" => _} = val, _), do: val
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
Encodable.encode(value, options)
end
def encode_root(value, options \\ []) do
case Encodable.encode(value, options) do
%{"M" => value} -> value
%{"L" => value} -> value
end
end
def atom_to_dynamo_type(:blob), do: "B"
def atom_to_dynamo_type(:boolean), do: "BOOL"
def atom_to_dynamo_type(:blob_set), do: "BS"
def atom_to_dynamo_type(:list), do: "L"
def atom_to_dynamo_type(:map), do: "M"
def atom_to_dynamo_type(:number_set), do: "NS"
def atom_to_dynamo_type(:null), do: "NULL"
def atom_to_dynamo_type(:number), do: "N"
def atom_to_dynamo_type(:string), do: "S"
def atom_to_dynamo_type(:string_set), do: "SS"
def atom_to_dynamo_type(value) do
raise ArgumentError, "Unknown dynamo type for value: #{inspect(value)}"
end
end