use crate::{DomainError, TemporalAxis, TemporalCursor, TemporalInterval};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum TemporalSelection {
#[default]
Frontier,
AsOf {
cursor: TemporalCursor,
axis: TemporalAxis,
},
Within {
interval: TemporalInterval,
axis: TemporalAxis,
},
}
impl TemporalSelection {
pub fn as_of(cursor: TemporalCursor, axis: TemporalAxis) -> Result<Self, DomainError> {
if matches!(cursor, TemporalCursor::Sequence(_)) {
return Err(DomainError::InvalidState(
"as_of takes a ref or a time; a sequence is relative to one dimension and \
names no instant"
.to_string(),
));
}
Ok(Self::AsOf { cursor, axis })
}
pub fn within(interval: TemporalInterval, axis: TemporalAxis) -> Self {
Self::Within { interval, axis }
}
pub fn is_frontier(&self) -> bool {
matches!(self, Self::Frontier)
}
pub fn axis(&self) -> Option<TemporalAxis> {
match self {
Self::Frontier => None,
Self::AsOf { axis, .. } | Self::Within { axis, .. } => Some(*axis),
}
}
pub fn interval(&self) -> Option<&TemporalInterval> {
match self {
Self::Within { interval, .. } => Some(interval),
_ => None,
}
}
pub fn cursor(&self) -> Option<&TemporalCursor> {
match self {
Self::AsOf { cursor, .. } => Some(cursor),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_sequence_cursor_names_no_instant_and_is_refused() {
let error = TemporalSelection::as_of(
TemporalCursor::sequence(3).expect("a sequence"),
TemporalAxis::Default,
)
.expect_err("a sequence is relative to one dimension");
assert!(error.to_string().contains("names no instant"), "{error}");
assert!(
TemporalSelection::as_of(
TemporalCursor::time("2026-03-01T00:00:00Z").expect("a time"),
TemporalAxis::Observed
)
.is_ok()
);
assert!(
TemporalSelection::as_of(
TemporalCursor::ref_id("about:x:entry:e1").expect("a ref"),
TemporalAxis::Default
)
.is_ok()
);
}
#[test]
fn the_frontier_is_the_default_and_reads_no_axis() {
let selection = TemporalSelection::default();
assert!(selection.is_frontier());
assert_eq!(selection.axis(), None);
assert!(selection.interval().is_none());
let within = TemporalSelection::within(
TemporalInterval::new(Some("2026-03-01T00:00:00Z".to_string()), None)
.expect("since March"),
TemporalAxis::Ingested,
);
assert_eq!(within.axis(), Some(TemporalAxis::Ingested));
assert!(within.interval().is_some());
}
}