Skip to content

Commit

Permalink
Support for sums-of-types in the DSL
Browse files Browse the repository at this point in the history
  • Loading branch information
solnic committed Oct 14, 2023
1 parent 255c1bd commit 3d3b967
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 1 deletion.
3 changes: 3 additions & 0 deletions lib/drops/contract.ex
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ defmodule Drops.Contract do
{:error, error_list} ->
collapse_errors(error_list)

{:or, {left_errors, right_errors}} ->
{:or, {collapse_errors(left_errors), collapse_errors(right_errors)}}

result ->
result
end)
Expand Down
8 changes: 8 additions & 0 deletions lib/drops/types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ defmodule Drops.Types do
Map.Key
}

def from_spec(%{primitive: _} = type, _opts) do
type
end

def from_spec(%{} = spec, opts) do
atomize = opts[:atomize] || false

Expand Down Expand Up @@ -55,6 +59,10 @@ defmodule Drops.Types do
}
end

def from_spec([left, right], opts) when is_tuple(left) and is_tuple(right) do
%Sum{left: from_spec(left, opts), right: from_spec(right, opts), opts: opts}
end

def from_spec([left, right], opts) do
%Sum{left: left, right: right, opts: opts}
end
Expand Down
2 changes: 1 addition & 1 deletion lib/drops/validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ defmodule Drops.Validator do

if length(errors) == 0,
do: {:ok, {path, result}},
else: errors
else: {:error, errors}

error ->
error
Expand Down
67 changes: 67 additions & 0 deletions test/contract/schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,73 @@ defmodule Drops.Contract.SchemaTest do
end
end

describe "sum of lists" do
contract do
schema do
%{
required(:values) => [
list(:string),
list(:integer)
]
}
end
end

test "returns success when either of the lists passed", %{contract: contract} do
assert {:ok, %{values: ["hello", "world"]}} =
contract.conform(%{values: ["hello", "world"]})

assert {:ok, %{values: [1, 2]}} = contract.conform(%{values: [1, 2]})
end

test "returns error when both cases didn't pass", %{contract: contract} do
assert {:error,
[
or:
{{:error, [error: {[:values, 0], :type?, [:string, 1]}]},
{:error, [error: {[:values, 1], :type?, [:integer, "hello"]}]}}
]} =
contract.conform(%{values: [1, "hello"]})
end
end

describe "sum of list of schemas" do
contract do
schema(:left) do
%{required(:name) => string()}
end

schema(:right) do
%{required(:login) => string()}
end

schema do
%{
required(:values) => [list(@schemas.left), list(@schemas.right)]
}
end
end

test "returns success when either of cases passed", %{contract: contract} do
assert {:ok, %{values: [%{name: "John Doe"}]}} =
contract.conform(%{values: [%{name: "John Doe"}]})

assert {:ok, %{values: [%{login: "john"}]}} =
contract.conform(%{values: [%{login: "john"}]})
end

test "returns error when both cases didn't pass", %{contract: contract} do
assert {:error,
[
or:
{{:error,
[error: [error: {[:values, 0, :name], :type?, [:string, 1]}]]},
{:error, [error: [error: {[:values, 0], :has_key?, [:login]}]]}}
]} =
contract.conform(%{values: [%{name: 1}]})
end
end

describe "sum of schemas" do
contract do
schema(:left) do
Expand Down

0 comments on commit 3d3b967

Please sign in to comment.