Hello @egze thanks for the and sorry for the late response.
The JSON-Editor could be a good example to show how xema
works together with phoenix-forms.
At the moment I have no idea for the form but a simplified first approach for the schema could be:
defmodule Form do
use Xema
@str map(properties: %{t: [const: "str"], v: :string})
@int map(properties: %{t: [const: "int"], v: :integer})
@obj map(
properties: %{
t: [const: "obj"],
v:
map(
property_names: string(min_length: 1),
pattern_properties: %{".*" => ref("#")}
)
}
)
@arr list(items: ref("#"))
xema do
one_of([@str, @int, @arr, @obj])
end
end
That would work for:
iex> Form.valid?(%{t: "str", v: "Hinz"})
true
iex> Form.valid?(%{
t: "obj",
v: %{
foo: %{t: "int", v: 55},
bar: [%{t: "str", v: "Hinz"}, %{t: "str", v: "Kunz"}]
}
})
In case of invalid data the error reason is a little bit hard to handle.
iex> Form.validate(%{
t: "obj",
v: %{
foo: %{t: "int", v: 55},
bar: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}]
}
})
{:error,
%Xema.ValidationError{
message: nil,
reason: %{
one_of: {:error,
[
%{
properties: %{
t: %{const: "str", value: "obj"},
v: %{
type: :string,
value: %{bar: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}], foo: %{t: "int", v: 55}}
}
}
},
%{
properties: %{
t: %{const: "int", value: "obj"},
v: %{
type: :integer,
value: %{bar: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}], foo: %{t: "int", v: 55}}
}
}
},
%{
type: :list,
value: %{
t: "obj",
v: %{bar: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}], foo: %{t: "int", v: 55}}
}
},
%{
properties: %{
v: %{
properties: %{
bar: %{
one_of: {:error,
[
%{type: :map, value: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}]},
%{type: :map, value: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}]},
%{
items: %{
1 => %{
one_of: {:error,
[
%{properties: %{v: %{type: :string, value: 88}}},
%{properties: %{t: %{const: "int", value: "str"}}},
%{type: :list, value: %{t: "str", v: 88}},
%{
properties: %{
t: %{const: "obj", value: "str"},
v: %{type: :map, value: 88}
}
}
]},
value: %{t: "str", v: 88}
}
}
},
%{type: :map, value: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}]}
]},
value: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}]
}
}
}
}
}
]},
value: %{
t: "obj",
v: %{bar: [%{t: "str", v: "Hinz"}, %{t: "str", v: 88}], foo: %{t: "int", v: 55}}
}
}
}}
I think this could be improved in xema
.