calcinator v5.0.0 Calcinator.Resources.Sort View Source

Sort in Calcinator.Resources.query_options

Link to this section Summary

Types

Keyword list of association path used to Ecto preloading

Used to convert includes used by JSONAPI to the corresponding association in Ecto

The direction to sort. Default to :ascending per the JSONAPI spec. Can be :descending when the dot-separated attribute path is prefixed with -

Name of a field in an Ecto.Schema.t

  • :associations_by_include - maps the Alembic.Fetch.Includes.t to Keyword.t of associations.
  • :ecto_schema_module - primary Ecto.Schema module for checking if attribute is an existent field after applying associations

Used to convert associations used in Ecto to JSONAPI includes

t()
  • :assocation - Keyword list of nested associations. nil when the :field is direction on the primary data.
  • :direction - the direction to sort :field
  • :field - name of the field to sort

Functions

Maps Alembic.Fetch.Sort.t attribute to t field and Alembic.Fetch.Sort.t relationships to t associations

Maps t field to Alembic.Fetch.Sort.t attribute and t associations to Alembic.Fetch.Sort.t relationships

Link to this section Types

Link to this type association() View Source
association() :: Keyword.t

Keyword list of association path used to Ecto preloading

Link to this type associations_by_include() View Source
associations_by_include() :: %{optional(Alembic.Fetch.Includes.t) => association}

Used to convert includes used by JSONAPI to the corresponding association in Ecto.

This map does not need to be a simple conversion of the nested map of strings Alembic.Fetch.Includes.t to the Keyword.t of associations, but can include completely different names or associations that the JSONAPI doesn’t even expose, so that deprecated relationships can be mapped to newer associations.

Link to this type direction() View Source
direction() :: :ascending | :descending

The direction to sort. Default to :ascending per the JSONAPI spec. Can be :descending when the dot-separated attribute path is prefixed with -.

Link to this type field_name() View Source
field_name() :: atom

Name of a field in an Ecto.Schema.t

Link to this type from_alembic_fetch_sort_options() View Source
from_alembic_fetch_sort_options() :: %{associations_by_include: associations_by_include, ecto_schema_module: module}
  • :associations_by_include - maps the Alembic.Fetch.Includes.t to Keyword.t of associations.
  • :ecto_schema_module - primary Ecto.Schema module for checking if attribute is an existent field after applying associations.
Link to this type include_by_associations() View Source
include_by_associations() :: %{optional(association) => Alembic.Fetch.Includes.t}

Used to convert associations used in Ecto to JSONAPI includes.

This map need not be the inverse of associations_by_include if the JSONAPI incoming relationships are no the same as the outgoing relationships.

Link to this type t() View Source
t() :: %Calcinator.Resources.Sort{association: nil | association, direction: direction, field: field_name}
  • :assocation - Keyword list of nested associations. nil when the :field is direction on the primary data.
  • :direction - the direction to sort :field
  • :field - name of the field to sort

Link to this section Functions

Link to this function from_alembic_fetch_sort(sort, map) View Source
from_alembic_fetch_sort(Alembic.Fetch.Sort.t, from_alembic_fetch_sort_options) ::
  {:ok, t} |
  {:error, Alembic.Document.t}

Maps Alembic.Fetch.Sort.t attribute to t field and Alembic.Fetch.Sort.t relationships to t associations.

When there are no relationships, there are no assocations

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "inserted-at"
...>   },
...>   %{
...>     associations_by_include: %{},
...>     ecto_schema_module: Calcinator.Resources.TestPost
...>   }
...> )
{
  :ok,
  %Calcinator.Resources.Sort{field: :inserted_at}
}

When there is relationship it is converted to association using :associations_by_include

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "inserted-at",
...>     relationship: "posts"
...>   },
...>   %{
...>     associations_by_include: %{"posts" => :posts},
...>     ecto_schema_module: Calcinator.Resources.TestAuthor
...>   }
...> )
{
  :ok,
  %Calcinator.Resources.Sort{
    association: :posts,
    direction: :ascending,
    field: :inserted_at
  }
}

The relationship can also be nested and it will be converted using :associations_by_include too

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "inserted-at",
...>     relationship: %{
...>       "posts" => "comments"
...>     }
...>   },
...>   %{
...>     associations_by_include: %{
...>       %{
...>         "posts" => "comments"
...>       } => [posts: :comments]
...>     },
...>     ecto_schema_module: Calcinator.Resources.TestAuthor
...>   }
...> )
{
  :ok,
  %Calcinator.Resources.Sort{
    association: [posts: :comments],
    direction: :ascending,
    field: :inserted_at
  }
}

Errors

If the Alembic.Fetch.Sort.t relationship is not in :associations_by_include, then an error is returned

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "inserted-at",
...>     relationship: "author"
...>   },
...>   %{
...>     associations_by_include: %{},
...>     ecto_schema_module: Calcinator.Resources.TestPost
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`author` is an unknown relationship path",
        meta: %{
          "relationship_path" => "author"
        },
        source: %Alembic.Source{
          parameter: "include"
        },
        title: "Unknown relationship path"
      }
    ]
  }
}

If the Alembic.Fetch.Sort.t attribute is not on :ecto_schema_module when there is no relationship, then an error is returned with only the attribute in it

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "likes",
...>     relationship: nil
...>   },
...>   %{
...>     associations_by_include: %{},
...>     ecto_schema_module: Calcinator.Resources.TestPost
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "Does not have `likes` attribute",
        meta: %{
          "attribute" => "likes"
        },
        source: %Alembic.Source{
          parameter: "sort"
        },
        title: "Unknown attribute"
      }
    ]
  }
}

If the Alembic.Fetch.Sort.t attribute is not on the associated Ecto.Schema module, than an error is returned with both the relationship and attribute in it.

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "title",
...>     relationship: "author"
...>   },
...>   %{
...>     associations_by_include: %{
...>       "author" => :author
...>     },
...>     ecto_schema_module: Calcinator.Resources.TestPost
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`author` does not have a `title` attribute",
        meta: %{
          "attribute" => "title",
          "relationship_path" => "author"
        },
        source: %Alembic.Source{
          parameter: "sort"
        },
        title: "Unknown attribute"
      }
    ]
  }
}

If the relationship is far, then the whole relationship is shown in the error

iex> Calcinator.Resources.Sort.from_alembic_fetch_sort(
...>   %Alembic.Fetch.Sort{
...>     attribute: "likes",
...>     relationship: %{
...>       "posts" => "comments"
...>     }
...>   },
...>   %{
...>     associations_by_include: %{
...>       %{
...>         "posts" => "comments"
...>       } => [posts: :comments]
...>     },
...>     ecto_schema_module: Calcinator.Resources.TestAuthor
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`posts.comments` does not have a `likes` attribute",
        meta: %{
          "attribute" => "likes",
          "relationship_path" => "posts.comments"
        },
        source: %Alembic.Source{
          parameter: "sort"
        },
        title: "Unknown attribute"
      }
    ]
  }
}
Link to this function to_alembic_fetch_sort(sort, module) View Source
to_alembic_fetch_sort(t, Calcinator.Resources.t) ::
  {:ok, Alembic.Fetch.Sort.t} |
  {:error, Alembic.Document.t}

Maps t field to Alembic.Fetch.Sort.t attribute and t associations to Alembic.Fetch.Sort.t relationships.