Normalixr v0.2.0 Normalixr

This module offers basic support to normalize nested Ecto schemas, merging normalized results, and backfilling has_on and belongs_to relations.

Summary

Functions

Backfill has_one 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 schema which might contain deeply nested data

Functions

backfill(result, opts)

Specs

backfill(map, Keyword.t) :: map

Backfill has_one 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.

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 schema 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.

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.