ergon_temporal_period (ergon v0.5.0)
View SourceThe decoded form of a PostgreSQL temporal validity period.
PostgreSQL 19 has no scalar PERIOD type: application-time (valid_period),
uniqueness (dedup_period), and system-time (system_time) are all tstzrange
columns. from_pg_range/1 converts what the driver decodes such a column into,
so callers work with a named shape instead of a positional tuple.
An infinite endpoint is unbounded; an empty range is empty := true with
empty endpoints. Both matter to Ergon specifically: a job is live exactly when
its valid_period upper bound is unbounded, and a non-unique job is one whose
dedup_period is empty, because empty ranges never overlap and so never trip the
uniqueness constraint.
Where this is and is not needed
No statement in priv/queries/ projects a range column today; every
job-returning query selects scalars. This module is for hosts that query
valid_period or system_time directly, and for the bi-temporal tests. It is
pure, so nothing here needs a database.
Summary
Functions
Whether Instant falls within the period, honouring bound inclusivity and
unbounded endpoints. An empty period contains nothing.
The empty period. Contains nothing and overlaps nothing.
Convert a range as the driver decodes it into a period.
A closed-open period [Lower, Upper), the bound style PostgreSQL uses for
tstzrange. Either endpoint may be unbounded.
Types
-type period_endpoint() :: pg_timestamp() | unbounded | empty.
-type pg_range() :: empty | {{pg_timestamp() | unbound, pg_timestamp() | unbound}, {boolean(), boolean()}}.
-type pg_timestamp() :: {calendar:date(), {0..23, 0..59, number()}} | infinity | '-infinity'.
-type temporal_period() :: #{lower := period_endpoint(), upper := period_endpoint(), lower_inclusive := boolean(), upper_inclusive := boolean(), empty := boolean()}.
Functions
-spec contains(temporal_period(), pg_timestamp()) -> boolean().
Whether Instant falls within the period, honouring bound inclusivity and
unbounded endpoints. An empty period contains nothing.
-spec empty() -> temporal_period().
The empty period. Contains nothing and overlaps nothing.
-spec from_pg_range(pg_range()) -> temporal_period().
Convert a range as the driver decodes it into a period.
pg_range is generic over its base type and answers either empty or
{{From, To}, {LowerInclusive, UpperInclusive}}, using unbound for an infinite
endpoint. This is the whole of the conversion: because that decoder is generic,
Ergon needs no hand-written binary codec for tstzrange.
-spec new(period_endpoint(), period_endpoint()) -> temporal_period().
A closed-open period [Lower, Upper), the bound style PostgreSQL uses for
tstzrange. Either endpoint may be unbounded.