resx v0.1.0 Resx.Resource

The resource representation.

Link to this section Summary

Functions

Check if two resources or resource references point to the same resource

Retrieve the attribute for a resource or resource reference

Retrieve the attribute keys for a resource or resource reference

Retrieve the attributes for a resource or resource reference

Discard the resource

Check whether a resource or resource reference exists

Finalise all pending operations on the resource

Finalise all pending operations on the resource

Compute a hash of the resource content using the default hashing function

Compute a hash of the resource content

Check what kind of reference this resource or resource reference is

Retrieve the newest of the two alike resources

Retrieve the oldest of the two alike resources

Open a resource from a pre-existing resource or a resource reference

Open a resource from a pre-existing resource or a resource reference

Get the source of the current resource or resource reference

Stream a resource from a pre-existing resource or a resource reference

Stream a resource from a pre-existing resource or a resource reference

Retrieve the URI for a resource or resource reference

Link to this section Types

Link to this type attribute_key()
attribute_key() :: atom() | String.t()
Link to this type compare_options()
compare_options() :: [
  order: compare_order(),
  unsure: compare_result(),
  content: boolean()
]
Link to this type compare_order()
compare_order() :: :first | :last
Link to this type compare_result()
compare_result() :: nil | :ne | :lt | :eq | :gt | :na
Link to this type hash_state()
hash_state() :: any()
Link to this type t(content)
t(content) :: %Resx.Resource{
  content: content,
  meta: keyword(),
  reference: Resx.Resource.Reference.t()
}

Link to this section Functions

Link to this function alike?(resource_a, resource_b)
alike?(t() | Resx.ref(), t() | Resx.ref()) :: boolean()

Check if two resources or resource references point to the same resource.

Link to this function attribute(resource, field)
attribute(t() | Resx.ref(), attribute_key()) ::
  {:ok, any()}
  | Resx.error(Resx.resource_error() | Resx.reference_error() | :unknown_key)

Retrieve the attribute for a resource or resource reference.

Link to this function attribute_keys(resource)
attribute_keys(t() | Resx.ref()) ::
  {:ok, [attribute_key()]}
  | Resx.error(Resx.resource_error() | Resx.reference_error())

Retrieve the attribute keys for a resource or resource reference.

Link to this function attributes(resource)
attributes(t() | Resx.ref()) ::
  {:ok, %{optional(attribute_key()) => any()}}
  | Resx.error(Resx.resource_error() | Resx.reference_error())

Retrieve the attributes for a resource or resource reference.

Link to this function compare(resource_a, resource_b, opts \\ [])
compare(t(), t(), compare_options()) :: compare_result()

Compare two resources.

The result of the comparison will be one of the following:

  • nil - The two resources are not alike. And therefore not equal.
  • :eq - The two resources are equal. This will either be integrity equality or if the :content option is set to true then the content's must also be equal.
  • :lt or :gt - The first resource is older or newer than the second. This is based on the integrity timestamps in the order specified in the :order option. A :first order will iterate through the sources from the original to the current, while :last order will iterate from current to original. The first one with a differing timestamp will be used. Note that this does not tell you the equality of the two resources (to do that check Resx.Resource.Reference.Integrity.compare/2 or manually compare).
  • :ne - The two resources are not equal. They have equal timestamps for all sources, but one of the sources does not have an equal checksum or if the :content option was set to true, then also if the content's are not equal.
  • :na - The two resources cannot be determined. The timestamps are all equal for all sources, but there were no checksums to compare against for the final iteration (see :order). If the :content option is set to true, then the final result will be determined by the content comparison, because of this :na will no longer be a possible result (it will instead be either :eq or :ne). The :unsure option can be to change the result term, e.g. if uncertain comparisons should just be considered not equal, then [unsure: :ne] could be passed as an option.

The following options may be passed to this function:

  • :order - The source order in which the comparisons should occur. An order of :first will iterate from the original source to the current, while :last will iterate from the current source to the original. By default this is :first.
  • :unsure - Override the result returned when the comparison result is ambiguous. By default this is set to :na.
  • :content - Expects a boolean indicating whether the content data should be compared as well or not. By default this is set to false.

Link to this function discard(resource, opts \\ [])

Discard the resource.

Only resources or resource references that implement the Resx.Storer behaviour should be passed to this.

Link to this function exists?(resource)
exists?(t() | Resx.ref()) ::
  {:ok, boolean()} | Resx.error(Resx.reference_error())

Check whether a resource or resource reference exists.

Link to this function finalise!(reference, opts \\ [])
finalise!(t() | Resx.ref(),
  content: boolean(),
  hash:
    boolean()
    | Resx.Resource.Reference.Integrity.algo()
    | hasher()
    | streamable_hasher()
) :: t() | no_return()

Finalise all pending operations on the resource.

For more details see Resx.Resource.finalise/2.

Raises any error exceptions.

Link to this function finalise(reference, opts \\ [])

Finalise all pending operations on the resource.

The result is a resource with the requested operations applied to it.

Set the :content option to indicate whether content should be included in the final resource (e.g. if it is a stream, its result should be stored instead). By default it is.

Set the :hash option to indicate whether the content hash should be included in the final resource, and which hashing algorithm should be used. By default it is included and is the same as calling Resx.Resource.hash/1.

Compute a hash of the resource content using the default hashing function.

The default hashing function can be configured by giving a :hash option in your config.

config :resx,
    hash: { :crc32, { :erlang, :crc32, 1 } }

See hash/2 for more information.

Compute a hash of the resource content.

Meta information and resource references are not included in the hash.

Hashing algorithms can take the form of either an atom that is a valid option to :crypto.hash/2, or a tuple of type hasher or streamable_hasher to provide a custom hashing function. Valid function formats are any callback variant, see Callback for more information.

Note: If the resource content is streamable and a hasher is provided for the algo, then the entire content will be decomposed first. If the algo is a streamable_hasher then no decomposition will take place.

The inputs to the initialiser function of a streamable_hasher are optional. The rest are all required.

If the requested hash is the same as the checksum found in the resource, then that checksum will be returned without rehashing the resource content.

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :crc32, { :erlang, :crc32, 1 } })
{ :crc32, 4157704578 }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :crc32, { :erlang, :crc32, [] } })
{ :crc32, 4157704578 }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :md5, { :crypto, :hash, [:md5] } })
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource.Content.Stream{ type: ["text/plain"], data: ["He", "l", "lo"] }, { :md5, { :crypto, :hash, [:md5] } })
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :md5, { :crypto, :hash_init, 1 }, { :crypto, :hash_update, 2 }, { :crypto, :hash_final, 1 } })
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource.Content.Stream{ type: ["text/plain"], data: ["He", "l", "lo"] }, { :md5, { :crypto, :hash_init, 1 }, { :crypto, :hash_update, 2 }, { :crypto, :hash_final, 1 } })
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, :md5)
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource.Content.Stream{ type: ["text/plain"], data: ["He", "l", "lo"] }, :md5)
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :hmac_md5_5, { :crypto, :hmac, [:md5, "secret", 5], 2 } })
{ :hmac_md5_5, <<243, 134, 128, 59, 99>> }

iex> Resx.Resource.hash(%Resx.Resource.Content.Stream{ type: ["text/plain"], data: ["He", "l", "lo"] }, { :hmac_md5_5, { :crypto, :hmac, [:md5, "secret", 5], 2 } })
{ :hmac_md5_5, <<243, 134, 128, 59, 99>> }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :hmac_md5_5, { :crypto, :hmac_init, [:md5, "secret"], nil }, { :crypto, :hmac_update, 2 }, { :crypto, :hmac_final_n, [5], 0 } })
{ :hmac_md5_5, <<243, 134, 128, 59, 99>> }

iex> Resx.Resource.hash(%Resx.Resource.Content.Stream{ type: ["text/plain"], data: ["He", "l", "lo"] }, { :hmac_md5_5, { :crypto, :hmac_init, [:md5, "secret"], nil }, { :crypto, :hmac_update, 2 }, { :crypto, :hmac_final_n, [5], 0 } })
{ :hmac_md5_5, <<243, 134, 128, 59, 99>> }

iex> Resx.Resource.hash(%Resx.Resource.Content{ type: ["text/plain"], data: "Hello" }, { :base64, &Base.encode64/1 })
{ :base64, "SGVsbG8=" }

iex> Resx.Resource.hash(%Resx.Resource{ reference: %Resx.Resource.Reference{ integrity: %Resx.Resource.Reference.Integrity{ timestamp: DateTime.utc_now }, adapter: nil, repository: nil }, content: %Resx.Resource.Content{ type: ["text/plain"], data: "Hello" } }, :md5)
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }

iex> Resx.Resource.hash(%Resx.Resource{ reference: %Resx.Resource.Reference{ integrity: %Resx.Resource.Reference.Integrity{ checksum: { :foo, 1 }, timestamp: DateTime.utc_now }, adapter: nil, repository: nil }, content: %Resx.Resource.Content{ type: ["text/plain"], data: "Hello" } }, :foo)
{ :foo, 1 }

iex> Resx.Resource.hash(%Resx.Resource{ reference: %Resx.Resource.Reference{ integrity: %Resx.Resource.Reference.Integrity{ checksum: { :foo, 1 }, timestamp: DateTime.utc_now }, adapter: nil, repository: nil }, content: %Resx.Resource.Content{ type: ["text/plain"], data: "Hello" } }, :md5)
{ :md5, <<139, 26, 153, 83, 196, 97, 18, 150, 168, 39, 171, 248, 196, 120, 4, 215>> }
Link to this function kind?(resource, behaviour)
kind?(t() | Resx.ref(), module()) :: boolean()

Check what kind of reference this resource or resource reference is.

iex> Resx.Resource.open!("data:,foo") |> Resx.Resource.kind?(Resx.Producer)
true

iex> Resx.Resource.kind?("data:,foo", Resx.Producer)
true

iex> Resx.Resource.kind?("data:,foo", Resx.Producers.Data)
true

iex> Resx.Resource.kind?("data:,foo", Resx.Storer)
false

iex> Resx.Resource.kind?("data:,foo", Resx.Transformer)
false
Link to this function newest(resource_a, resource_b, opts \\ [])
newest(t(), t(), [{:default, term() | compare_options()}]) ::
  t() | term()

Retrieve the newest of the two alike resources.

If this cannot be determined, it will return the value in the :default option.

Comparison options can be passed to control how the two resources are compared with each other. For more details on this behaviour see Resx.Resource.compare/3.

iex> old = Resx.Resource.open!("data:,hello")
...> new = Resx.Resource.open!(old)
...> new == Resx.Resource.newest(old, new)
true

iex> old = Resx.Resource.open!("data:,hello")
...> new = Resx.Resource.open!(old)
...> new == Resx.Resource.newest(new, old)
true

iex> old = Resx.Resource.open!("data:,foo")
...> new = Resx.Resource.open!("data:,bar")
...> Resx.Resource.newest(new, old)
nil
Link to this function oldest(resource_a, resource_b, opts \\ [])
oldest(t(), t(), [{:default, term() | compare_options()}]) ::
  t() | term()

Retrieve the oldest of the two alike resources.

If this cannot be determined, it will return the value in the :default option.

Comparison options can be passed to control how the two resources are compared with each other. For more details on this behaviour see Resx.Resource.compare/3.

iex> old = Resx.Resource.open!("data:,hello")
...> new = Resx.Resource.open!(old)
...> old == Resx.Resource.oldest(old, new)
true

iex> old = Resx.Resource.open!("data:,hello")
...> new = Resx.Resource.open!(old)
...> old == Resx.Resource.oldest(new, old)
true

iex> old = Resx.Resource.open!("data:,foo")
...> new = Resx.Resource.open!("data:,bar")
...> Resx.Resource.oldest(new, old)
nil
Link to this function open!(resource, opts \\ [])

Open a resource from a pre-existing resource or a resource reference.

Raises a Resx.Resource.OpenError if the resource could not be opened.

For more details see Resx.Resource.open/2.

Open a resource from a pre-existing resource or a resource reference.

Link to this function source(resource)
source(t() | Resx.ref()) ::
  {:ok, Resx.ref() | nil} | Resx.error(Resx.reference_error())

Get the source of the current resource or resource reference.

It will return { :ok, nil } if there is no source.

Link to this function store!(resource, storer, opts \\ [])
store!(t() | Resx.ref(), module(), keyword()) :: t() | no_return()

Store the resource.

If a resource reference is given, a stream will be opened to that resource.

Raises a Resx.Storer.StoreError if the resource cannot be saved, or a Resx.Resource.OpenError if the resource could not be opened.

For more details see Resx.Storer.save!/2.

Link to this function store(resource, storer, opts \\ [])
store(t() | Resx.ref(), module(), keyword()) ::
  {:ok, t()} | Resx.error(Resx.resource_error() | Resx.reference_error())

Store the resource.

If a resource reference is given, a stream will be opened to that resource.

For more details see Resx.Storer.save/2.

Link to this function stream!(resource, opts \\ [])

Stream a resource from a pre-existing resource or a resource reference.

Raises a Resx.Resource.OpenError if the resource could not be streamed.

For more details see Resx.Resource.stream/2.

Stream a resource from a pre-existing resource or a resource reference.

Link to this function transform!(resource, transformer, opts \\ [])
transform!(t() | Resx.ref(), module(), keyword()) :: t() | no_return()

Transform the resource.

If a resource reference is given, a stream will be opened to that resource.

Raises a Resx.Transformer.TransformError if the transformation cannot be applied, or a Resx.Resource.OpenError if the resource could not be opened.

For more details see Resx.Transformer.apply!/2.

Link to this function transform(resource, transformer, opts \\ [])
transform(t() | Resx.ref(), module(), keyword()) ::
  {:ok, t()} | Resx.error(Resx.resource_error() | Resx.reference_error())

Transform the resource.

If a resource reference is given, a stream will be opened to that resource.

For more details see Resx.Transformer.apply/2.

Retrieve the URI for a resource or resource reference.