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

backfill(result, opts)

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.

merge(result_or_results, initial_result \\ %{})

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.
normalize(schema_or_schemas, result \\ %{})

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 schemas
  • initial_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.