use object_store::path::Path;
use olai_storage_credentials::{StorageLocation, StorageProvider, StorageScope};
use url::Url;
use crate::{Error, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageLocationUrl {
raw: Url,
location: StorageLocation,
}
impl StorageLocationUrl {
pub fn parse(url: impl AsRef<str>) -> Result<Self> {
let url = url.as_ref();
let raw = Url::parse(url)
.map_err(|e| Error::invalid_argument(format!("invalid storage location: {e}")))?;
let location =
StorageLocation::parse(&raw).map_err(|e| Error::invalid_argument(e.to_string()))?;
Ok(Self { raw, location })
}
pub fn raw(&self) -> &Url {
&self.raw
}
pub fn location(&self) -> &StorageLocation {
&self.location
}
pub fn scope(&self) -> StorageScope {
StorageScope::new(self.location.clone())
}
pub fn path(&self) -> &Path {
self.location.path()
}
pub fn is_local(&self) -> bool {
self.location.provider() == StorageProvider::Local
}
pub fn starts_with(&self, prefix: &StorageLocationUrl) -> bool {
self.location.starts_with(&prefix.location)
}
pub fn overlaps(&self, other: &StorageLocationUrl) -> bool {
self.starts_with(other) || other.starts_with(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn parse(url: &str) -> StorageLocationUrl {
StorageLocationUrl::parse(url).unwrap()
}
#[test]
fn overlap_is_segment_aware_and_symmetric() {
assert!(parse("s3://b/data").overlaps(&parse("s3://b/data/sub")));
assert!(parse("s3://b/data/sub").overlaps(&parse("s3://b/data")));
assert!(parse("s3://b/data").overlaps(&parse("s3://b/data/")));
assert!(!parse("s3://b/data").overlaps(&parse("s3://b/data-secret")));
assert!(!parse("s3://b/data").overlaps(&parse("s3://c/data")));
}
#[test]
fn azure_spellings_compare_canonically() {
let abfss = parse("abfss://container@account.dfs.core.windows.net/data/tab");
let https = parse("https://account.blob.core.windows.net/container/data");
assert!(abfss.starts_with(&https));
assert!(!https.starts_with(&abfss));
}
#[test]
fn local_locations_are_detected() {
assert!(parse("file:///tmp/data").is_local());
assert!(!parse("s3://b/data").is_local());
assert!(StorageLocationUrl::parse("not a url").is_err());
}
}