///|
#derive(Debug)
pub suberror ReindexError {
DifferentIndex
InvalidGeneration
IncompatibleFields
}
///|
pub extend ReindexError with @debug.Debug::{to_repr}
///|
/// A checked projection from a frozen source index to its replacement.
pub struct ReindexPlan {
priv source_spec : KeySpec
priv target_spec : KeySpec
priv positions : Array[Int32]
}
///|
fn Field::same_kind(self : Field, other : Field) -> Bool {
match (self, other) {
(BytesField(_), BytesField(_)) | (Int64Field(_), Int64Field(_)) => true
_ => false
}
}
///|
pub fn ReindexPlan::new(
source : IndexContract,
target : IndexContract,
) -> ReindexPlan raise ReindexError {
if source.index_id != target.index_id {
raise DifferentIndex
}
if target.generation <= source.generation {
raise InvalidGeneration
}
if source.field_ids.length() != target.field_ids.length() {
raise IncompatibleFields
}
let by_id : Map[Bytes, Int32] = Map([])
for position, id in source.field_ids {
by_id[id] = position
}
let positions = []
for position, id in target.field_ids {
match by_id.get(id) {
Some(old) if source.spec.fields[old].same_kind(
target.spec.fields[position],
) => positions.push(old)
_ => raise IncompatibleFields
}
}
{ source_spec: source.spec, target_spec: target.spec, positions, }
}
///|
pub fn ReindexPlan::rekey(
self : ReindexPlan,
key : Bytes,
) -> Bytes raise KeyError {
let old_values = self.source_spec.decode(key)
self.target_spec.encode(self.positions.map(fn(index) { old_values[index] }))
}