use std::collections::BTreeSet;
use crate::id::Id;
use crate::query::register::{resolve, ObservationOrder};
use crate::query::TriblePattern;
pub fn latest<P>(facts: &P, observes: Id, candidates: impl IntoIterator<Item = Id>) -> BTreeSet<Id>
where
P: TriblePattern,
{
resolve(&ObservationOrder::new(facts, observes), candidates)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::id::ExclusiveId;
use crate::macros::entity;
use crate::metadata;
use crate::prelude::*;
fn edge(successor: &ExclusiveId, predecessor: &ExclusiveId) -> TribleSet {
entity! { successor @ metadata::supersedes: predecessor }.into()
}
#[test]
fn a_lone_state_is_its_own_frontier() {
let only = ufoid();
let facts = TribleSet::new();
assert_eq!(
latest(&facts, metadata::supersedes.id(), [*only]),
[*only].into_iter().collect::<BTreeSet<_>>()
);
}
#[test]
fn arrival_order_does_not_change_the_frontier() {
let predecessor = ufoid();
let successor = ufoid();
let candidates = [*predecessor, *successor];
let mut forwards = TribleSet::new();
forwards += entity! { &predecessor @ metadata::name: "p" };
forwards += edge(&successor, &predecessor);
let mut backwards = TribleSet::new();
backwards += edge(&successor, &predecessor);
backwards += entity! { &predecessor @ metadata::name: "p" };
let expected: BTreeSet<Id> = [*successor].into_iter().collect();
assert_eq!(
latest(&forwards, metadata::supersedes.id(), candidates),
expected
);
assert_eq!(
latest(&backwards, metadata::supersedes.id(), candidates),
expected
);
}
#[test]
fn transitive_chains_need_no_closure() {
let a = ufoid();
let b = ufoid();
let c = ufoid();
let mut facts = TribleSet::new();
facts += edge(&b, &a);
facts += edge(&c, &b);
assert_eq!(
latest(&facts, metadata::supersedes.id(), [*a, *b, *c]),
[*c].into_iter().collect::<BTreeSet<_>>()
);
}
#[test]
fn concurrent_states_both_survive() {
let base = ufoid();
let left = ufoid();
let right = ufoid();
let mut facts = TribleSet::new();
facts += edge(&left, &base);
facts += edge(&right, &base);
assert_eq!(
latest(&facts, metadata::supersedes.id(), [*base, *left, *right]),
[*left, *right].into_iter().collect::<BTreeSet<_>>()
);
}
#[test]
fn the_attribute_is_a_parameter() {
let old = ufoid();
let new = ufoid();
let mut facts = TribleSet::new();
facts += edge(&new, &old);
assert_eq!(
latest(&facts, metadata::name.id(), [*old, *new]),
[*old, *new].into_iter().collect::<BTreeSet<_>>()
);
}
#[test]
fn frames_disagree_and_both_are_right() {
let first = ufoid();
let second = ufoid();
let mut early = TribleSet::new();
early += entity! { &first @ metadata::name: "first" };
let mut late = early.clone();
late += edge(&second, &first);
let candidates = [*first, *second];
assert_eq!(
latest(&early, metadata::supersedes.id(), candidates),
[*first, *second].into_iter().collect::<BTreeSet<_>>()
);
assert_eq!(
latest(&late, metadata::supersedes.id(), candidates),
[*second].into_iter().collect::<BTreeSet<_>>()
);
}
#[test]
fn re_resolving_frame_survivors_agrees_with_the_full_union_oracle() {
let base = ufoid();
let left = ufoid();
let right = ufoid();
let merge = ufoid();
let candidates = [*base, *left, *right, *merge];
let mut c1 = TribleSet::new();
c1 += edge(&left, &base);
let mut c2 = TribleSet::new();
c2 += edge(&right, &base);
c2 += edge(&merge, &right);
let mut union = c1.clone();
union += c2.clone();
let attribute = metadata::supersedes.id();
let l1 = latest(&c1, attribute, candidates);
let l2 = latest(&c2, attribute, candidates);
let joined = latest(&union, attribute, l1.iter().chain(l2.iter()).copied());
assert_eq!(latest(&union, attribute, candidates), joined);
}
}