Alembic v4.0.0 Alembic.ResourceIdentifier View Source

A JSON API Resource Identifier.

Link to this section Summary

Types

t()

A “resource identifier object” is [an %Alembic.ResourceIdentifier{}] that identifies an individual resource.

A “resource identifier object” MUST contain type and id members.

A “resource identifier object” MAY also include a meta member, whose value is a [Alembic.Meta.t] that contains non-standard meta-information.

JSON API - Document Structure - Resource Identifier Object

Functions

Converts resource_identifier to params format used by Ecto.Changeset.cast/4

Unlike to_params/2, if type and id of convertable already exists in converted_by_id_by_type, then the params returned are only %{ "id" => id } without any further expansion, that is, a resource identifier, so that loops are prevented

Link to this section Types

Link to this type t() View Source
t() :: %Alembic.ResourceIdentifier{
  id: String.t(),
  meta: Alembic.Meta.t(),
  type: String.t()
}

A “resource identifier object” is [an %Alembic.ResourceIdentifier{}] that identifies an individual resource.

A “resource identifier object” MUST contain type and id members.

A “resource identifier object” MAY also include a meta member, whose value is a [Alembic.Meta.t] that contains non-standard meta-information.

JSON API - Document Structure - Resource Identifier Object

Link to this section Functions

Link to this function from_json(json, error_template) View Source
from_json(
  %{optional(String.t()) => String.t() | Alembic.json_object()},
  Alembic.Error.t()
) :: {:ok, t()} | Alembic.FromJson.error()
from_json(
  nil | true | false | list() | float() | integer() | String.t(),
  Alembic.Error.t()
) :: Alembic.FromJson.error()

Examples

A resource identifier is valid with "id" and "type"

iex> Alembic.ResourceIdentifier.from_json(
...>   %{"id" => "1", "type" => "shirt"},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/data/relationships/shirt/data"
...>     }
...>   }
...> )
{:ok, %Alembic.ResourceIdentifier{id: "1", type: "shirt"}}

A resource identifier can optionally have "meta"

iex> Alembic.ResourceIdentifier.from_json(
...>   %{"id" => "1", "meta" => %{"copyright" => "2015"}, "type" => "shirt"},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/data/relationships/shirt/data"
...>     }
...>   }
...> )
{:ok, %Alembic.ResourceIdentifier{id: "1", meta: %{"copyright" => "2015"}, type: "shirt"}}

A resource identifier MUST have an "id"

iex> Alembic.ResourceIdentifier.from_json(
...>   %{"type" => "shirt"},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/data/relationships/shirt/data"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/data/relationships/shirt/data/id` is missing",
        meta: %{
          "child" => "id"
        },
        source: %Alembic.Source{
          pointer: "/data/relationships/shirt/data"
        },
        status: "422",
        title: "Child missing"
      }
    ]
  }
}

A resource identifer MUST have a "type"

iex> Alembic.ResourceIdentifier.from_json(
...>   %{"id" => "1"},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/data/relationships/shirt/data"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/data/relationships/shirt/data/type` is missing",
        meta: %{
          "child" => "type"
        },
        source: %Alembic.Source{
          pointer: "/data/relationships/shirt/data"
        },
        status: "422",
        title: "Child missing"
      }
    ]
  }
}

A resource identifer missing both "id" and "type" will show both as missing

iex> Alembic.ResourceIdentifier.from_json(
...>   %{},
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/data/relationships/shirt/data"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/data/relationships/shirt/data/id` is missing",
        meta: %{
          "child" => "id"
        },
        source: %Alembic.Source{
          pointer: "/data/relationships/shirt/data"
        },
        status: "422",
        title: "Child missing"
      },
      %Alembic.Error{
        detail: "`/data/relationships/shirt/data/type` is missing",
        meta: %{
          "child" => "type"
        },
        source: %Alembic.Source{
          pointer: "/data/relationships/shirt/data"
        },
        status: "422",
        title: "Child missing"
      }
    ]
  }
}

A non-resource-identifier will be identified as such

iex> Alembic.ResourceIdentifier.from_json(
...>   [],
...>   %Alembic.Error{
...>     source: %Alembic.Source{
...>       pointer: "/data/relationships/shirt/data"
...>     }
...>   }
...> )
{
  :error,
  %Alembic.Document{
    errors: [
      %Alembic.Error{
        detail: "`/data/relationships/shirt/data` type is not resource identifier",
        meta: %{
          "type" => "resource identifier"
        },
        source: %Alembic.Source{
          pointer: "/data/relationships/shirt/data"
        },
        status: "422",
        title: "Type is wrong"
      }
    ]
  }
}
Link to this function to_params(resource_identifier, resource_by_id_by_type) View Source

Converts resource_identifier to params format used by Ecto.Changeset.cast/4.

id and type will be used to lookup the attributes in resource_by_id_by_type. Theses attributes and the id will be combined into a map for params

iex> Alembic.ResourceIdentifier.to_params(
...>   %Alembic.ResourceIdentifier{id: "1", type: "author"},
...>   %{
...>     "author" => %{
...>       "1" => %Alembic.Resource{
...>         type: "author",
...>         id: "1",
...>         attributes: %{
...>           "name" => "Alice"
...>         }
...>       }
...>     }
...>   }
...> )
%{
  "id" => "1",
  "name" => "Alice"
}

If no entry is found in resource_by_id_by_type, then only the id is copied to the params. This can happen when the server only wants to send foreign keys.

iex> Alembic.ResourceIdentifier.to_params(
...>   %Alembic.ResourceIdentifier{id: "1", type: "author"},
...>   %{}
...> )
%{
  "id" => "1"
}
Link to this function to_params(resource_identifier, resource_by_id_by_type, converted_by_id_by_type) View Source

Unlike to_params/2, if type and id of convertable already exists in converted_by_id_by_type, then the params returned are only %{ "id" => id } without any further expansion, that is, a resource identifier, so that loops are prevented.

Parameters

  • convertable - an Alembic.Document.t hierarchy data structure
  • resources_by_id_by_type - A nest map with the outer layer keyed by the Alembic.Resource.type, then the next layer keyed by the Alembic.Resource.id with the values being the full Alembic.Resource.t from Alembic.Document.t included.
  • converted_by_id_by_type - Tracks which (type, id) have been converted already to prevent infinite recursion when expanding indirect relationships.

Returns

Success

  • {nil} if an empty singleton
  • %{} - if a non-empty singleton
  • [] - if an empty collection
  • [%{}] - if a non-empty collection

Errors

  • {:error, :already_converted} - if the type and id of convertable already exists in converted_by_id_by_type
  • {:error, :unset} - if the convertable data is not set

Callback implementation for Alembic.ToParams.to_params/3.