Normalixr v0.4.0 Normalixr
This module offers basic support to normalize nested Ecto schemas, merging normalized results, and backfilling has_one and belongs_to-relations.
In order to use this library, you need to add :normalixr
to your list of
running applications, and replace any instance of use Ecto.Schema
with
use Normalixr.Schema
.
Summary
Functions
Backfill has_one (through) and belongs_to associations if the data has already been loaded
Merge one or more normalized representations
Normalizes an Ecto schema or list of Ecto schemas which might contain deeply nested data
Functions
Specs
backfill(map, Keyword.t) :: map
Backfill has_one (through) and belongs_to associations if the data has already been loaded.
Parameters
result
: a normalized representation.opts
: a keyword list, the keys should be the name of the schemas you want to backfill, the values the list of associations that should be backfilled for those schemas.
Example
iex> [%MyApp.Schemas.City{id: 1}, %MyApp.Schemas.Mayor{id: 2, city_id: 1}]
...> |> Normalixr.normalize
...> |> Normalixr.backfill(city: [:mayor], mayor: [:city])
%{city: %{1 => %MyApp.Schemas.City{id: 1, mayor: %{field: :mayor, ids: [2]}}},
mayor: %{2 => %MyApp.Schemas.Mayor{id: 2, city_id: 1, city: %{field: :city, ids: [1]}}}}
As you can see, both the originally unloaded one-to-one relations have been backfilled.
If you try to backfill unsupported associations, a Normalixr.UnsupportedAssociation
error is raised.
Specs
merge([map] | map, map) :: map
Merge one or more normalized representations.
Parameters
result_or_results
: a normalized representation, or list of normalized representations.initial_result
: a normalized representation, optional when a list of normalized representations is passed as the first argument.
Specs
normalize(Ecto.Schema.t | [Ecto.Schema.t], map) :: map
Normalizes an Ecto schema or list of Ecto schemas which might contain deeply nested data.
Parameters
schema_or_schemas
: An ecto schema or a list of ecto schemasinitial_result
: The result of an earlier normalization. Defaults to an empty map.
This function returns a single map, which is a normalized representation of the schema(s) it received. The second argument that can be passed should be the result of an earlier call to this function, because it will be used as initial value of the normalized representation that is returned.
The keys of the map are determined by the modules that define the schemas. All but the last dot-separated block is ignored, this last block is converted to a lower-case atom with underscores.
For example, if your module is called MyApp.Schemas.CityName
, the key
corresponding to these schemas in the normalized representation is
:city_name
.
You can override these default values by overriding underscored_name/0
with a function which returns the name as an atom. For example, if you
want MyApp.Weather.Home
to have the key :weather_home
, you should
define def underscored_name, do: :weather_home
.
The keys each point to a map which contains only the data of that type. The key of a schema is its primary key.
Example
iex> Normalixr.normalize(%MyApp.Schemas.CityName{id: 1})
%{city_name: %{1 => %MyApp.Schemas.CityName{id: 1}}}
The results no longer contain any nested schemas. Every loaded
association is replaced by a map with two keys, :field
and :ids
.
The former has the key for those schemas, the latter contains a list of ids
referenced by the schema.
Example
iex> Normalixr.normalize(%City{id: 4, city_name: %CityName{id: 1}})
%{city: %{4 => %City{id: 4, city_name: %{field: :city_name, ids: [1]}}},
city_name: %{1 => %CityName{id: 1}}}
As you can see the nesting has been lost.
If a schema is inserted into the normalized representation which has
already been set, a Normalixr.FieldMismatchError
is raised if the field
is set in both schemas and they don’t match. If either value is nil
,
it is replaced if the other value is not nil
.