calcinator v1.4.0 Calcinator.Resources.Sort

Sort in Calcinator.Resources.query_options

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

Types

association()
association() :: Keyword.t

Keyword list of association path used to Ecto preloading

associations_by_include()
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.

direction()
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 -.

field_name()
field_name() :: atom

Name of a field in an Ecto.Schema.t

from_alembic_fetch_sort_options()
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.
include_by_associations()
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.

t()
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

Functions

from_alembic_fetch_sort(sort, map)
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"
      }
    ]
  }
}
to_alembic_fetch_sort(sort, module)
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.