EctoMorph v0.1.10 EctoMorph View Source
Utility functions for Ecto related stuff and things. Check out the functions docs to see what is available.
Link to this section Summary
Functions
Returns a map of all of the schema fields contained within data
Casts the given data into a changeset according to the types defined by the given schema. It ignores any fields in data that are not defined in the schema, and recursively casts any embedded fields to a changeset also. Accepts a different struct as the first argument, calling Map.to_struct on it first.
Takes in a map of data and creates a changeset out of it by casting the data recursively, according to the whitelist of fields in fields. The map of data may be a struct, and the fields whitelist can whitelist fields of nested relations by providing a list for them as well.
Take a changeset and returns a struct if there are no errors on the changeset. Returns an error tuple with the invalid changeset otherwise.
Creates a map out of the Ecto struct, removing the internal ecto fields. Optionally you can remove the inserted_at and updated_at timestamp fields also by passing in :exclude_timestamps as an option
Takes some data and tries to convert it to a struct in the shape of the given schema. Casts values to the types defined by the schema dynamically using ecto changesets.
Link to this section Functions
filter_by_schema_fields(data, schema) View Source
Returns a map of all of the schema fields contained within data
generate_changeset(data, schema)
View Source
generate_changeset(map() | ecto_struct(), ecto_schema_module()) ::
Ecto.Changeset.t()
generate_changeset(map() | ecto_struct(), ecto_schema_module()) :: Ecto.Changeset.t()
Casts the given data into a changeset according to the types defined by the given schema. It ignores any fields in data that are not defined in the schema, and recursively casts any embedded fields to a changeset also. Accepts a different struct as the first argument, calling Map.to_struct on it first.
generate_changeset(data, schema, fields)
View Source
generate_changeset(map() | ecto_struct(), ecto_schema_module(), list()) ::
Ecto.Changeset.t()
generate_changeset(map() | ecto_struct(), ecto_schema_module(), list()) :: Ecto.Changeset.t()
Takes in a map of data and creates a changeset out of it by casting the data recursively, according to the whitelist of fields in fields. The map of data may be a struct, and the fields whitelist can whitelist fields of nested relations by providing a list for them as well.
Examples
If we provide a whitelist of fields, we will be passed a changeset for the changes on those fields only:
...> data = %{
...> "integer" => "77",
...> "steamed_hams" => [%{
...> "pickles" => 1,
...> "sauce_ratio" => "0.7",
...> "double_nested_schema" => %{"value" => "works!"}
...> }],
...> }
...> EctoMorph.generate_changeset(data, SchemaUnderTest, [:integer])
...>
We can also define whitelists for any arbitrarily deep relation like so:
...> data = %{
...> "integer" => "77",
...> "steamed_hams" => [%{
...> "pickles" => 1,
...> "sauce_ratio" => "0.7",
...> "double_nested_schema" => %{"value" => "works!"}
...> }],
...> }
...> EctoMorph.generate_changeset(data, SchemaUnderTest, [
...> :integer,
...> steamed_hams: [:pickles, double_nested_schema: [:value]]
...> ])
into_struct(changeset)
View Source
into_struct(Ecto.Changeset.t()) ::
{:ok, ecto_struct()} | {:error, Ecto.Changeset.t()}
into_struct(Ecto.Changeset.t()) :: {:ok, ecto_struct()} | {:error, Ecto.Changeset.t()}
Take a changeset and returns a struct if there are no errors on the changeset. Returns an error tuple with the invalid changeset otherwise.
map_from_struct(struct, options \\ []) View Source
Creates a map out of the Ecto struct, removing the internal ecto fields. Optionally you can remove the inserted_at and updated_at timestamp fields also by passing in :exclude_timestamps as an option
Examples
iex> map_from_struct(%Test{}, [:exclude_timestamps])
%Test{foo: "bar", id: 10}
iex> map_from_struct(%Test{})
%Test{foo: "bar", updated_at: ~N[2000-01-01 23:00:07], inserted_at: ~N[2000-01-01 23:00:07], id: 10}
iex> map_from_struct(%Test{}, [:exclude_timestamps, :exclude_id])
%Test{foo: "bar"}
to_struct(data, schema)
View Source
to_struct(map_with_string_keys() | ecto_struct(), ecto_schema_module()) ::
{:ok, ecto_struct()} | {:error, Ecto.Changeset.t()}
to_struct(map_with_string_keys() | ecto_struct(), ecto_schema_module()) :: {:ok, ecto_struct()} | {:error, Ecto.Changeset.t()}
Takes some data and tries to convert it to a struct in the shape of the given schema. Casts values to the types defined by the schema dynamically using ecto changesets.
Consider this:
iex> Jason.encode!(%{a: :b, c: Decimal.new("10")}) |> Jason.decode!
%{"a" => "b", "c" => "10"}
When we decode some JSON (e.g. from a jsonb column in the db or from a network request), the JSON gets
decode
d by our Jason lib, but not all of the information is preserved; any atom keys become strings,
and if the value is a type that is not part of the JSON spec, it is casted to a string.
This means we cannot pass that JSON data directly into a struct/2 function and expect a shiny Ecto struct back (struct!/2 will just raise, and struct/2 will silently return an empty struct)
UNTIL NOW!
Here we take care of casting the values in the json to the type that the given schema defines, as well as turning the string keys into (existing) atoms. (We know they will be existing atoms because they will exist in the schema definitions.)
We filter out any keys that are not defined in the schema, and if the first argument is a struct, we call Map.from_struct/1 on it first. This can be useful for converting data between structs.
Alternatively you can pass in a list of fields that you allow updates / inserts on. This list of fields can define fields for inner schemas also like so:
EctoMorph.to_struct(json, SchemaUnderTest, [
:boolean,
:name,
:binary,
:array_of_ints,
steamed_hams: [:pickles, double_nested_schema: [:value]]
])
Check out the test for more full examples.
Examples
iex> defmodule Test do
...> use Ecto.Schema
...>
...> embedded_schema do
...> field(:pageviews, :integer)
...> end
...> end
...> {:ok, test = %Test{}} = to_struct(%{"pageviews" => "10"}, Test)
...> test.pageviews
10
iex> defmodule Test do
...> use Ecto.Schema
...>
...> embedded_schema do
...> field(:pageviews, :integer)
...> end
...> end
...> json = %{"pageviews" => "10", "ignored_field" => "ten"}
...> {:ok, test = %Test{}} = to_struct(json, Test)
...> test.pageviews
10
to_struct(data, schema, fields)
View Source
to_struct(map_with_string_keys() | ecto_struct(), ecto_schema_module(), list()) ::
{:ok, ecto_struct()} | {:error, Ecto.Changeset.t()}
to_struct(map_with_string_keys() | ecto_struct(), ecto_schema_module(), list()) :: {:ok, ecto_struct()} | {:error, Ecto.Changeset.t()}