Skip to content

Commit d58c222

Browse files
committed
Include tests around nested selections
1 parent 162906c commit d58c222

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

lib/norm.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ defmodule Norm do
512512
in the selection are still considered optional. Selections, like schemas,
513513
are open and allow unspecied keys to be passed through. If no selectors are
514514
provided then `selection` defaults to `:all` and recursively marks all keys in
515-
all schema's as required.
515+
all nested schema's. If the schema includes internal selections these selections
516+
will not be overwritten.
516517
517518
## Examples
518519

lib/norm/spec/selection.ex

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,28 @@ defmodule Norm.Spec.Selection do
5151
defp validate_selectors!([_key | rest]), do: validate_selectors!(rest)
5252
defp validate_selectors!(other), do: raise ArgumentError, "select expects a list of keys but received: #{inspect other}"
5353

54-
defp assert_spec!(schema, key) do
54+
defp assert_spec!(%Schema{}=schema, key) do
5555
case Schema.spec(schema, key) do
5656
nil -> raise SpecError, {:selection, key, schema}
5757
spec -> spec
5858
end
5959
end
60+
defp assert_spec!(%__MODULE__{}, _key) do
61+
# In the future we might support this and allow users to overwrite internal
62+
# selections. But for now its safer to forbid this.
63+
raise ArgumentError, """
64+
Attempting to specify a selection on top of another selection is
65+
not allowed.
66+
"""
67+
end
68+
defp assert_spec!(other, _key) do
69+
raise ArgumentError, "Expected a schema and got: #{inspect other}"
70+
end
6071

6172
defimpl Norm.Conformer.Conformable do
6273
alias Norm.Conformer
6374
alias Norm.Conformer.Conformable
6475

65-
# def conform(_, input, path) when not is_map(input) do
66-
# {:error, [Conformer.error(path, input, "not a map")]}
67-
# end
68-
6976
def conform(%{required: required, schema: schema}, input, path) do
7077
with {:ok, conformed} <- Conformable.conform(schema, input, path) do
7178
errors = ensure_keys(required, conformed, path, [])

test/norm/selection_test.exs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,25 @@ defmodule Norm.SelectionTest do
3737
assert errors == [%{spec: ":required", input: %{fauxuser: %{age: 31}}, path: [:user]}]
3838
end
3939

40+
test "works with nested selections" do
41+
user_with_name = schema(%{user: selection(user_schema(), [:name])})
42+
input = %{name: "chris"}
43+
assert %{user: input} == conform!(%{user: input}, selection(user_with_name))
44+
45+
assert_raise ArgumentError, fn ->
46+
user = schema(%{name: spec(is_binary()), age: spec(is_integer())})
47+
required_user = selection(user)
48+
selection(schema(%{user: required_user}), [user: [:name]])
49+
end
50+
end
51+
52+
test "returns an error if a non map input is given" do
53+
assert {:error, errors} = conform(123, selection(user_schema()))
54+
assert errors == [
55+
%{input: 123, path: [], spec: "not a map"}
56+
]
57+
end
58+
4059
test "if no keys are selected all keys are enforced recursively" do
4160
assert valid?(@input, selection(user_schema()))
4261
refute valid?(%{}, selection(user_schema()))

0 commit comments

Comments
 (0)