use std::path::Path;
use crate::common::error::{BioFormatsError, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MdbTable {
pub name: String,
pub columns: Vec<String>,
pub rows: Vec<Vec<String>>,
}
pub fn parse_database(path: &Path) -> Result<Vec<MdbTable>> {
let mut db = open_db(path)?;
let table_names = user_table_names(&mut db)?;
let mut tables = Vec::with_capacity(table_names.len());
for name in table_names {
if let Some(table) = read_named_table(&mut db, &name) {
tables.push(table);
}
}
Ok(tables)
}
pub fn parse_table(path: &Path, name: &str) -> Result<Option<MdbTable>> {
let mut db = open_db(path)?;
Ok(read_named_table(&mut db, name))
}
fn open_db(path: &Path) -> Result<mdbtools::safe::Db> {
mdbtools::safe::Db::open(path).map_err(|e| {
BioFormatsError::UnsupportedFormat(format!(
"MDB database could not be opened by mdbtools-rs: {} ({e})",
path.display()
))
})
}
fn user_table_names(db: &mut mdbtools::safe::Db) -> Result<Vec<String>> {
let catalog = db.read_catalog(mdbtools::MDB_TABLE).ok_or_else(|| {
BioFormatsError::InvalidData("MDB catalog could not be read by mdbtools-rs".into())
})?;
Ok(catalog
.iter()
.filter(|entry| entry.is_user_table())
.map(|entry| entry.name().to_string())
.collect())
}
fn read_named_table(db: &mut mdbtools::safe::Db, name: &str) -> Option<MdbTable> {
let mut table = db.read_table(name)?;
let columns: Vec<String> = table.columns().map(|c| c.name().to_string()).collect();
let rows: Vec<Vec<String>> = table.rows().collect();
Some(MdbTable {
name: table.name().to_string(),
columns,
rows,
})
}