Resolves as_of into the point of time or period that the data layer stores.
On a temporal resource every
version of a record is valid for a period of datetimes. You can provide a DateTime, or
:now.
# a read resolves as_of a point in time
Ash.Temporal.resolve_read_as_of(query.as_of)
# a write resolves a period beginning at the point,
# and extending forever unless a later write closes it
{:ok, instant} = Ash.Temporal.write_instant(resource, :now)
{:ok, period} = Ash.Temporal.write_period(resource, :now)The write functions return a DateTime cast to the precision the resource's period
declares.
A write that provides no as_of takes effect now. Ash resolves it once for the whole write,
before the data layer is called, so a data layer receives a temporal write's as_of as an
instant or a range, never nil or :now.
Summary
Functions
Casts the as_of of a write to a temporal resource into the type its periods are built
from, applying the precision that type declares.
Checks the as_of of a write to a temporal resource, casting it as cast_write_as_of/2 does.
Resolves the as_of a read answers at.
Resolves the as_of a write takes effect at.
Whether a change, validation or preparation module declares itself safe to run on a temporal resource, for the given options.
Resolves the point where a write first takes effect.
Resolves the period a write is valid for.
Types
@type as_of() :: :now | term() | nil
An as_of as a caller may give it, before it is resolved.
Functions
@spec cast_write_as_of(Ash.Resource.t(), as_of()) :: term()
Casts the as_of of a write to a temporal resource into the type its periods are built
from, applying the precision that type declares.
An instant or :now becomes an instant (see write_instant/2) and a range becomes a period
(see write_period/2). Anything that can't be cast, and any as_of of a resource that
isn't temporal, is returned unchanged.
@spec check_write_as_of(Ash.Resource.t(), as_of()) :: {:ok, term()} | {:error, Exception.t()}
Checks the as_of of a write to a temporal resource, casting it as cast_write_as_of/2 does.
An instant must cast to the type the resource's periods are built from. A range must
cast to the resource's period, and satisfy its constraints. Returns the cast as_of, or
an Ash.Error.Changes.InvalidAsOf saying why it is refused. Any as_of of a resource
that isn't temporal is returned unchanged.
@spec resolve_read_as_of(as_of()) :: DateTime.t() | nil
Resolves the as_of a read answers at.
:now resolves to the current time, and a DateTime is that instant. nil means no
particular time was provided. Anything else, such as a range or a Date, raises
Ash.Error.Query.AsOfNotAnInstant.
Resolves the as_of a write takes effect at.
:now resolves to the current time. A range resolves to its lower bound. Anything else is
returned unchanged. nil means no particular time was provided.
Whether a change, validation or preparation module declares itself safe to run on a temporal resource, for the given options.
Every action on a temporal resource runs "as of" a point in time, so anything that
runs as part of one must not assume it is happening now. A module declares that it
meets that bar with the temporal_safe?/1 callback of its behaviour
(Ash.Resource.Change.temporal_safe?/1, Ash.Resource.Validation.temporal_safe?/1,
Ash.Resource.Preparation.temporal_safe?/1). A module that does not define it is
not temporal safe.
Modules from packages that don't declare it yet can be listed as temporal safe in config:
config :ash, :temporal_safe_modules, [SomePackage.Changes.DoesThing]
@spec write_instant(Ash.Resource.t(), as_of()) :: {:ok, DateTime.t()} | :error
Resolves the point where a write first takes effect.
The value comes back as a DateTime, cast to whatever precision the resource's period
declares.
@spec write_period(Ash.Resource.t(), as_of()) :: {:ok, Ash.Range.t()} | :error
Resolves the period a write is valid for.
The value comes back cast to the resource's period. It begins where the write takes effect and extends forever unless a later write closes it.