pub mod toc;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use serde::Serialize;
use crate::error::Error;
use crate::error::Result;
use crate::xctrace::Xctrace;
use crate::xml::Cell;
use crate::xml::Schema;
use crate::xml::stream::RowReader;
use crate::xml::stream::RowReaderEvent;
pub use toc::Table;
pub use toc::Toc;
#[derive(Debug, Clone)]
pub struct TraceBundle {
path: PathBuf,
xctrace: Xctrace,
}
impl TraceBundle {
pub fn open(path: impl Into<PathBuf>) -> Result<Self> {
let path = path.into();
if !path.exists() {
return Err(Error::BundleMissing(path));
}
Ok(Self {
path,
xctrace: Xctrace::discover(),
})
}
pub fn with_xctrace(mut self, xctrace: Xctrace) -> Self {
self.xctrace = xctrace;
self
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn xctrace(&self) -> &Xctrace {
&self.xctrace
}
pub fn toc(&self) -> Result<Toc> {
let xml = self.xctrace.export_toc(&self.path)?;
Toc::parse(&xml)
}
pub fn query(&self, xpath: &str) -> Result<QueryResult> {
let xml = self.xctrace.export_xpath(&self.path, xpath)?;
QueryResult::parse(xml)
}
}
#[derive(Debug, Default, Serialize)]
pub struct QueryResult {
pub nodes: Vec<NodeData>,
}
#[derive(Debug, Serialize)]
pub struct NodeData {
pub xpath: Option<String>,
pub schema: Option<Schema>,
pub rows: Vec<Vec<Rc<Cell>>>,
}
impl QueryResult {
pub fn parse(xml: Vec<u8>) -> Result<Self> {
let cursor = std::io::Cursor::new(xml);
let mut reader = RowReader::new(cursor);
let mut result = QueryResult::default();
let mut current: Option<NodeData> = None;
while let Some(ev) = reader.next_event()? {
match ev {
RowReaderEvent::NodeStart(node) => {
if let Some(prev) = current.take() {
result.nodes.push(prev);
}
current = Some(NodeData {
xpath: node.xpath,
schema: node.schema,
rows: Vec::new(),
});
}
RowReaderEvent::Row(cells) => {
if let Some(n) = current.as_mut() {
n.rows.push(cells);
}
}
RowReaderEvent::NodeEnd => {
if let Some(n) = current.take() {
result.nodes.push(n);
}
}
}
}
if let Some(n) = current.take() {
result.nodes.push(n);
}
Ok(result)
}
}