///|
/// One bounded page of immutable revisions. `next_offset` is the offset to
/// request next, or `None` when this page reaches the end of the sequence.
pub struct RevisionPage {
items : Array[Revision]
offset : Int32
total : Int32
next_offset : Int32?
}
///|
pub fn RevisionPage::items(self : RevisionPage) -> Array[Revision] {
self.items.copy()
}
///|
pub fn RevisionPage::offset(self : RevisionPage) -> Int32 {
self.offset
}
///|
pub fn RevisionPage::total(self : RevisionPage) -> Int32 {
self.total
}
///|
pub fn RevisionPage::next_offset(self : RevisionPage) -> Int32? {
self.next_offset
}
///|
pub fn RevisionPage::is_empty(self : RevisionPage) -> Bool {
self.items.is_empty()
}
///|
fn validate_page(offset : Int32, max_items : Int32) -> Unit raise TemporalError {
if offset < 0 {
raise InvalidPage("offset must be non-negative")
}
if max_items <= 0 || max_items > 10000 {
raise InvalidPage("max_items must be in 1..10000")
}
}
///|
fn page_end(offset : Int32, max_items : Int32, total : Int32) -> Int32 {
if offset >= total {
total
} else if max_items >= total - offset {
total
} else {
offset + max_items
}
}
///|
/// Page through the full append log without copying unrelated revisions.
pub fn Ledger::page(
self : Ledger,
offset : Int32,
max_items : Int32,
) -> RevisionPage raise TemporalError {
validate_page(offset, max_items)
let total = self.revisions.length()
let end = page_end(offset, max_items, total)
let items : Array[Revision] = []
if offset < total {
for i = offset; i < end; i = i + 1 {
items.push(self.revisions[i])
}
}
let next_offset = if end < total { Some(end) } else { None }
{ items, offset, total, next_offset, }
}
///|
/// Page through revisions for one key. Offsets are positions in that key's
/// history, while each returned revision retains its global sequence number.
pub fn Ledger::history_page(
self : Ledger,
key : String,
offset : Int32,
max_items : Int32,
) -> RevisionPage raise TemporalError {
validate_page(offset, max_items)
let positions = match self.index.get(key) {
Some(positions) => positions
None => []
}
let total = positions.length()
let end = page_end(offset, max_items, total)
let items : Array[Revision] = []
if offset < total {
for i = offset; i < end; i = i + 1 {
items.push(self.revisions[positions[i]])
}
}
let next_offset = if end < total { Some(end) } else { None }
{ items, offset, total, next_offset, }
}