///|
/// Result of comparing a database or ORM adapter with the reference seek
/// semantics. Keeping the expected and actual ids makes CI failures actionable.
pub struct SeekConformance {
expected_ids : Array[String]
actual_ids : Array[String]
} derive(Debug, Eq)
///|
pub fn SeekConformance::expected_ids(self : SeekConformance) -> Array[String] {
self.expected_ids.copy()
}
///|
pub fn SeekConformance::actual_ids(self : SeekConformance) -> Array[String] {
self.actual_ids.copy()
}
///|
pub fn SeekConformance::matches(self : SeekConformance) -> Bool {
self.expected_ids == self.actual_ids
}
///|
/// Return the canonical ids that a database seek query must return. This is a
/// deliberately small reference oracle for adapter tests; production adapters
/// still execute their query inside the database.
pub fn expected_seek_ids(
input : Array[PageRow],
boundary : PagePosition,
sort : Array[SortField],
mode : PageMode,
limit : Int,
limits? : PageLimits = page_limits(),
) -> Result[Array[String], PageError] {
if limit < 1 || limit > limits.max_size {
return Err(
page_error(
InvalidPageSize,
"limit",
"adapter verification limit must be within configured bounds",
),
)
}
let rows = match sort_rows(input, sort, limits~) {
Ok(rows) => rows
Err(error) => return Err(error)
}
let eligible : Array[PageRow] = []
for row in rows {
let compared = match compare_row_to_position(row, boundary, sort) {
Ok(value) => value
Err(error) => return Err(error)
}
let is_eligible = match mode {
ForwardPage => compared > 0
BackwardPage => compared < 0
}
if is_eligible {
eligible.push(row)
}
}
let start = match mode {
ForwardPage => 0
BackwardPage =>
if eligible.length() > limit {
eligible.length() - limit
} else {
0
}
}
let end = if start + limit < eligible.length() {
start + limit
} else {
eligible.length()
}
let ids : Array[String] = []
for index = start; index < end; index = index + 1 {
ids.push(eligible[index].id())
}
Ok(ids)
}
///|
/// Compare ids returned by a real adapter with the canonical reference page.
pub fn verify_seek_ids(
actual_ids : Array[String],
input : Array[PageRow],
boundary : PagePosition,
sort : Array[SortField],
mode : PageMode,
limit : Int,
limits? : PageLimits = page_limits(),
) -> Result[SeekConformance, PageError] {
let expected_ids = match
expected_seek_ids(input, boundary, sort, mode, limit, limits~) {
Ok(ids) => ids
Err(error) => return Err(error)
}
Ok({ expected_ids, actual_ids: actual_ids.copy() })
}