pub(super) fn row_system_time(
row: &[nodedb_types::value::Value],
ts_system_idx: Option<usize>,
) -> i64 {
use nodedb_types::value::Value;
match ts_system_idx.and_then(|i| row.get(i)) {
Some(Value::Integer(i)) => *i,
Some(Value::DateTime(dt)) | Some(Value::NaiveDateTime(dt)) => dt.micros / 1000,
_ => i64::MIN,
}
}
pub(super) fn bitemporal_row_visible(
row: &[nodedb_types::value::Value],
ts_system_idx: Option<usize>,
ts_valid_from_idx: Option<usize>,
ts_valid_until_idx: Option<usize>,
system_as_of_ms: Option<i64>,
valid_at_ms: Option<i64>,
) -> bool {
use nodedb_types::value::Value;
if let Some(cutoff) = system_as_of_ms
&& let Some(idx) = ts_system_idx
&& let Some(v) = row.get(idx)
{
let ts = match v {
Value::Integer(i) => *i,
Value::DateTime(dt) | Value::NaiveDateTime(dt) => dt.micros / 1000,
_ => return false,
};
if ts > cutoff {
return false;
}
}
if let Some(point) = valid_at_ms {
let vf = ts_valid_from_idx
.and_then(|i| row.get(i))
.and_then(|v| match v {
Value::Integer(i) => Some(*i),
Value::DateTime(dt) => Some(dt.micros / 1000),
_ => None,
})
.unwrap_or(i64::MIN);
let vu = ts_valid_until_idx
.and_then(|i| row.get(i))
.and_then(|v| match v {
Value::Integer(i) => Some(*i),
Value::DateTime(dt) => Some(dt.micros / 1000),
_ => None,
})
.unwrap_or(i64::MAX);
if point < vf || point >= vu {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
use nodedb_types::value::Value;
fn row(ts_system: i64, value: i64) -> Vec<Value> {
vec![
Value::Integer(ts_system),
Value::Integer(0),
Value::Integer(i64::MAX),
Value::Integer(value),
]
}
#[test]
fn row_system_time_reads_column() {
assert_eq!(row_system_time(&row(123, 9), Some(0)), 123);
assert_eq!(row_system_time(&row(123, 9), None), i64::MIN);
}
#[test]
fn all_versions_sort_orders_ascending_by_system_time() {
let mut rows = [row(300, 3), row(100, 1), row(200, 2)];
let ts_idx = Some(0);
rows.sort_by_key(|r| row_system_time(r, ts_idx));
let times: Vec<i64> = rows.iter().map(|r| row_system_time(r, ts_idx)).collect();
assert_eq!(times, vec![100, 200, 300]);
let values: Vec<i64> = rows
.iter()
.map(|r| match r.get(3) {
Some(Value::Integer(v)) => *v,
_ => -1,
})
.collect();
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn all_versions_does_not_apply_system_cutoff() {
assert!(bitemporal_row_visible(
&row(999, 1),
Some(0),
Some(1),
Some(2),
None,
None
));
}
}