Skip to content

Commit

Permalink
Support custom caster modules
Browse files Browse the repository at this point in the history
  • Loading branch information
solnic committed Sep 21, 2023
1 parent 83a2097 commit 4b7d5a8
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 9 deletions.
6 changes: 4 additions & 2 deletions lib/drops/contract.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ defmodule Drops.Contract do
def step(
data,
{:validate,
%{type: {:cast, {{input_type, input_predicates}, output_type}}} = key}
%{type: {:cast, {{input_type, input_predicates, cast_opts}, output_type}}} =
key}
) do
value = get_in(data, key.path)
caster = cast_opts[:caster] || Casters

case apply_predicates(value, input_predicates, path: key.path) do
{:ok, _} ->
validate(
Casters.cast(input_type, output_type, value),
caster.cast(input_type, output_type, value),
key.predicates,
path: key.path
)
Expand Down
8 changes: 4 additions & 4 deletions lib/drops/contract/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ defmodule Drops.Contract.DSL do
{:optional, name}
end

def from(type) do
{:cast, type}
def from(type, cast_opts \\ []) do
{:cast, {type, cast_opts}}
end

def type([list: members]) when is_map(members) do
Expand All @@ -35,7 +35,7 @@ defmodule Drops.Contract.DSL do
{:type, {type, predicates}}
end

def type({:cast, input_type}, output_type) do
{:cast, {type(input_type), type(output_type)}}
def type({:cast, {input_type, cast_opts}}, output_type) do
{:cast, {type(input_type), type(output_type), cast_opts}}
end
end
6 changes: 3 additions & 3 deletions lib/drops/contract/schema/key.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ defmodule Drops.Contract.Schema.Key do
Enum.map(spec, &infer_type(&1, opts))
end

defp infer_type({:cast, {input_type, output_type}}, opts) do
defp infer_type({:cast, {input_type, output_type, cast_opts}}, opts) do
{:cast,
{{infer_type(input_type, opts), infer_predicates(input_type, opts)},
{{infer_type(input_type, opts), infer_predicates(input_type, opts), cast_opts},
infer_type(output_type, opts)}}
end

defp infer_predicates({:cast, {_input_type, output_type}}, opts) do
defp infer_predicates({:cast, {_input_type, output_type, _cast_opts}}, opts) do
infer_predicates(output_type, opts)
end

Expand Down
18 changes: 18 additions & 0 deletions test/contract/casters_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,22 @@ defmodule Drops.CastersTest do
assert {:ok, %{test: 31.2}} = contract.conform(%{test: "31.2"})
end
end

describe "using a customer caster" do
contract do
defmodule CustomCaster do
def cast(:string, :string, value) do
String.downcase(value)
end
end

schema do
%{required(:test) => from(:string, caster: CustomCaster) |> type(:string)}
end
end

test "defining a required key with coercion", %{contract: contract} do
assert {:ok, %{test: "hello"}} = contract.conform(%{test: "HELLO"})
end
end
end

0 comments on commit 4b7d5a8

Please sign in to comment.