diff --git a/datafusion/datasource-parquet/src/reader.rs b/datafusion/datasource-parquet/src/reader.rs index 06ab40fdd27cd..a1d1bde02dd9b 100644 --- a/datafusion/datasource-parquet/src/reader.rs +++ b/datafusion/datasource-parquet/src/reader.rs @@ -68,7 +68,7 @@ pub trait ParquetFileSchemaProvider: Debug + Send + Sync + 'static { /// such as pre-cached metadata, I/O coalescing, etc. /// /// See [`DefaultParquetFileReaderFactory`] for a simple implementation. -pub trait ParquetFileReaderFactory: Debug + Send + Sync + 'static { +pub trait ParquetFileReaderFactory: Any + Debug + Send + Sync { /// Provides an `AsyncFileReader` for reading data from a parquet file specified /// /// # Notes @@ -92,6 +92,18 @@ pub trait ParquetFileReaderFactory: Debug + Send + Sync + 'static { ) -> datafusion_common::Result>; } +impl dyn ParquetFileReaderFactory { + /// Returns `true` if this factory is of type `T`. + pub fn is(&self) -> bool { + (self as &dyn Any).is::() + } + + /// Attempts to downcast this factory to a concrete type `T`. + pub fn downcast_ref(&self) -> Option<&T> { + (self as &dyn Any).downcast_ref() + } +} + /// Default implementation of [`ParquetFileReaderFactory`] /// /// This implementation: diff --git a/datafusion/datasource-parquet/src/source.rs b/datafusion/datasource-parquet/src/source.rs index fbb6265847afc..7bd37b97c5bd4 100644 --- a/datafusion/datasource-parquet/src/source.rs +++ b/datafusion/datasource-parquet/src/source.rs @@ -1465,6 +1465,40 @@ mod tests { assert!(source.filter().is_some()); } + #[test] + fn parquet_file_reader_factory_downcasts_to_concrete_type() { + use crate::CachedParquetFileReaderFactory; + use datafusion_execution::cache::cache_manager::FileMetadataCache; + use datafusion_execution::cache::default_cache::DefaultCache; + use object_store::memory::InMemory; + + let store: Arc = Arc::new(InMemory::new()); + let source = ParquetSource::new(Arc::new(Schema::empty())) + .with_parquet_file_reader_factory(Arc::new( + DefaultParquetFileReaderFactory::new(Arc::clone(&store)), + )); + let factory = source.parquet_file_reader_factory().unwrap(); + assert!(factory.is::()); + assert!( + factory + .downcast_ref::() + .is_none() + ); + + let cache: Arc = Arc::new(DefaultCache::new(1024)); + let source = ParquetSource::new(Arc::new(Schema::empty())) + .with_parquet_file_reader_factory(Arc::new( + CachedParquetFileReaderFactory::new(store, cache), + )); + let factory = source.parquet_file_reader_factory().unwrap(); + assert!(factory.is::()); + assert!( + factory + .downcast_ref::() + .is_none() + ); + } + /// Render a `ParquetSource`'s `fmt_extra` output as a `String` for /// inspection in tests. fn render_fmt_extra(source: &ParquetSource, t: DisplayFormatType) -> String { diff --git a/docs/source/library-user-guide/upgrading/56.0.0.md b/docs/source/library-user-guide/upgrading/56.0.0.md index 2ec01c99479c4..be44bc583d43c 100644 --- a/docs/source/library-user-guide/upgrading/56.0.0.md +++ b/docs/source/library-user-guide/upgrading/56.0.0.md @@ -1306,3 +1306,18 @@ without declaring one, use `FileScanConfigBuilder::with_preserve_order(true)`. Code that reads `FileScanConfig::preserve_order` to decide whether files may be reordered should call `FileScanConfig::preserves_file_order()` instead, which also accounts for the output ordering. + +### `ParquetFileReaderFactory` adds `Any` as a supertrait + +To enable downcasting of `dyn ParquetFileReaderFactory` to concrete factory +types (via `is::()` / `downcast_ref::()`), the +`ParquetFileReaderFactory` trait now has `Any` as a supertrait: + +```diff +- pub trait ParquetFileReaderFactory: Debug + Send + Sync + 'static ++ pub trait ParquetFileReaderFactory: Any + Debug + Send + Sync +``` + +The trait already required `'static`, which `Any` implies, so existing +implementations need no changes. `ParquetSource::parquet_file_reader_factory` +returns the trait object to downcast.