use std::collections::HashMap;
use std::fmt::Debug;
use std::io::BufRead;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::error::{RedDbError, Result};
use crate::serializer::Serializer;
use crate::storage::{FileStorage, Storage};
use crate::wal::WalOp;
use crate::{DbConfig, RedDb};
#[derive(Serialize, Deserialize)]
#[serde(rename = "Document")]
struct V1Document<T> {
_id: Uuid,
data: T,
_st: V1Status,
}
#[derive(Serialize, Deserialize, PartialEq)]
enum V1Status {
In,
Up,
De,
}
#[allow(private_bounds)]
pub async fn from_v1<T, SE>(v1_path: &str, v2_name: &str) -> Result<usize>
where
for<'de> T: Serialize + Deserialize<'de> + Debug + Clone + PartialEq + Send + Sync + 'static,
SE: Serializer + Debug + 'static,
FileStorage<SE>: Storage + Debug + Send + Sync + 'static,
{
let serializer = SE::default();
let mut live: HashMap<Uuid, Vec<u8>> = HashMap::new();
let file = std::fs::File::open(v1_path)?;
let reader = std::io::BufReader::new(file);
for line in reader.lines() {
let line = line?;
let trimmed = line.trim();
if trimmed.is_empty() {
continue;
}
let v1doc: V1Document<T> = serializer
.deserialize(trimmed.as_bytes())
.map_err(|e| RedDbError::Deserialize(e.to_string()))?;
if v1doc._st == V1Status::De {
live.remove(&v1doc._id);
} else {
let raw = serializer
.serialize(&v1doc.data)
.map_err(|e| RedDbError::Serialize(e.to_string()))?;
live.insert(v1doc._id, raw);
}
}
if live.is_empty() {
return Ok(0);
}
let db: RedDb<SE, FileStorage<SE>> = RedDb::open::<T>(DbConfig::new(v2_name)).await?;
let ops: Vec<(WalOp, Uuid, Vec<u8>)> = live
.iter()
.map(|(id, raw)| (WalOp::Insert, *id, raw.clone()))
.collect();
let count = ops.len();
{
let mut data = db.write_lock().await?;
for (_, id, raw) in &ops {
data.insert(*id, raw.clone());
}
}
db.storage_persist_raw(&ops).await?;
Ok(count)
}