@@ -23,6 +23,7 @@ use glob::Pattern;
2323use itertools:: Itertools ;
2424use object_store:: path:: Path ;
2525use object_store:: { ObjectMeta , ObjectStore } ;
26+ use percent_encoding;
2627use url:: Url ;
2728
2829/// A parsed URL identifying files for a listing table, see [`ListingTableUrl::parse`]
@@ -108,7 +109,9 @@ impl ListingTableUrl {
108109
109110 /// Creates a new [`ListingTableUrl`] from a url and optional glob expression
110111 fn new ( url : Url , glob : Option < Pattern > ) -> Self {
111- let prefix = Path :: parse ( url. path ( ) ) . expect ( "should be URL safe" ) ;
112+ let decoded_path =
113+ percent_encoding:: percent_decode_str ( url. path ( ) ) . decode_utf8_lossy ( ) ;
114+ let prefix = Path :: from ( decoded_path. as_ref ( ) ) ;
112115 Self { url, prefix, glob }
113116 }
114117
@@ -246,6 +249,15 @@ mod tests {
246249 let url = ListingTableUrl :: parse ( "file:///foo" ) . unwrap ( ) ;
247250 let child = Path :: parse ( "/foob/bar" ) . unwrap ( ) ;
248251 assert ! ( url. strip_prefix( & child) . is_none( ) ) ;
252+
253+ let url = ListingTableUrl :: parse ( "file:///foo/ bar" ) . unwrap ( ) ;
254+ assert_eq ! ( url. prefix. as_ref( ) , "foo/ bar" ) ;
255+
256+ let url = ListingTableUrl :: parse ( "file:///foo/bar?" ) . unwrap ( ) ;
257+ assert_eq ! ( url. prefix. as_ref( ) , "foo/bar" ) ;
258+
259+ let url = ListingTableUrl :: parse ( "file:///foo/😺" ) . unwrap ( ) ;
260+ assert_eq ! ( url. prefix. as_ref( ) , "foo/%F0%9F%98%BA" ) ;
249261 }
250262
251263 #[ test]
0 commit comments