diff --git a/.gitignore b/.gitignore index faa7a0e..ddd5b4a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,6 @@ erl_crash.dump hex.config *.ez uof_messages-*.tar -*~ \ No newline at end of file +*~ +\#* +.\#* \ No newline at end of file diff --git a/lib/uof/api/descriptions.ex b/lib/uof/api/descriptions.ex index 72f0cb0..a1c91b2 100644 --- a/lib/uof/api/descriptions.ex +++ b/lib/uof/api/descriptions.ex @@ -1,16 +1,6 @@ defmodule UOF.API.Descriptions do alias UOF.API.Utils.HTTP - @doc """ - Describe all currently available markets. - """ - def markets(lang \\ "en") do - # TO-DO: Optional mappings - endpoint = ["descriptions", lang, "markets.xml"] - - HTTP.get(%UOF.API.Mappings.MarketDescriptions{}, endpoint) - end - @doc """ Get a list of all variants and which markets they are used for. """ diff --git a/lib/uof/api/descriptions/market.ex b/lib/uof/api/descriptions/market.ex new file mode 100644 index 0000000..75f6e73 --- /dev/null +++ b/lib/uof/api/descriptions/market.ex @@ -0,0 +1,148 @@ +defmodule UOF.API.Descriptions.Market do + @moduledoc """ + """ + use Ecto.Schema + import Ecto.Changeset + import UOF.API.EctoHelpers + + @doc """ + List all supported markets. + """ + @spec all(include_mappings? :: boolean(), lang :: String.t()) :: list(Market.t()) + def all(include_mappings? \\ false, lang \\ "en") do + case UOF.API.get("/descriptions/#{lang}/markets.xml", + query: [include_mappings: include_mappings?] + ) do + {:ok, %_{status: 200, body: resp}} -> + resp + |> Map.get("market_descriptions") + |> Map.get("market") + + # |> Enum.map(fn x -> + # {:ok, x} = changeset(x) + # x + # end) + + {:error, _} = error -> + error + end + end + + defmodule Outcome do + @moduledoc false + use Ecto.Schema + import Ecto.Changeset + import UOF.API.EctoHelpers + + @primary_key false + + embedded_schema do + field(:id, :integer) + field(:name, :string) + end + + def changeset(model \\ %__MODULE__{}, params) do + cast(model, prepare(params), [:id, :name]) + end + + defp prepare(params) do + params + |> rename_fields + end + end + + defmodule Specifier do + @moduledoc false + use Ecto.Schema + import Ecto.Changeset + import UOF.API.EctoHelpers + + @primary_key false + + embedded_schema do + # ["decimal", "integer", "string", "variable_text"] + field(:type, :string) + field(:name, :string) + end + + def changeset(model \\ %__MODULE__{}, params) do + cast(model, prepare(params), [:name, :type]) + end + + defp prepare(params) do + params + |> rename_fields + end + end + + @primary_key false + + embedded_schema do + field(:id, :integer) + field(:name, :string) + field(:groups, {:array, :string}) + # ["player", "competitor", "free_text"] + field(:outcome_type, :string) + field(:includes_outcomes_of_type, :string) + embeds_many(:outcomes, Outcome) + embeds_many(:specifiers, Specifier) + # TO-DO: embeds_many(:mappings, Mapping) + end + + def changeset(model \\ %__MODULE__{}, params) do + model + |> cast(prepare(params), [:id, :name, :groups, :outcome_type, :includes_outcomes_of_type]) + |> cast_embed(:outcomes) + |> cast_embed(:specifiers) + |> case do + %Ecto.Changeset{valid?: true} = changeset -> + {:ok, apply_changes(changeset)} + + %Ecto.Changeset{} = changeset -> + {:error, {params, traverse_errors(changeset)}} + end + end + + defp prepare(params) do + params + |> rename_fields + |> prepare_outcomes + |> prepare_specifiers + |> split_groups + end + + defp prepare_outcomes(params) do + outcomes = + params + |> Map.get("outcomes", %{}) + |> Map.get("outcome", []) + + case outcomes do + outcome when not is_list(outcome) -> + Map.put(params, "outcomes", [outcome]) + + _ -> + Map.put(params, "outcomes", outcomes) + end + end + + defp prepare_specifiers(params) do + specifiers = + params + |> Map.get("specifiers", %{}) + |> Map.get("specifier", []) + + case specifiers do + specifier when not is_list(specifier) -> + Map.put(params, "specifiers", [specifier]) + + _ -> + Map.put(params, "specifiers", specifiers) + end + end + + defp split_groups(params) do + scope = String.split(params["groups"], "|") + Map.put(params, "groups", scope) + end +end diff --git a/lib/uof/api/mappings/market.ex b/lib/uof/api/mappings/market.ex deleted file mode 100644 index 1c8c809..0000000 --- a/lib/uof/api/mappings/market.ex +++ /dev/null @@ -1,15 +0,0 @@ -defmodule UOF.API.Mappings.Market do - @moduledoc false - use Saxaboom.Mapper - - alias UOF.API.Mappings.{Outcome, Specifier} - - document do - attribute(:id, cast: :integer) - attribute(:name) - attribute(:groups) - # attribute :outcome_type, as: :market.outcome_type - elements(:outcome, as: :outcomes, into: %Outcome{}) - elements(:specifier, as: :specifiers, into: %Specifier{}) - end -end diff --git a/lib/uof/api/mappings/market_descriptions.ex b/lib/uof/api/mappings/market_descriptions.ex deleted file mode 100644 index 8587002..0000000 --- a/lib/uof/api/mappings/market_descriptions.ex +++ /dev/null @@ -1,10 +0,0 @@ -defmodule UOF.API.Mappings.MarketDescriptions do - @moduledoc false - use Saxaboom.Mapper - - alias UOF.API.Mappings.Market - - document do - elements(:market, as: :markets, into: %Market{}) - end -end diff --git a/test/uof/api/descriptions/market_test.exs b/test/uof/api/descriptions/market_test.exs new file mode 100644 index 0000000..7370254 --- /dev/null +++ b/test/uof/api/descriptions/market_test.exs @@ -0,0 +1,25 @@ +defmodule UOF.API.Descriptions.Market.Test do + use ExUnit.Case + + setup do + :ok = Application.put_env(:tesla, UOF.API, adapter: Tesla.Mock) + + Tesla.Mock.mock(fn + %{method: :get} -> + resp = File.read!("test/data/markets.xml") + %Tesla.Env{status: 200, headers: [{"content-type", "application/xml"}], body: resp} + end) + + :ok + end + + test "can parse UOF.API.Descriptions.Market.all/0 response" do + resp = UOF.API.Descriptions.Market.all() + + assert Enum.count(resp) == 1172 + assert hd(resp).id == 282 + assert hd(resp).name == "Innings 1 to 5th top - {$competitor1} total" + assert hd(resp).groups == ["all", "score", "4.5_innings"] + assert Enum.map(hd(resp).outcomes, & &1.id) == [13, 12] + end +end diff --git a/test/uof/api/descriptions_test.exs b/test/uof/api/descriptions_test.exs index 4402643..4ce888b 100644 --- a/test/uof/api/descriptions_test.exs +++ b/test/uof/api/descriptions_test.exs @@ -15,18 +15,6 @@ defmodule UOF.API.Descriptions.Test do :ok end - test "can parse UOF.API.Descriptions.markets/{0, 1} response" do - {:ok, desc} = UOF.API.Descriptions.markets() - - market = hd(desc.markets) - - assert Enum.count(desc.markets) == 1172 - assert market.id == 282 - assert market.name == "Innings 1 to 5th top - {$competitor1} total" - assert market.groups == "all|score|4.5_innings" - assert Enum.map(market.outcomes, & &1.id) == ["13", "12"] - end - test "can parse UOF.API.Descriptions.variants/{0, 1} response" do {:ok, desc} = UOF.API.Descriptions.variants()