lib/ash_thrift.ex

defmodule AshThrift do
  defmodule Namespace do
    @type t :: %__MODULE__{
            language: atom(),
            name: String.t()
          }

    defstruct [:language, :name]
  end

  defmodule Field do
    @type t :: %__MODULE__{
            id: non_neg_integer(),
            attribute: atom(),
            optional: boolean()
          }

    defstruct [:id, :attribute, :optional]
  end

  defmodule Struct do
    @type t :: %__MODULE__{
            name: String.t(),
            fields: Field.t()
          }

    defstruct [:name, :fields]
  end

  @doc """
  Builds an Ash resource from a thrift struct
  """
  @spec into(
          data :: map(),
          resource :: module(),
          variant :: String.t(),
          dest :: map()
        ) :: term()
  def into(data, resource, variant, dest \\ nil)

  def into(data, resource, variant, nil),
    do: into(data, resource, variant, struct(resource))

  def into(data, resource, variant, dest) do
    Spark.Dsl.Extension.get_persisted(resource, :thrift, %{})
    |> Map.get(variant, [])
    |> Enum.reduce(dest, fn {_field,
                             %Ash.Resource.Attribute{
                               name: name,
                               type: type
                             }},
                            acc ->
      value = AshThrift.Conversion.parse(type, Map.get(data, name))
      Map.put(acc, name, value)
    end)
  end

  @doc """
  Dumps an Ash resource to a thrift struct
  """
  @spec dump(resource :: struct(), variant :: String.t(), thrift_struct :: map()) :: struct()
  def dump(resource, variant, dest \\ %{}) do
    Spark.Dsl.Extension.get_persisted(resource.__struct__, :thrift, %{})
    |> Map.get(variant, [])
    |> Enum.reduce(dest, fn {_field,
                             %Ash.Resource.Attribute{
                               name: name,
                               type: type
                             }},
                            acc ->
      value = AshThrift.Conversion.value(type, Map.get(resource, name))
      Map.put(acc, name, value)
    end)
  end
end