|
15 | 15 | // specific language governing permissions and limitations |
16 | 16 | // under the License. |
17 | 17 |
|
| 18 | +use async_trait::async_trait; |
| 19 | +use std::any::Any; |
18 | 20 | use std::io::Write; |
19 | 21 |
|
| 22 | +use datafusion::datasource::datasource::TableProviderFactory; |
| 23 | +use datafusion::execution::context::SessionState; |
| 24 | +use datafusion_expr::TableType; |
20 | 25 | use tempfile::TempDir; |
21 | 26 |
|
22 | 27 | use super::*; |
@@ -360,6 +365,74 @@ async fn create_pipe_delimited_csv_table() -> Result<()> { |
360 | 365 | Ok(()) |
361 | 366 | } |
362 | 367 |
|
| 368 | +struct TestTableProvider {} |
| 369 | + |
| 370 | +impl TestTableProvider {} |
| 371 | + |
| 372 | +#[async_trait] |
| 373 | +impl TableProvider for TestTableProvider { |
| 374 | + fn as_any(&self) -> &dyn Any { |
| 375 | + unimplemented!("TestTableProvider is a stub for testing.") |
| 376 | + } |
| 377 | + |
| 378 | + fn schema(&self) -> SchemaRef { |
| 379 | + unimplemented!("TestTableProvider is a stub for testing.") |
| 380 | + } |
| 381 | + |
| 382 | + fn table_type(&self) -> TableType { |
| 383 | + unimplemented!("TestTableProvider is a stub for testing.") |
| 384 | + } |
| 385 | + |
| 386 | + async fn scan( |
| 387 | + &self, |
| 388 | + _ctx: &SessionState, |
| 389 | + _projection: &Option<Vec<usize>>, |
| 390 | + _filters: &[Expr], |
| 391 | + _limit: Option<usize>, |
| 392 | + ) -> Result<Arc<dyn ExecutionPlan>> { |
| 393 | + unimplemented!("TestTableProvider is a stub for testing.") |
| 394 | + } |
| 395 | +} |
| 396 | + |
| 397 | +struct TestTableFactory {} |
| 398 | + |
| 399 | +impl TableProviderFactory for TestTableFactory { |
| 400 | + fn create(&self, _name: &str, _path: &str) -> Arc<dyn TableProvider> { |
| 401 | + Arc::new(TestTableProvider {}) |
| 402 | + } |
| 403 | +} |
| 404 | + |
| 405 | +#[tokio::test] |
| 406 | +async fn create_custom_table() -> Result<()> { |
| 407 | + let mut ctx = SessionContext::new(); |
| 408 | + ctx.register_table_factory("DELTATABLE", Arc::new(TestTableFactory {})); |
| 409 | + |
| 410 | + let sql = "CREATE EXTERNAL TABLE dt STORED AS DELTATABLE LOCATION 's3://bucket/schema/table';"; |
| 411 | + ctx.sql(sql).await.unwrap(); |
| 412 | + |
| 413 | + let cat = ctx.catalog("datafusion").unwrap(); |
| 414 | + let schema = cat.schema("public").unwrap(); |
| 415 | + let exists = schema.table_exist("dt"); |
| 416 | + assert!(exists, "Table should have been created!"); |
| 417 | + |
| 418 | + Ok(()) |
| 419 | +} |
| 420 | + |
| 421 | +#[tokio::test] |
| 422 | +async fn create_bad_custom_table() { |
| 423 | + let ctx = SessionContext::new(); |
| 424 | + |
| 425 | + let sql = "CREATE EXTERNAL TABLE dt STORED AS DELTATABLE LOCATION 's3://bucket/schema/table';"; |
| 426 | + let res = ctx.sql(sql).await; |
| 427 | + match res { |
| 428 | + Ok(_) => panic!("Registration of tables without factories should fail"), |
| 429 | + Err(e) => { |
| 430 | + assert!(e.to_string().contains("Unable to find factory for"), "Registration of tables without factories should throw correct error") |
| 431 | + } |
| 432 | + } |
| 433 | + } |
| 434 | +} |
| 435 | + |
363 | 436 | #[tokio::test] |
364 | 437 | async fn create_csv_table_empty_file() -> Result<()> { |
365 | 438 | let ctx = |
|
0 commit comments