@@ -698,6 +698,64 @@ impl ObjectStorage for BlobStore {
698698 Ok ( streams)
699699 }
700700
701+ async fn list_hours (
702+ & self ,
703+ stream_name : & str ,
704+ date : & str ,
705+ ) -> Result < Vec < String > , ObjectStorageError > {
706+ let pre = object_store:: path:: Path :: from ( format ! ( "{}/{}/" , stream_name, date) ) ;
707+ let resp = self . client . list_with_delimiter ( Some ( & pre) ) . await ?;
708+
709+ let hours = resp
710+ . common_prefixes
711+ . iter ( )
712+ . filter_map ( |path| {
713+ let path_str = path. as_ref ( ) ;
714+ if let Some ( stripped) = path_str. strip_prefix ( & format ! ( "{}/{}/" , stream_name, date) )
715+ {
716+ // Remove trailing slash if present, otherwise use as is
717+ let clean_path = stripped. strip_suffix ( '/' ) . unwrap_or ( stripped) ;
718+ Some ( clean_path. to_string ( ) )
719+ } else {
720+ None
721+ }
722+ } )
723+ . filter ( |dir| dir. starts_with ( "hour=" ) )
724+ . collect ( ) ;
725+
726+ Ok ( hours)
727+ }
728+
729+ async fn list_minutes (
730+ & self ,
731+ stream_name : & str ,
732+ date : & str ,
733+ hour : & str ,
734+ ) -> Result < Vec < String > , ObjectStorageError > {
735+ let pre = object_store:: path:: Path :: from ( format ! ( "{}/{}/{}/" , stream_name, date, hour) ) ;
736+ let resp = self . client . list_with_delimiter ( Some ( & pre) ) . await ?;
737+
738+ let minutes = resp
739+ . common_prefixes
740+ . iter ( )
741+ . filter_map ( |path| {
742+ let path_str = path. as_ref ( ) ;
743+ if let Some ( stripped) =
744+ path_str. strip_prefix ( & format ! ( "{}/{}/{}/" , stream_name, date, hour) )
745+ {
746+ // Remove trailing slash if present, otherwise use as is
747+ let clean_path = stripped. strip_suffix ( '/' ) . unwrap_or ( stripped) ;
748+ Some ( clean_path. to_string ( ) )
749+ } else {
750+ None
751+ }
752+ } )
753+ . filter ( |dir| dir. starts_with ( "minute=" ) )
754+ . collect ( ) ;
755+
756+ Ok ( minutes)
757+ }
758+
701759 async fn list_manifest_files (
702760 & self ,
703761 stream_name : & str ,
0 commit comments