@@ -89,7 +89,13 @@ pub fn register_listing_table<T: ListingTableLike>() {
8989/// Attempt to cast the given TableProvider into a [`ListingTableLike`].
9090/// If the table's type has not been registered using [`register_listing_table`], will return `None`.
9191pub fn cast_to_listing_table ( table : & dyn TableProvider ) -> Option < & dyn ListingTableLike > {
92- TABLE_TYPE_REGISTRY . cast_to_listing_table ( table)
92+ TABLE_TYPE_REGISTRY
93+ . cast_to_listing_table ( table)
94+ . or_else ( || {
95+ TABLE_TYPE_REGISTRY
96+ . cast_to_decorator ( table)
97+ . and_then ( |decorator| cast_to_listing_table ( decorator. base ( ) ) )
98+ } )
9399}
94100
95101/// A hive-partitioned table in object storage that is defined by a user-provided query.
@@ -110,7 +116,24 @@ pub fn register_materialized<T: Materialized>() {
110116/// Attempt to cast the given TableProvider into a [`Materialized`].
111117/// If the table's type has not been registered using [`register_materialized`], will return `None`.
112118pub fn cast_to_materialized ( table : & dyn TableProvider ) -> Option < & dyn Materialized > {
113- TABLE_TYPE_REGISTRY . cast_to_materialized ( table)
119+ TABLE_TYPE_REGISTRY . cast_to_materialized ( table) . or_else ( || {
120+ TABLE_TYPE_REGISTRY
121+ . cast_to_decorator ( table)
122+ . and_then ( |decorator| cast_to_materialized ( decorator. base ( ) ) )
123+ } )
124+ }
125+
126+ /// A `TableProvider` that decorates other `TableProvider`s.
127+ /// Sometimes users may implement a `TableProvider` that overrides functionality of a base `TableProvider`.
128+ /// This API allows the decorator to also be recognized as `ListingTableLike` or `Materialized` automatically.
129+ pub trait Decorator : TableProvider + ' static {
130+ /// The underlying `TableProvider` that this decorator wraps.
131+ fn base ( & self ) -> & dyn TableProvider ;
132+ }
133+
134+ /// Register `T` as a [`Decorator`].
135+ pub fn register_decorator < T : Decorator > ( ) {
136+ TABLE_TYPE_REGISTRY . register_decorator :: < T > ( )
114137}
115138
116139type Downcaster < T > = Arc < dyn Fn ( & dyn Any ) -> Option < & T > + Send + Sync > ;
@@ -123,6 +146,7 @@ type Downcaster<T> = Arc<dyn Fn(&dyn Any) -> Option<&T> + Send + Sync>;
123146struct TableTypeRegistry {
124147 listing_table_accessors : DashMap < TypeId , ( & ' static str , Downcaster < dyn ListingTableLike > ) > ,
125148 materialized_accessors : DashMap < TypeId , ( & ' static str , Downcaster < dyn Materialized > ) > ,
149+ decorator_accessors : DashMap < TypeId , ( & ' static str , Downcaster < dyn Decorator > ) > ,
126150}
127151
128152impl Debug for TableTypeRegistry {
@@ -145,6 +169,7 @@ impl Default for TableTypeRegistry {
145169 let new = Self {
146170 listing_table_accessors : DashMap :: new ( ) ,
147171 materialized_accessors : DashMap :: new ( ) ,
172+ decorator_accessors : DashMap :: new ( ) ,
148173 } ;
149174 new. register_listing_table :: < ListingTable > ( ) ;
150175
@@ -175,6 +200,16 @@ impl TableTypeRegistry {
175200 self . register_listing_table :: < T > ( ) ;
176201 }
177202
203+ fn register_decorator < T : Decorator > ( & self ) {
204+ self . decorator_accessors . insert (
205+ TypeId :: of :: < T > ( ) ,
206+ (
207+ type_name :: < T > ( ) ,
208+ Arc :: new ( |any| any. downcast_ref :: < T > ( ) . map ( |t| t as & dyn Decorator ) ) ,
209+ ) ,
210+ ) ;
211+ }
212+
178213 fn cast_to_listing_table < ' a > (
179214 & ' a self ,
180215 table : & ' a dyn TableProvider ,
@@ -192,4 +227,10 @@ impl TableTypeRegistry {
192227 . get ( & table. as_any ( ) . type_id ( ) )
193228 . and_then ( |r| r. value ( ) . 1 ( table. as_any ( ) ) )
194229 }
230+
231+ fn cast_to_decorator < ' a > ( & ' a self , table : & ' a dyn TableProvider ) -> Option < & ' a dyn Decorator > {
232+ self . decorator_accessors
233+ . get ( & table. as_any ( ) . type_id ( ) )
234+ . and_then ( |r| r. value ( ) . 1 ( table. as_any ( ) ) )
235+ }
195236}
0 commit comments