diff --git a/lib/open_api_spex/cast/integer.ex b/lib/open_api_spex/cast/integer.ex index 7f768f2b..fe3c3399 100644 --- a/lib/open_api_spex/cast/integer.ex +++ b/lib/open_api_spex/cast/integer.ex @@ -21,6 +21,16 @@ defmodule OpenApiSpex.Cast.Integer do end end + if Code.ensure_loaded?(Decimal) do + def cast(%{value: %Decimal{} = value} = ctx) do + if Decimal.integer?(value) do + cast(%{ctx | value: Decimal.to_string(value)}) + else + Cast.error(ctx, {:invalid_type, :integer}) + end + end + end + def cast(ctx) do Cast.error(ctx, {:invalid_type, :integer}) end diff --git a/lib/open_api_spex/cast/number.ex b/lib/open_api_spex/cast/number.ex index 9fbadd11..b445516f 100644 --- a/lib/open_api_spex/cast/number.ex +++ b/lib/open_api_spex/cast/number.ex @@ -24,6 +24,12 @@ defmodule OpenApiSpex.Cast.Number do end end + if Code.ensure_loaded?(Decimal) do + def cast(%{value: %Decimal{} = value} = ctx) do + cast(%{ctx | value: Decimal.to_string(value)}) + end + end + def cast(ctx) do Cast.error(ctx, {:invalid_type, :number}) end diff --git a/mix.exs b/mix.exs index dbb1c193..6cc36aad 100644 --- a/mix.exs +++ b/mix.exs @@ -67,6 +67,7 @@ defmodule OpenApiSpex.Mixfile do {:dialyxir, "~> 1.0", only: [:dev], runtime: false}, {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:jason, "~> 1.0", optional: true}, + {:decimal, "~> 1.0 or ~> 2.0", optional: true}, {:phoenix, "~> 1.3", only: [:dev, :test]}, {:plug, "~> 1.7"}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", optional: true}, diff --git a/mix.lock b/mix.lock index 05c04d38..605a5da4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,7 @@ %{ "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, + "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, diff --git a/test/cast/integer_test.exs b/test/cast/integer_test.exs index 55cab47f..f4ca5e01 100644 --- a/test/cast/integer_test.exs +++ b/test/cast/integer_test.exs @@ -18,6 +18,17 @@ defmodule OpenApiSpex.CastIntegerTest do assert %Error{reason: :invalid_type, value: "other"} = error end + test "with a Decimal" do + schema = %Schema{type: :integer} + + assert {:ok, 1} = cast(value: Decimal.new(1), schema: schema) + + number = Decimal.new("1.2") + + assert {:error, [%{reason: :invalid_type, value: ^number}]} = + cast(value: number, schema: schema) + end + test "with multiple of" do schema = %Schema{type: :integer, multipleOf: 2} assert cast(value: 2, schema: schema) == {:ok, 2} diff --git a/test/cast/number_test.exs b/test/cast/number_test.exs index 3568432a..bb28edb5 100644 --- a/test/cast/number_test.exs +++ b/test/cast/number_test.exs @@ -17,6 +17,19 @@ defmodule OpenApiSpex.CastNumberTest do assert error.value == "other" end + test "with a Decimal" do + schema = %Schema{type: :number} + + assert cast(value: Decimal.new("1.2345"), schema: schema) === {:ok, 1.2345} + + schema = %Schema{type: :number, minimum: 2} + assert cast(value: Decimal.new("3"), schema: schema) === {:ok, 3.0} + assert cast(value: Decimal.new("2"), schema: schema) === {:ok, 2.0} + + assert {:error, [%{reason: :minimum, value: 1.0}]} = + cast(value: Decimal.new("1"), schema: schema) + end + test "with minimum" do schema = %Schema{type: :number, minimum: 2} assert cast(value: 3, schema: schema) === {:ok, 3.0}