| # Licensed to the Apache Software Foundation (ASF) under one | |
| # or more contributor license agreements. See the NOTICE file | |
| # distributed with this work for additional information | |
| # regarding copyright ownership. The ASF licenses this file | |
| # to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance | |
| # with the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, | |
| # software distributed under the License is distributed on an | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| # KIND, either express or implied. See the License for the | |
| # specific language governing permissions and limitations | |
| # under the License. | |
| from __future__ import annotations | |
| import pyarrow as pa | |
| import pyarrow.dataset as ds | |
| import pytest | |
| from datafusion import SessionContext, Table | |
| from datafusion.catalog import Schema | |
| from datafusion_ffi_example import MyCatalogProvider, MyCatalogProviderList | |
| def create_test_dataset() -> Table: | |
| """Create a simple test dataset.""" | |
| batch = pa.RecordBatch.from_arrays( | |
| [pa.array([100, 200, 300]), pa.array([1.1, 2.2, 3.3])], | |
| names=["id", "value"], | |
| ) | |
| dataset = ds.dataset([batch]) | |
| return Table(dataset) | |
| @pytest.mark.parametrize("inner_capsule", [True, False]) | |
| def test_ffi_catalog_provider_list(inner_capsule: bool) -> None: | |
| """Test basic FFI CatalogProviderList functionality.""" | |
| ctx = SessionContext() | |
| # Register FFI catalog | |
| catalog_provider_list = MyCatalogProviderList() | |
| if inner_capsule: | |
| catalog_provider_list = ( | |
| catalog_provider_list.__datafusion_catalog_provider_list__(ctx) | |
| ) | |
| ctx.register_catalog_provider_list(catalog_provider_list) | |
| # Verify the catalog exists | |
| catalog = ctx.catalog("auto_ffi_catalog") | |
| schema_names = catalog.names() | |
| assert "my_schema" in schema_names | |
| ctx.register_catalog_provider("second", MyCatalogProvider()) | |
| assert ctx.catalog_names() == {"auto_ffi_catalog", "second"} | |
| @pytest.mark.parametrize("inner_capsule", [True, False]) | |
| def test_ffi_catalog_provider_basic(inner_capsule: bool) -> None: | |
| """Test basic FFI CatalogProvider functionality.""" | |
| ctx = SessionContext() | |
| # Register FFI catalog | |
| catalog_provider = MyCatalogProvider() | |
| if inner_capsule: | |
| catalog_provider = catalog_provider.__datafusion_catalog_provider__(ctx) | |
| ctx.register_catalog_provider("ffi_catalog", catalog_provider) | |
| # Verify the catalog exists | |
| catalog = ctx.catalog("ffi_catalog") | |
| schema_names = catalog.names() | |
| assert "my_schema" in schema_names | |
| # Query the pre-populated table | |
| result = ctx.sql("SELECT * FROM ffi_catalog.my_schema.my_table").collect() | |
| assert len(result) == 2 | |
| assert result[0].num_columns == 2 | |
| def test_ffi_catalog_provider_register_schema(): | |
| """Test registering additional schemas to FFI CatalogProvider.""" | |
| ctx = SessionContext() | |
| catalog_provider = MyCatalogProvider() | |
| ctx.register_catalog_provider("ffi_catalog", catalog_provider) | |
| catalog = ctx.catalog("ffi_catalog") | |
| # Register a new memory schema | |
| new_schema = Schema.memory_schema() | |
| catalog.register_schema("additional_schema", new_schema) | |
| # Verify the schema was registered | |
| assert "additional_schema" in catalog.names() | |
| # Add a table to the new schema | |
| new_schema.register_table("new_table", create_test_dataset()) | |
| # Query the new table | |
| result = ctx.sql("SELECT * FROM ffi_catalog.additional_schema.new_table").collect() | |
| assert len(result) == 1 | |
| assert result[0].column(0) == pa.array([100, 200, 300]) | |
| def test_ffi_catalog_provider_deregister_schema(): | |
| """Test deregistering schemas from FFI CatalogProvider.""" | |
| ctx = SessionContext() | |
| catalog_provider = MyCatalogProvider() | |
| ctx.register_catalog_provider("ffi_catalog", catalog_provider) | |
| catalog = ctx.catalog("ffi_catalog") | |
| # Register two schemas | |
| schema1 = Schema.memory_schema() | |
| schema2 = Schema.memory_schema() | |
| catalog.register_schema("temp_schema1", schema1) | |
| catalog.register_schema("temp_schema2", schema2) | |
| # Verify both exist | |
| names = catalog.names() | |
| assert "temp_schema1" in names | |
| assert "temp_schema2" in names | |
| # Deregister one schema | |
| catalog.deregister_schema("temp_schema1") | |
| # Verify it's gone | |
| names = catalog.names() | |
| assert "temp_schema1" not in names | |
| assert "temp_schema2" in names |