use std::{collections::BTreeMap, fmt::Debug};
use fjall::{Keyspace, Slice};
use xxhash_rust::xxh3::Xxh3Default;
use crate::{
Cid, Record,
error::{DbError, DbResult},
record::{MigrationFn, MigrationRes, MigrationType},
utils::{GroupVal, HashPoints},
};
pub(crate) fn collection_name(base_name: &str, version: u16) -> String {
format!("{base_name}:v{version}")
}
pub(crate) fn run_migration<Item>(
source: &Keyspace,
target: &Keyspace,
migration_fn: MigrationFn<Item, Slice>,
) -> DbResult<u64>
where
Item: Record<Value = Slice>,
{
let mut count = 0u64;
for item in source.iter() {
let (k, bytes) = item.into_inner()?;
let key = k.as_ref();
match migration_fn(key, &bytes) {
MigrationRes::Unchanged(..) => {
target.insert(key, bytes)?;
count += 1;
}
MigrationRes::Deleted => {}
MigrationRes::Changed {
migration_type,
new_key,
new_value,
} => {
match migration_type {
MigrationType::Key => {
let encoded = Cid::encode(&new_key);
target.insert(encoded.as_ref(), bytes)?;
}
MigrationType::Value => {
let val = Record::ser(&new_value);
target.insert(key, val)?;
}
MigrationType::Entry => {
let encoded = Cid::encode(&new_key);
let val = Record::ser(&new_value);
target.insert(encoded.as_ref(), val)?;
}
}
count += 1;
}
}
}
Ok(count)
}
pub(crate) fn compute_hashpoints<Item, F>(
iter: impl Iterator<Item = (Slice, Slice)>,
hashpoints: &HashPoints,
mut handle_fn: Option<F>,
mut on_entry: impl FnMut(&Item::SelfId, &Item),
) -> DbResult<(u64, u64)>
where
Item: Record<Value = Slice> + Debug,
F: for<'a> FnMut(&'a Item::SelfId, &'a Item),
{
let mut map = BTreeMap::<u32, Xxh3Default>::new();
let mut count = 0u64;
for (k, bytes) in iter {
let key = <Item as Record>::SelfId::from_bytes(&k).map_err(DbError::from)?;
let val = <Item as Record>::deser(&bytes);
if let Some(f) = handle_fn.as_mut() {
f(&key, &val);
}
on_entry(&key, &val);
count += 1;
let group_id = key.group_id();
let hasher = map.entry(group_id).or_default();
hasher.update(&k);
hasher.update(&bytes);
}
let mut hasher = Xxh3Default::new();
for (k, v) in map {
hasher.update(&k.to_le_bytes());
hashpoints.insert(
k,
GroupVal {
hash: v.digest(),
changed: false,
},
);
}
Ok((hasher.digest(), count))
}