From 8a3cab626df820ff1b9bf703f2346d34207ad4a9 Mon Sep 17 00:00:00 2001 From: Huangshi Tian Date: Sun, 29 Mar 2026 20:11:07 +0000 Subject: [PATCH] feat(inspect): Add base class for metadata table support --- src/iceberg/CMakeLists.txt | 4 + src/iceberg/inspect/history_table.cc | 56 ++++++ src/iceberg/inspect/history_table.h | 57 ++++++ src/iceberg/inspect/metadata_table.cc | 87 +++++++++ src/iceberg/inspect/metadata_table.h | 180 ++++++++++++++++++ src/iceberg/inspect/metadata_table_factory.cc | 37 ++++ src/iceberg/inspect/metadata_table_factory.h | 61 ++++++ src/iceberg/inspect/snapshots_table.cc | 61 ++++++ src/iceberg/inspect/snapshots_table.h | 57 ++++++ src/iceberg/test/CMakeLists.txt | 2 + src/iceberg/test/metadata_table_test.cc | 141 ++++++++++++++ 11 files changed, 743 insertions(+) create mode 100644 src/iceberg/inspect/history_table.cc create mode 100644 src/iceberg/inspect/history_table.h create mode 100644 src/iceberg/inspect/metadata_table.cc create mode 100644 src/iceberg/inspect/metadata_table.h create mode 100644 src/iceberg/inspect/metadata_table_factory.cc create mode 100644 src/iceberg/inspect/metadata_table_factory.h create mode 100644 src/iceberg/inspect/snapshots_table.cc create mode 100644 src/iceberg/inspect/snapshots_table.h create mode 100644 src/iceberg/test/metadata_table_test.cc diff --git a/src/iceberg/CMakeLists.txt b/src/iceberg/CMakeLists.txt index 21e87bee4..1261fd93d 100644 --- a/src/iceberg/CMakeLists.txt +++ b/src/iceberg/CMakeLists.txt @@ -42,6 +42,9 @@ set(ICEBERG_SOURCES expression/term.cc file_reader.cc file_writer.cc + inspect/history_table.cc + inspect/metadata_table_factory.cc + inspect/snapshots_table.cc inheritable_metadata.cc json_serde.cc location_provider.cc @@ -57,6 +60,7 @@ set(ICEBERG_SOURCES manifest/v2_metadata.cc manifest/v3_metadata.cc metadata_columns.cc + inspect/metadata_table.cc metrics_config.cc name_mapping.cc partition_field.cc diff --git a/src/iceberg/inspect/history_table.cc b/src/iceberg/inspect/history_table.cc new file mode 100644 index 000000000..55fd75168 --- /dev/null +++ b/src/iceberg/inspect/history_table.cc @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#include "iceberg/inspect/history_table.h" + +#include +#include + +#include "iceberg/inspect/metadata_table.h" +#include "iceberg/schema.h" +#include "iceberg/schema_field.h" +#include "iceberg/table_identifier.h" +#include "iceberg/type.h" + +namespace iceberg { + +HistoryTable::HistoryTable(std::shared_ptr table) + : BaseMetadataTable(table, CreateName(table->name()), CreateSchema()) {} + +HistoryTable::~HistoryTable() = default; + +std::shared_ptr HistoryTable::CreateSchema() { + return std::make_shared( + std::vector{ + SchemaField::MakeRequired(1, "made_current_at", int64()), + SchemaField::MakeRequired(2, "snapshot_id", int64()), + SchemaField::MakeOptional(3, "parent_id", int64()), + SchemaField::MakeRequired(4, "is_current_ancestor", boolean())}, + 1); +} + +TableIdentifier HistoryTable::CreateName(const TableIdentifier& source_name) { + return TableIdentifier{source_name.ns, source_name.name + ".history"}; +} + +Result> HistoryTable::Make(std::shared_ptr
table) { + return std::shared_ptr(new HistoryTable(table)); +} + +} // namespace iceberg diff --git a/src/iceberg/inspect/history_table.h b/src/iceberg/inspect/history_table.h new file mode 100644 index 000000000..e624359f3 --- /dev/null +++ b/src/iceberg/inspect/history_table.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/inspect/metadata_table.h" +#include "iceberg/result.h" +#include "iceberg/table.h" + +namespace iceberg { + +/// \brief History metadata table +/// +/// History is based on the table's snapshot log, which logs each update +/// to the table's current snapshot. Each row has columns: +/// - made_current_at (long, timestamp) +/// - snapshot_id (long) +/// - parent_id (long, optional) +/// - is_current_ancestor (bool) +class ICEBERG_EXPORT HistoryTable : public BaseMetadataTable { + public: + /// \brief Create a HistoryTable from table metadata + /// + /// \param[in] table The source table + /// \return A HistoryTable instance or error status + static Result> Make(std::shared_ptr
table); + + ~HistoryTable() override; + + private: + HistoryTable(std::shared_ptr
table); + + std::shared_ptr CreateSchema(); + + TableIdentifier CreateName(const TableIdentifier& source_name); +}; + +} // namespace iceberg diff --git a/src/iceberg/inspect/metadata_table.cc b/src/iceberg/inspect/metadata_table.cc new file mode 100644 index 000000000..9a56ce362 --- /dev/null +++ b/src/iceberg/inspect/metadata_table.cc @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#include "iceberg/inspect/metadata_table.h" + +#include +#include +#include + +#include "iceberg/file_io.h" +#include "iceberg/schema.h" +#include "iceberg/schema_field.h" +#include "iceberg/table_identifier.h" +#include "iceberg/table_metadata.h" +#include "iceberg/table_scan.h" +#include "iceberg/type.h" +#include "iceberg/util/uuid.h" + +namespace iceberg { + +BaseMetadataTable::BaseMetadataTable(std::shared_ptr
source_table, + TableIdentifier identifier, + std::shared_ptr schema) + : Table(identifier, source_table->metadata(), + std::string(source_table->metadata_file_location()), source_table->io(), + source_table->catalog()), + source_table_(std::move(source_table)), + schema_(schema) { + uuid_ = Uuid::GenerateV4().ToString(); + schemas_[schema->schema_id()] = schema; +} + +BaseMetadataTable::~BaseMetadataTable() = default; + +Status BaseMetadataTable::Refresh() { + return NotSupported("Cannot refresh a metadata table"); +} + +Result> BaseMetadataTable::NewScan() const { + return NotSupported("TODO: Scanning metadata tables is not yet supported"); +}; + +Result> BaseMetadataTable::NewTransaction() { + return NotSupported("Cannot create a transaction for a metadata table"); +} + +Result> BaseMetadataTable::NewUpdateProperties() { + return NotSupported("Cannot create an update properties for a metadata table"); +} + +Result> BaseMetadataTable::NewUpdateSchema() { + return NotSupported("Cannot create an update schema for a metadata table"); +} + +Result> BaseMetadataTable::NewUpdateLocation() { + return NotSupported("Cannot create an update location for a metadata table"); +} + +Result> BaseMetadataTable::NewUpdatePartitionSpec() { + return NotSupported("Cannot create an update partition spec for a metadata table"); +} + +Result> BaseMetadataTable::NewUpdateSortOrder() { + return NotSupported("Cannot create an update sort order for a metadata table"); +} + +Result> BaseMetadataTable::NewExpireSnapshots() { + return NotSupported("Cannot create an expire snapshots for a metadata table"); +} + +} // namespace iceberg diff --git a/src/iceberg/inspect/metadata_table.h b/src/iceberg/inspect/metadata_table.h new file mode 100644 index 000000000..7cb19e357 --- /dev/null +++ b/src/iceberg/inspect/metadata_table.h @@ -0,0 +1,180 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/location_provider.h" +#include "iceberg/result.h" +#include "iceberg/sort_order.h" +#include "iceberg/table.h" +#include "iceberg/table_metadata.h" +#include "iceberg/table_scan.h" + +namespace iceberg { + +/// Forward declarations +class FileIO; + +/// \brief Base class for Iceberg metadata tables +/// +/// Metadata tables expose table metadata as queryable tables with schemas and scan +/// support. They provide read-only access to metadata. +class ICEBERG_EXPORT BaseMetadataTable : public Table { + public: + /// \brief Returns the identifier of this table + const TableIdentifier& name() const { return identifier_; } + + /// \brief Returns the UUID of the table + const std::string& uuid() const { return uuid_; } + + /// \brief Returns the schema for this table, return NotFoundError if not found + Result> schema() const { return schema_; } + + /// \brief Returns a map of schema for this table + Result< + std::reference_wrapper>>> + schemas() const { + return schemas_; + } + + /// \brief Returns the partition spec for this table, return NotFoundError if not found + Result> spec() const { return partition_spec; }; + + /// \brief Returns a map of partition specs for this table + Result>>> + specs() const { + return partition_specs_; + } + + /// \brief Returns the sort order for this table, return NotFoundError if not found + Result> sort_order() const { return sort_order_; } + + /// \brief Returns a map of sort order IDs to sort orders for this table + Result>>> + sort_orders() const { + return sort_orders_; + } + + /// \brief Returns the properties of this table + const TableProperties& properties() const { return properties_; } + + /// \brief Returns the table's metadata file location + std::string_view metadata_file_location() const { + return source_table_->metadata_file_location(); + } + + /// \brief Returns the table's base location + std::string_view location() const { return source_table_->location(); } + + /// \brief Returns the time when this table was last updated + TimePointMs last_updated_ms() const { return source_table_->last_updated_ms(); } + + /// \brief Returns the table's current snapshot, return NotFoundError if not found + Result> current_snapshot() const { + return source_table_->current_snapshot(); + } + + /// \brief Get the snapshot of this table with the given id + /// + /// \param snapshot_id the ID of the snapshot to get + /// \return the Snapshot with the given id, return NotFoundError if not found + Result> SnapshotById(int64_t snapshot_id) const { + return source_table_->SnapshotById(snapshot_id); + } + + /// \brief Get the snapshots of this table + const std::vector>& snapshots() const { + return source_table_->snapshots(); + } + + /// \brief Get the snapshot history of this table + const std::vector& history() const { + return source_table_->history(); + } + + /// \brief Returns the current metadata for this table + const std::shared_ptr& metadata() const { + // TODO: or should we return an empty TableMetadata? + return source_table_->metadata(); + } + + /// \brief Returns the catalog that this table belongs to + const std::shared_ptr& catalog() const { return source_table_->catalog(); } + + /// \brief Returns a LocationProvider for this table + Result> location_provider() const { + return source_table_->location_provider(); + } + + /// \brief Refreshing is not supported in metadata tables. + Status Refresh() override; + + /// \brief Create a new table scan builder for this table + /// + /// Once a table scan builder is created, it can be refined to project columns and + /// filter data. + Result> NewScan() const; + + /// \brief Creating transactions is not supported in metadata tables. + Result> NewTransaction() override; + + /// \brief Updating partition specs is not supported in metadata tables. + Result> NewUpdatePartitionSpec() override; + + /// \brief Updating table properties is not supported in metadata tables. + Result> NewUpdateProperties() override; + + /// \brief Updating sort orders is not supported in metadata tables. + Result> NewUpdateSortOrder() override; + + /// \brief Updating schemas is not supported in metadata tables. + Result> NewUpdateSchema() override; + + /// \brief Expiring snapshots is not supported in metadata tables. + Result> NewExpireSnapshots() override; + + /// \brief Updating table location is not supported in metadata tables. + Result> NewUpdateLocation() override; + + protected: + BaseMetadataTable(std::shared_ptr
source_table, TableIdentifier identifier, + std::shared_ptr schema); + + virtual ~BaseMetadataTable(); + + std::shared_ptr
source_table_; + std::string uuid_; + std::shared_ptr schema_; + std::unordered_map> schemas_; + TableProperties properties_ = TableProperties(); + const std::shared_ptr sort_order_ = SortOrder::Unsorted(); + const std::unordered_map> sort_orders_ = { + {sort_order_->order_id(), sort_order_}}; + const std::shared_ptr partition_spec = PartitionSpec::Unpartitioned(); + const std::unordered_map> partition_specs_ = { + {partition_spec->spec_id(), partition_spec}}; +}; + +} // namespace iceberg diff --git a/src/iceberg/inspect/metadata_table_factory.cc b/src/iceberg/inspect/metadata_table_factory.cc new file mode 100644 index 000000000..b4a981672 --- /dev/null +++ b/src/iceberg/inspect/metadata_table_factory.cc @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#include "iceberg/inspect/metadata_table_factory.h" + +#include "iceberg/inspect/history_table.h" +#include "iceberg/inspect/snapshots_table.h" + +namespace iceberg { + +Result> MetadataTableFactory::GetSnapshotsTable( + std::shared_ptr
table) { + return SnapshotsTable::Make(table); +} + +Result> MetadataTableFactory::GetHistoryTable( + std::shared_ptr
table) { + return HistoryTable::Make(table); +} + +} // namespace iceberg diff --git a/src/iceberg/inspect/metadata_table_factory.h b/src/iceberg/inspect/metadata_table_factory.h new file mode 100644 index 000000000..3cf031884 --- /dev/null +++ b/src/iceberg/inspect/metadata_table_factory.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/result.h" +#include "iceberg/table.h" + +namespace iceberg { + +class HistoryTable; +class SnapshotsTable; +class Table; + +/// \brief Metadata table factory and inspector +/// +/// MetadataTable provides factory methods to create specific metadata tables for +/// inspecting table metadata. Each metadata table exposes a different aspect of the +/// table's metadata as a scannable Iceberg table. +/// +/// Usage: +/// auto snapshots = ICEBERG_TRY(MetadataTable::GetSnapshotsTable(table)); +/// auto scan = ICEBERG_TRY(snapshots->NewScan()); +/// // ... scan and read snapshot data +class ICEBERG_EXPORT MetadataTableFactory { + public: + /// \brief Create a SnapshotsTable from a table + /// + /// \param table The source table + /// \return A SnapshotsTable exposing all snapshots or error status + static Result> GetSnapshotsTable( + std::shared_ptr
table); + + /// \brief Create a HistoryTable from a table + /// + /// \param table The source table + /// \return A HistoryTable exposing snapshot history or error status + static Result> GetHistoryTable( + std::shared_ptr
table); +}; + +} // namespace iceberg diff --git a/src/iceberg/inspect/snapshots_table.cc b/src/iceberg/inspect/snapshots_table.cc new file mode 100644 index 000000000..4b0f6f790 --- /dev/null +++ b/src/iceberg/inspect/snapshots_table.cc @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#include "iceberg/inspect/snapshots_table.h" + +#include +#include + +#include "iceberg/inspect/metadata_table.h" +#include "iceberg/schema.h" +#include "iceberg/schema_field.h" +#include "iceberg/table_identifier.h" +#include "iceberg/type.h" + +namespace iceberg { + +SnapshotsTable::SnapshotsTable(std::shared_ptr
table) + : BaseMetadataTable(table, CreateName(table->name()), CreateSchema()) {} + +SnapshotsTable::~SnapshotsTable() = default; + +std::shared_ptr SnapshotsTable::CreateSchema() { + return std::make_shared( + std::vector{SchemaField::MakeRequired(1, "committed_at", int64()), + SchemaField::MakeOptional(2, "snapshot_id", int64()), + SchemaField::MakeRequired(3, "parent_id", int64()), + SchemaField::MakeRequired(4, "manifest_list", string()), + SchemaField::MakeRequired( + 5, "summary", + std::make_shared( + SchemaField::MakeRequired(6, "key", string()), + SchemaField::MakeRequired(7, "value", string())))}, + 1); +} + +TableIdentifier SnapshotsTable::CreateName(const TableIdentifier& source_name) { + return TableIdentifier{source_name.ns, source_name.name + ".snapshots"}; +} + +Result> SnapshotsTable::Make( + std::shared_ptr
table) { + return std::shared_ptr(new SnapshotsTable(table)); +} + +} // namespace iceberg diff --git a/src/iceberg/inspect/snapshots_table.h b/src/iceberg/inspect/snapshots_table.h new file mode 100644 index 000000000..fc6c46013 --- /dev/null +++ b/src/iceberg/inspect/snapshots_table.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "iceberg/iceberg_export.h" +#include "iceberg/inspect/metadata_table.h" +#include "iceberg/result.h" +#include "iceberg/table.h" + +namespace iceberg { + +/// \brief Snapshots metadata table +/// +/// Exposes all snapshots in the table as rows with columns: +/// - committed_at (timestamp) +/// - snapshot_id (long) +/// - parent_id (long) +/// - manifest_list (string) +/// - summary (map) +class ICEBERG_EXPORT SnapshotsTable : public BaseMetadataTable { + public: + /// \brief Create a SnapshotsTable from table metadata + /// + /// \param[in] table The source table + /// \return A SnapshotsTable instance or error status + static Result> Make(std::shared_ptr
table); + + ~SnapshotsTable() override; + + private: + SnapshotsTable(std::shared_ptr
table); + + std::shared_ptr CreateSchema(); + + TableIdentifier CreateName(const TableIdentifier& source_name); +}; + +} // namespace iceberg diff --git a/src/iceberg/test/CMakeLists.txt b/src/iceberg/test/CMakeLists.txt index fdd88888e..9c10f7193 100644 --- a/src/iceberg/test/CMakeLists.txt +++ b/src/iceberg/test/CMakeLists.txt @@ -189,6 +189,8 @@ if(ICEBERG_BUILD_BUNDLE) update_sort_order_test.cc update_statistics_test.cc) + add_iceberg_test(metadata_table_test SOURCES metadata_table_test.cc) + add_iceberg_test(data_writer_test USE_BUNDLE SOURCES data_writer_test.cc) endif() diff --git a/src/iceberg/test/metadata_table_test.cc b/src/iceberg/test/metadata_table_test.cc new file mode 100644 index 000000000..9260d76ec --- /dev/null +++ b/src/iceberg/test/metadata_table_test.cc @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include "iceberg/inspect/metadata_table.h" + +#include +#include + +#include "iceberg/inspect/metadata_table_factory.h" +#include "iceberg/inspect/snapshots_table.h" +#include "iceberg/schema.h" +#include "iceberg/schema_field.h" +#include "iceberg/table.h" +#include "iceberg/table_identifier.h" +#include "iceberg/table_metadata.h" +#include "iceberg/test/matchers.h" +#include "iceberg/test/mock_catalog.h" +#include "iceberg/test/mock_io.h" + +namespace iceberg { + +class MetadataTableTest : public ::testing::Test { + protected: + void SetUp() override { + io_ = std::make_shared(); + catalog_ = std::make_shared(); + + auto schema = std::make_shared( + std::vector{SchemaField::MakeRequired(1, "id", int64()), + SchemaField::MakeOptional(2, "name", string())}, + 1); + metadata_ = std::make_shared( + TableMetadata{.format_version = 2, .schemas = {schema}, .current_schema_id = 1}); + + TableIdentifier source_ident{.ns = Namespace{.levels = {"db"}}, + .name = "source_table"}; + auto source_table_result = + Table::Make(source_ident, metadata_, "s3://bucket/meta.json", io_, catalog_); + EXPECT_THAT(source_table_result, IsOk()); + source_table_ = *source_table_result; + + auto snapshots_table_result = MetadataTableFactory::GetSnapshotsTable(source_table_); + EXPECT_THAT(snapshots_table_result, IsOk()); + snapshots_table_ = *snapshots_table_result; + } + + std::shared_ptr io_; + std::shared_ptr catalog_; + std::shared_ptr metadata_; + std::shared_ptr
source_table_; + std::shared_ptr snapshots_table_; +}; + +TEST_F(MetadataTableTest, Constructor) { + EXPECT_EQ(snapshots_table_->name().name, "source_table.snapshots"); + EXPECT_FALSE(snapshots_table_->uuid().empty()); + auto schema_result = snapshots_table_->schema(); + EXPECT_THAT(schema_result, IsOk()); + EXPECT_EQ((*schema_result)->schema_id(), 1); +} + +TEST_F(MetadataTableTest, DelegatesToSourceTable) { + EXPECT_EQ(snapshots_table_->location(), source_table_->location()); + EXPECT_EQ(snapshots_table_->last_updated_ms(), source_table_->last_updated_ms()); + EXPECT_EQ(snapshots_table_->metadata(), source_table_->metadata()); + EXPECT_EQ(snapshots_table_->catalog(), source_table_->catalog()); +} + +TEST_F(MetadataTableTest, NotSupportedOperations) { + EXPECT_THAT(snapshots_table_->Refresh(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewTransaction(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewUpdateProperties(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewUpdateSchema(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewUpdateLocation(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewUpdatePartitionSpec(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewUpdateSortOrder(), HasErrorMessage("Cannot")); + EXPECT_THAT(snapshots_table_->NewExpireSnapshots(), HasErrorMessage("Cannot")); +} + +TEST_F(MetadataTableTest, SchemasAndSpecs) { + auto schemas_result = snapshots_table_->schemas(); + EXPECT_THAT(schemas_result, IsOk()); + EXPECT_EQ(schemas_result->get().size(), 1); + EXPECT_EQ(schemas_result->get().at(1)->schema_id(), 1); + + auto spec_result = snapshots_table_->spec(); + EXPECT_THAT(spec_result, IsOk()); + EXPECT_EQ(*spec_result, PartitionSpec::Unpartitioned()); + + auto specs_result = snapshots_table_->specs(); + EXPECT_THAT(specs_result, IsOk()); + EXPECT_EQ(specs_result->get().size(), 1); +} + +TEST_F(MetadataTableTest, SortOrders) { + auto sort_order_result = snapshots_table_->sort_order(); + EXPECT_THAT(sort_order_result, IsOk()); + EXPECT_EQ(*sort_order_result, SortOrder::Unsorted()); + + auto sort_orders_result = snapshots_table_->sort_orders(); + EXPECT_THAT(sort_orders_result, IsOk()); + EXPECT_EQ(sort_orders_result->get().size(), 1); +} + +TEST_F(MetadataTableTest, Properties) { + EXPECT_EQ(snapshots_table_->properties().configs().size(), 0); +} + +TEST_F(MetadataTableTest, Snapshots) { + // Assuming source table has no current snapshot + auto cur_snapshot_result = snapshots_table_->current_snapshot(); + EXPECT_THAT(cur_snapshot_result, IsError(ErrorKind::kNotFound)); + auto snapshot_result = snapshots_table_->SnapshotById(1); + EXPECT_THAT(snapshot_result, IsError(ErrorKind::kNotFound)); + EXPECT_TRUE(snapshots_table_->snapshots().empty()); +} + +TEST_F(MetadataTableTest, History) { EXPECT_TRUE(snapshots_table_->history().empty()); } + +TEST_F(MetadataTableTest, LocationProvider) { + auto lp_result = snapshots_table_->location_provider(); + EXPECT_THAT(lp_result, IsOk()); +} + +} // namespace iceberg