The JSON document a SQLite column holds for a Tempo expression.
SQLite has no range type, so Tempo.Ecto.SQLite.TempoRange stores an
expression as one TEXT value holding a JSON object: the expression
whole, as the PostgreSQL composite types keep it, beside the integer
bounds of the time it covers.
{"v": 1, "frame": "utc", "lo": 1781514000, "hi": 1781517600,
"spans": [[1781514000, 1781517600]],
"meta": {"expression": "2026Y6M15DT9H0MZ/T10H0MZ", ...}}loandhiare the half-open bounds of the stretch the expression covers, from the start of its first span to the end of its last, in whole seconds: since the Unix epoch at UTC for a column on the UTC frame, and since 1970-01-01T00:00 on the wall clock for a floating one. A bound with a fraction of a second is rounded outward, so the bounds always cover the expression. An open end is the least or the greatest 64-bit integer.spansare the bounds of each span the expression has, in order. A recurrence with no end has its stretch alone.metais the documentTempo.SQL.Metawrites, from which the expression is read back as it was written.
encode/2 writes the document, decode/1 reads the expression back,
and bounds/2 gives the bounds alone, for a query's probe.
Summary
Functions
The half-open bounds of the stretch an expression covers, in whole seconds on a frame.
Reads back the expression a SQLite column's document holds.
Writes the document a SQLite column holds for an expression.
Types
@type bound() :: integer()
A bound in whole seconds on a column's frame.
Functions
@spec bounds(Tempo.t(), Tempo.SQL.Conversion.frame()) :: {:ok, {bound(), bound()}} | {:error, Exception.t()}
The half-open bounds of the stretch an expression covers, in whole seconds on a frame.
Arguments
expressionis aTempo.t/0with a place on the time line.frameis:utc(the default) or:floating.
Returns
{:ok, {lower, upper}}, each an integer, an open end the least or the greatest 64-bit integer.{:error, exception}asTempo.SQL.Conversion.interval_to_queryable_range/2returns it.
Examples
iex> Tempo.SQL.SQLite.Document.bounds(~o"2026-06-15/2026-06-16", :floating)
{:ok, {1781481600, 1781654400}}
iex> Tempo.SQL.SQLite.Document.bounds(~o"2026-06-15T09:00Z/..")
{:ok, {1781514000, 9223372036854775807}}
Reads back the expression a SQLite column's document holds.
Arguments
jsonis the document, asencode/2writes it.
Returns
{:ok, expression}, aTempo.t/0, as it was written.{:error, reason}for a document that is not JSON, not of this shape, or whose expression cannot be read.
Examples
iex> {:ok, json} = Tempo.SQL.SQLite.Document.encode(~o"2026-06", :floating)
iex> Tempo.SQL.SQLite.Document.decode(json)
{:ok, ~o"2026-06"}
iex> {:error, {:invalid_document, _}} = Tempo.SQL.SQLite.Document.decode(~s({"v": 9}))
@spec encode(Tempo.t(), Tempo.SQL.Conversion.frame()) :: {:ok, binary()} | {:error, Exception.t()}
Writes the document a SQLite column holds for an expression.
Arguments
expressionis aTempo.t/0with ISO 8601 text and a place on the time line.frameis:utc(the default) or:floating, the column's frame.
Returns
{:ok, json}, the document as a binary.{:error, exception}whereexceptionis aTempo.SQL.UnsupportedValueError.t/0for an expression with no place on the time line or of the other frame (the reason:frame), or the errorTempo.to_iso8601/1returns.
Examples
iex> {:ok, json} = Tempo.SQL.SQLite.Document.encode(~o"2026-06-15T09:00Z/2026-06-15T10:00Z")
iex> document = Tempo.SQL.JSON.decode!(json)
iex> {document["lo"], document["hi"]}
{1781514000, 1781517600}
iex> {:error, error} = Tempo.SQL.SQLite.Document.encode(~o"2026-06-15T09:00/2026-06-15T10:00")
iex> error.reason
:frame