-
-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Apply custom validation to filters #267
Comments
I don't feel like this should be part of the library. Could you solve your problem similar to this? def list_pets(%{} = args) do
with {:ok, flop} <- Flop.validate(args, for: Pet),
{:ok, flop} <- custom_validation(flop) do
Flop.run(Pet, flop, for: Pet)
end
end
defp custom_validation(%Flop{} = flop) do
# retrieve filter values
if whatever do
{:ok, flop}
else
# build meta struct with error
{:error, meta_with_error}
end
end #253 is about adding some functions for retrieving and manipulating filters in a Flop struct, which should make this scenario fairly easy to implement. I could also imagine an |
Agreed, if there would be an ergonomic way to retrieve the values and add custom errors to the flop, I'd be fine doing it like that. How would |
I need to think about the ergonomics of the |
I've added a couple of functions to find filters for a field. If you have a list function like this: def list_pets(%{} = args) do
opts = [for: Pet]
with {:ok, flop} <- Flop.validate(args, opts),
{:ok, flop} <- custom_validation(flop, params, opts) do
Flop.run(Pet, flop, for: Pet)
end
end You could implement the custom validation function similar to this: defp custom_validation(%Flop{} = flop, %{} = args, opts) do
%{value: one} = Flop.Filter.get(flop.filters, :field_one)
%{value: two} = Flop.Filter.get(flop.filters, :field_two)
if one > two do
{:ok, flop}
else
meta = %Meta{
errors: [filters: ["is invalid"]],
# convert_params/1 would have to be made public
params: convert_params(params),
schema: opts[:for]
}
{:error, meta}
end
end In this version, the errors need to be set as a keyword list. Alternatively, I could imagine a @spec validate_with(Flop.t() | map, function, [option()]) :: {:ok, Flop.t()} | {:error, Meta.t()} Basically the same as Now your list function would look like this: def list_pets(%{} = args) do
with {:ok, flop} <- Flop.validate_with(args, &custom_validation/1, for: Pet) do
Flop.run(Pet, flop, for: Pet)
end
end The custom validation function needs to take and return an Ecto changeset in this case: defp custom_validation(%Ecto.Changeset{} = changeset) do
filters = Ecto.Changeset.fetch_field!(changeset, :filters)
%{value: one} = Flop.Filter.get(filters, :field_one)
%{value: two} = Flop.Filter.get(filters, :field_two)
if one > two do
changeset
else
Ecto.Changeset.add_error(changeset, :filters, "is invalid")
end
end This has the advantage that a) you don't need to know how to build a Meta struct with errors and can just use changeset functions for validations, and b) the default and custom validation is running in one step, so you'll see all the errors at once, and not _eitherv the default validation errors or the custom errors. In both examples, the validation error is just added to the |
I added the function |
Very cool, I'm eager to try it out! |
Is your feature request related to a problem? Please describe.
I would love to replace some custom code with Flop and Flop Phoenix but:
I need the ability to add custom validations to filters and across filters, i.e. validation functions may depend on the values of multiple filters.
Describe the solution you'd like
A key like
that one may add to the
opts
argument ofFlop.validate
orFlop.validate_and_run
.Alternatively every validation function could also just always be called with a map of
and one matches on the wanted values.
Describe alternatives you've considered
I could not use Flop. :(
Additional context
I'm willing to sketch a PR out if you agree that something along those lines would be a nice addition.
The text was updated successfully, but these errors were encountered: