Adzz / data_schema

Declarative schemas for data transformations.
Apache License 2.0
85 stars 9 forks source link

Add some more better Error functions - extract_errors / traverse_errors etc #3

Closed Adzz closed 1 year ago

Adzz commented 2 years ago

We return errors from casting it would be good to add functions on that struct that extract all the errors needed - or traverse them giving the user a chance to do something with all the errors like concat them into a string or whatever.

ayrat555 commented 2 years ago

@Adzz hey. yes, this feature would be great to have. Currently, the library returns an error without a meaningful descriptions (which field/value failed)

Adzz commented 2 years ago

@ayrat555 Thanks, this issue was originally about adding some extra functions to help handle errors, but you prompted me to look and I actually thought errors were being handled better! Right now only "non null" errors have an indication of what went wrong.

This PR https://github.com/Adzz/data_schema/pull/21 has now fixed that. If you return an error from a casting function we will now return a (possibly nested) DataSchema.Errors struct. You can then see the specific field by traversing errors, try the example below:

  defmodule Author do
    import DataSchema, only: [data_schema: 1]
    data_schema(
      field: {:name, "name", fn _ -> :error  end}
    )
  end

  defmodule Comment do
    import DataSchema, only: [data_schema: 1]
    data_schema(
      has_one: {:author, "author", Author}
    )
  end

  defmodule BlagPost do
    import DataSchema, only: [data_schema: 1]

    data_schema(
      field: {:content, "content", &{:ok, to_string(&1)}},
      has_many: {:comments, "comments", Comment},
    )
  end

input = %{
  "content" => "This is a blog post",
  "comments" => [
    %{"author" => %{"name" => "Ted"} }, 
    %{"author" => %{"name" => "Danson"} }
  ]
}
DataSchema.to_struct(input, BlagPost)

Returns

{:error,
 %DataSchema.Errors{
   errors: [
     comments: %DataSchema.Errors{
       errors: [
         author: %DataSchema.Errors{errors: [name: "There was an error!"]}
       ]
     }
   ]
 }}

Pushing a release with that fix now.

ayrat555 commented 2 years ago

thank you!

Adzz commented 2 years ago

Latest version also adds DataSchema.Errors.to_error_tuple/1 which will take this:

 %DataSchema.Errors{
   errors: [
     comments: %DataSchema.Errors{
       errors: [
         author: %DataSchema.Errors{errors: [name: "There was an error!"]}
       ]
     }
   ]
 }

and turn it into:

{:error, {[:comments, :author, :name], "There was an error!}}

and DataSchema.Errors.flatten_errors which will take the same and return

{[:comments, :author, :name], "There was an error!}