lib/ecto_adapters_dynamodb/dynamodbset.ex

defmodule Ecto.Adapters.DynamoDB.DynamoDBSet do
  @moduledoc """
  An Ecto type for handling MapSet, corresponding with DynamoDB's **set** types. Since ExAws
  already encodes and decodes MapSet, we only handle casting and validation here.
  """

  @behaviour Ecto.Type

  @doc """
  This type is actually a MapSet
  """
  @impl Ecto.Type
  def type, do: MapSet

  @doc """
  Confirm the type is a MapSet and its elements are of one type, number or binary
  """
  @impl Ecto.Type
  def cast(mapset) do
    case mapset do
      %MapSet{} -> if valid?(mapset), do: {:ok, mapset}, else: :error
      _ -> :error
    end
  end

  @doc """
  Load as is
  """
  @impl Ecto.Type
  def load(mapset), do: {:ok, mapset}

  @doc """
  Dump as is
  """
  @impl Ecto.Type
  def dump(mapset), do: {:ok, mapset}

  @doc """
  Check if two terms are semantically equal
  """
  @impl Ecto.Type
  def equal?(%MapSet{} = term_a, %MapSet{} = term_b), do: MapSet.equal?(term_a, term_b)
  def equal?(nil, %MapSet{}), do: false
  def equal?(%MapSet{}, nil), do: false
  def equal?(nil, nil), do: true

  @doc """
  Dictates how the type should be treated inside embeds
  """
  @impl Ecto.Type
  def embed_as(_), do: :self

  defp valid?(mapset) do
    Enum.all?(mapset, fn x -> is_number(x) end) or
      Enum.all?(mapset, fn x -> is_binary(x) end)
  end
end