use std::path::PathBuf;
use std::sync::Arc;
use arrow_array::{BinaryArray, RecordBatch, StringArray};
use arrow_schema::{DataType, Field, Schema};
use edgestore::{EdgestoreConfig, Engine};
use parquet::arrow::ArrowWriter;
use parquet::file::properties::WriterProperties;
fn main() -> anyhow::Result<()> {
let args: Vec<String> = std::env::args().collect();
if args.len() != 4 {
eprintln!("Usage: parquet_export <db_path> <namespace> <output.parquet>");
std::process::exit(1);
}
let db_path = PathBuf::from(&args[1]);
let namespace = args[2].as_bytes();
let out_path = PathBuf::from(&args[3]);
let engine = Engine::open(EdgestoreConfig::new(&db_path))?;
let records = engine.range(namespace, b"", b"\xff")?;
if records.is_empty() {
println!("No records found in namespace {:?}", args[2]);
return Ok(());
}
let schema = Arc::new(Schema::new(vec![
Field::new("key", DataType::Binary, false),
Field::new("value", DataType::Utf8, true),
]));
let mut keys: Vec<&[u8]> = Vec::with_capacity(records.len());
let mut values: Vec<Option<&str>> = Vec::with_capacity(records.len());
for (k, v) in &records {
keys.push(k.as_slice());
values.push(std::str::from_utf8(v.as_slice()).ok());
}
let batch = RecordBatch::try_new(
schema.clone(),
vec![
Arc::new(BinaryArray::from(keys)),
Arc::new(StringArray::from(values)),
],
)?;
let file = std::fs::File::create(&out_path)?;
let props = WriterProperties::builder()
.set_compression(parquet::basic::Compression::ZSTD(Default::default()))
.build();
let mut writer = ArrowWriter::try_new(file, schema, Some(props))?;
writer.write(&batch)?;
writer.close()?;
println!(
"Exported {} records from namespace {:?} to {}",
records.len(),
args[2],
out_path.display()
);
Ok(())
}