use object_store::path::Path;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use url::Url;
use super::uri::UriParser;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum UPath {
Local(PathBuf),
S3 {
bucket: String,
#[serde(skip)]
path: Path,
},
}
impl UPath {
pub fn parse(uri_string: &str) -> Result<Self, String> {
let uri = UriParser::try_from(uri_string)?;
match uri.scheme.as_str() {
"file" => Ok(Self::Local(PathBuf::from(uri.path))),
"s3" => Ok(Self::S3 {
bucket: uri.host,
path: Path::from(uri.path),
}),
_ => Err("unsupported scheme".into()),
}
}
pub fn to_uri(&self) -> Url {
match self {
Self::Local(path) => Url::from_file_path(path).unwrap(),
Self::S3 { bucket, path } => {
let mut uri = Url::parse("s3://").unwrap();
uri.set_host(Some(bucket)).unwrap();
uri.set_path(&path.to_string());
uri
}
}
}
pub fn to_string(&self) -> String {
format!("UPath({})", self.to_uri())
}
pub fn join(&self, sub_path: &str) -> Self {
let mut uri = self.to_uri();
uri.set_path(&format!("{}/{}", uri.path(), sub_path));
Self::parse(&uri.to_string()).unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use tracing::info;
#[test]
fn test_new_local() {
let local_uri = crate::utils::local_uri_parquet();
let upath = UPath::parse(&local_uri).unwrap();
info!("upath: {:?}", upath);
assert_eq!(upath.to_uri().to_string(), local_uri);
let upath_string = upath.to_string();
assert_eq!(upath_string, format!("UPath({})", local_uri));
let UPath::Local(fpath) = upath else { panic!() };
assert_eq!(local_uri, format!("file://{}", fpath.to_string_lossy()));
}
#[test]
fn test_new_s3() {
let upath = UPath::parse(crate::utils::TEST_S3_URI).unwrap();
assert_eq!(upath.to_uri().to_string(), crate::utils::TEST_S3_URI);
assert_eq!(
upath,
UPath::S3 {
bucket: "quilt-example".into(),
path: "akarve/test_dest/README.md".into()
}
);
}
#[test]
fn test_new_invalid() {
UPath::parse("blah://123").expect_err("did not get an error");
}
}