Skip to content

Commit c0fdd0d

Browse files
committed
feat(rest):implement load table
1 parent f43d24b commit c0fdd0d

File tree

2 files changed

+117
-71
lines changed

2 files changed

+117
-71
lines changed

src/iceberg/catalog/rest/rest_catalog.cc

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,20 @@ Status RestCatalog::RenameTable([[maybe_unused]] const TableIdentifier& from,
309309
return NotImplemented("Not implemented");
310310
}
311311

312-
Result<std::shared_ptr<Table>> RestCatalog::LoadTable(
313-
[[maybe_unused]] const TableIdentifier& identifier) {
314-
return NotImplemented("Not implemented");
312+
Result<std::shared_ptr<Table>> RestCatalog::LoadTable(const TableIdentifier& identifier) {
313+
ICEBERG_RETURN_UNEXPECTED(CheckEndpoint(supported_endpoints_, Endpoint::LoadTable()));
314+
ICEBERG_ASSIGN_OR_RAISE(auto path, paths_->Table(identifier));
315+
316+
ICEBERG_ASSIGN_OR_RAISE(
317+
const auto response,
318+
client_->Get(path, /*params=*/{}, /*headers=*/{}, *TableErrorHandler::Instance()));
319+
320+
// TODO(Feiyang Li): support load metadata table
321+
ICEBERG_ASSIGN_OR_RAISE(auto json, FromJsonString(response.body()));
322+
ICEBERG_ASSIGN_OR_RAISE(auto load_result, LoadTableResultFromJson(json));
323+
return Table::Make(identifier, load_result.metadata,
324+
std::move(load_result.metadata_location), file_io_,
325+
shared_from_this());
315326
}
316327

317328
Result<std::shared_ptr<Table>> RestCatalog::RegisterTable(

src/iceberg/test/rest_catalog_test.cc

Lines changed: 103 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,45 @@ class RestCatalogIntegrationTest : public ::testing::Test {
136136
return RestCatalog::Make(*config, std::make_shared<test::StdFileIO>());
137137
}
138138

139+
// Helper function to create and verify a catalog (asserts on failure)
140+
std::shared_ptr<RestCatalog> CreateAndVerifyCatalog() {
141+
auto catalog_result = CreateCatalog();
142+
EXPECT_THAT(catalog_result, IsOk());
143+
return catalog_result.value();
144+
}
145+
146+
// Helper function to create and verify a namespace
147+
void CreateAndVerifyNamespace(
148+
RestCatalog& catalog, const Namespace& ns,
149+
const std::unordered_map<std::string, std::string>& properties = {}) {
150+
auto status = catalog.CreateNamespace(ns, properties);
151+
EXPECT_THAT(status, IsOk());
152+
}
153+
154+
// Helper function to create a default schema for testing
155+
std::shared_ptr<Schema> CreateDefaultSchema() {
156+
return std::make_shared<Schema>(
157+
std::vector<SchemaField>{SchemaField::MakeRequired(1, "id", int32()),
158+
SchemaField::MakeOptional(2, "data", string())},
159+
/*schema_id=*/1);
160+
}
161+
162+
// Helper function to create a default unpartitioned partition spec
163+
std::shared_ptr<PartitionSpec> CreateDefaultPartitionSpec() {
164+
auto partition_spec_result =
165+
PartitionSpec::Make(PartitionSpec::kInitialSpecId, {}, 0);
166+
EXPECT_THAT(partition_spec_result, IsOk());
167+
return std::shared_ptr<PartitionSpec>(std::move(*partition_spec_result));
168+
}
169+
170+
// Helper function to create a default unsorted sort order
171+
std::shared_ptr<SortOrder> CreateDefaultSortOrder() {
172+
auto sort_order_result =
173+
SortOrder::Make(SortOrder::kUnsortedOrderId, std::vector<SortField>{});
174+
EXPECT_THAT(sort_order_result, IsOk());
175+
return std::shared_ptr<SortOrder>(std::move(*sort_order_result));
176+
}
177+
139178
static inline std::unique_ptr<DockerCompose> docker_compose_;
140179
};
141180

@@ -182,9 +221,7 @@ TEST_F(RestCatalogIntegrationTest, FetchServerConfigDirect) {
182221
}
183222

184223
TEST_F(RestCatalogIntegrationTest, ListNamespaces) {
185-
auto catalog_result = CreateCatalog();
186-
ASSERT_THAT(catalog_result, IsOk());
187-
auto& catalog = catalog_result.value();
224+
auto catalog = CreateAndVerifyCatalog();
188225

189226
Namespace root{.levels = {}};
190227
auto result = catalog->ListNamespaces(root);
@@ -193,14 +230,11 @@ TEST_F(RestCatalogIntegrationTest, ListNamespaces) {
193230
}
194231

195232
TEST_F(RestCatalogIntegrationTest, CreateNamespace) {
196-
auto catalog_result = CreateCatalog();
197-
ASSERT_THAT(catalog_result, IsOk());
198-
auto& catalog = catalog_result.value();
233+
auto catalog = CreateAndVerifyCatalog();
199234

200235
// Create a simple namespace
201236
Namespace ns{.levels = {"test_ns"}};
202-
auto status = catalog->CreateNamespace(ns, {});
203-
EXPECT_THAT(status, IsOk());
237+
CreateAndVerifyNamespace(*catalog, ns);
204238

205239
// Verify it was created by listing
206240
Namespace root{.levels = {}};
@@ -211,16 +245,13 @@ TEST_F(RestCatalogIntegrationTest, CreateNamespace) {
211245
}
212246

213247
TEST_F(RestCatalogIntegrationTest, CreateNamespaceWithProperties) {
214-
auto catalog_result = CreateCatalog();
215-
ASSERT_THAT(catalog_result, IsOk());
216-
auto& catalog = catalog_result.value();
248+
auto catalog = CreateAndVerifyCatalog();
217249

218250
// Create namespace with properties
219251
Namespace ns{.levels = {"test_ns_props"}};
220252
std::unordered_map<std::string, std::string> properties{
221253
{"owner", "test_user"}, {"description", "Test namespace with properties"}};
222-
auto status = catalog->CreateNamespace(ns, properties);
223-
EXPECT_THAT(status, IsOk());
254+
CreateAndVerifyNamespace(*catalog, ns, properties);
224255

225256
// Verify properties were set
226257
auto props_result = catalog->GetNamespaceProperties(ns);
@@ -230,19 +261,15 @@ TEST_F(RestCatalogIntegrationTest, CreateNamespaceWithProperties) {
230261
}
231262

232263
TEST_F(RestCatalogIntegrationTest, CreateNestedNamespace) {
233-
auto catalog_result = CreateCatalog();
234-
ASSERT_THAT(catalog_result, IsOk());
235-
auto& catalog = catalog_result.value();
264+
auto catalog = CreateAndVerifyCatalog();
236265

237266
// Create parent namespace
238267
Namespace parent{.levels = {"parent"}};
239-
auto status = catalog->CreateNamespace(parent, {});
240-
EXPECT_THAT(status, IsOk());
268+
CreateAndVerifyNamespace(*catalog, parent);
241269

242270
// Create nested namespace
243271
Namespace child{.levels = {"parent", "child"}};
244-
status = catalog->CreateNamespace(child, {});
245-
EXPECT_THAT(status, IsOk());
272+
CreateAndVerifyNamespace(*catalog, child);
246273

247274
// Verify nested namespace exists
248275
auto list_result = catalog->ListNamespaces(parent);
@@ -252,16 +279,13 @@ TEST_F(RestCatalogIntegrationTest, CreateNestedNamespace) {
252279
}
253280

254281
TEST_F(RestCatalogIntegrationTest, GetNamespaceProperties) {
255-
auto catalog_result = CreateCatalog();
256-
ASSERT_THAT(catalog_result, IsOk());
257-
auto& catalog = catalog_result.value();
282+
auto catalog = CreateAndVerifyCatalog();
258283

259284
// Create namespace with properties
260285
Namespace ns{.levels = {"test_get_props"}};
261286
std::unordered_map<std::string, std::string> properties{{"key1", "value1"},
262287
{"key2", "value2"}};
263-
auto status = catalog->CreateNamespace(ns, properties);
264-
EXPECT_THAT(status, IsOk());
288+
CreateAndVerifyNamespace(*catalog, ns, properties);
265289

266290
// Get properties
267291
auto props_result = catalog->GetNamespaceProperties(ns);
@@ -271,9 +295,7 @@ TEST_F(RestCatalogIntegrationTest, GetNamespaceProperties) {
271295
}
272296

273297
TEST_F(RestCatalogIntegrationTest, NamespaceExists) {
274-
auto catalog_result = CreateCatalog();
275-
ASSERT_THAT(catalog_result, IsOk());
276-
auto& catalog = catalog_result.value();
298+
auto catalog = CreateAndVerifyCatalog();
277299

278300
// Check non-existent namespace
279301
Namespace ns{.levels = {"non_existent"}};
@@ -282,8 +304,7 @@ TEST_F(RestCatalogIntegrationTest, NamespaceExists) {
282304
EXPECT_FALSE(*exists_result);
283305

284306
// Create namespace
285-
auto status = catalog->CreateNamespace(ns, {});
286-
EXPECT_THAT(status, IsOk());
307+
CreateAndVerifyNamespace(*catalog, ns);
287308

288309
// Check it now exists
289310
exists_result = catalog->NamespaceExists(ns);
@@ -292,22 +313,19 @@ TEST_F(RestCatalogIntegrationTest, NamespaceExists) {
292313
}
293314

294315
TEST_F(RestCatalogIntegrationTest, UpdateNamespaceProperties) {
295-
auto catalog_result = CreateCatalog();
296-
ASSERT_THAT(catalog_result, IsOk());
297-
auto& catalog = catalog_result.value();
316+
auto catalog = CreateAndVerifyCatalog();
298317

299318
// Create namespace with initial properties
300319
Namespace ns{.levels = {"test_update"}};
301320
std::unordered_map<std::string, std::string> initial_props{{"key1", "value1"},
302321
{"key2", "value2"}};
303-
auto status = catalog->CreateNamespace(ns, initial_props);
304-
EXPECT_THAT(status, IsOk());
322+
CreateAndVerifyNamespace(*catalog, ns, initial_props);
305323

306324
// Update properties: modify key1, add key3, remove key2
307325
std::unordered_map<std::string, std::string> updates{{"key1", "updated_value1"},
308326
{"key3", "value3"}};
309327
std::unordered_set<std::string> removals{"key2"};
310-
status = catalog->UpdateNamespaceProperties(ns, updates, removals);
328+
auto status = catalog->UpdateNamespaceProperties(ns, updates, removals);
311329
EXPECT_THAT(status, IsOk());
312330

313331
// Verify updated properties
@@ -319,22 +337,19 @@ TEST_F(RestCatalogIntegrationTest, UpdateNamespaceProperties) {
319337
}
320338

321339
TEST_F(RestCatalogIntegrationTest, DropNamespace) {
322-
auto catalog_result = CreateCatalog();
323-
ASSERT_THAT(catalog_result, IsOk());
324-
auto& catalog = catalog_result.value();
340+
auto catalog = CreateAndVerifyCatalog();
325341

326342
// Create namespace
327343
Namespace ns{.levels = {"test_drop"}};
328-
auto status = catalog->CreateNamespace(ns, {});
329-
EXPECT_THAT(status, IsOk());
344+
CreateAndVerifyNamespace(*catalog, ns);
330345

331346
// Verify it exists
332347
auto exists_result = catalog->NamespaceExists(ns);
333348
ASSERT_THAT(exists_result, IsOk());
334349
EXPECT_TRUE(*exists_result);
335350

336351
// Drop namespace
337-
status = catalog->DropNamespace(ns);
352+
auto status = catalog->DropNamespace(ns);
338353
EXPECT_THAT(status, IsOk());
339354

340355
// Verify it no longer exists
@@ -344,40 +359,21 @@ TEST_F(RestCatalogIntegrationTest, DropNamespace) {
344359
}
345360

346361
TEST_F(RestCatalogIntegrationTest, CreateTable) {
347-
auto catalog_result = CreateCatalog();
348-
ASSERT_THAT(catalog_result, IsOk());
349-
auto& catalog = catalog_result.value();
362+
auto catalog = CreateAndVerifyCatalog();
350363

351364
// Create nested namespace with properties
352365
Namespace ns{.levels = {"test_create_table", "apple", "ios"}};
353366
std::unordered_map<std::string, std::string> ns_properties{{"owner", "ray"},
354367
{"community", "apache"}};
355368

356369
// Create parent namespaces first
357-
auto status = catalog->CreateNamespace(Namespace{.levels = {"test_create_table"}}, {});
358-
EXPECT_THAT(status, IsOk());
359-
status =
360-
catalog->CreateNamespace(Namespace{.levels = {"test_create_table", "apple"}}, {});
361-
EXPECT_THAT(status, IsOk());
362-
status = catalog->CreateNamespace(ns, ns_properties);
363-
EXPECT_THAT(status, IsOk());
364-
365-
// Create schema
366-
auto schema = std::make_shared<Schema>(
367-
std::vector<SchemaField>{SchemaField::MakeOptional(1, "foo", string()),
368-
SchemaField::MakeRequired(2, "bar", int32()),
369-
SchemaField::MakeOptional(3, "baz", boolean())},
370-
/*schema_id=*/1);
370+
CreateAndVerifyNamespace(*catalog, Namespace{.levels = {"test_create_table"}});
371+
CreateAndVerifyNamespace(*catalog, Namespace{.levels = {"test_create_table", "apple"}});
372+
CreateAndVerifyNamespace(*catalog, ns, ns_properties);
371373

372-
// Create partition spec and sort order (unpartitioned and unsorted)
373-
auto partition_spec_result = PartitionSpec::Make(PartitionSpec::kInitialSpecId, {}, 0);
374-
ASSERT_THAT(partition_spec_result, IsOk());
375-
auto partition_spec = std::shared_ptr<PartitionSpec>(std::move(*partition_spec_result));
376-
377-
auto sort_order_result =
378-
SortOrder::Make(SortOrder::kUnsortedOrderId, std::vector<SortField>{});
379-
ASSERT_THAT(sort_order_result, IsOk());
380-
auto sort_order = std::shared_ptr<SortOrder>(std::move(*sort_order_result));
374+
auto schema = CreateDefaultSchema();
375+
auto partition_spec = CreateDefaultPartitionSpec();
376+
auto sort_order = CreateDefaultSortOrder();
381377

382378
// Create table
383379
TableIdentifier table_id{.ns = ns, .name = "t1"};
@@ -400,4 +396,43 @@ TEST_F(RestCatalogIntegrationTest, CreateTable) {
400396
HasErrorMessage("Table already exists: test_create_table.apple.ios.t1"));
401397
}
402398

399+
TEST_F(RestCatalogIntegrationTest, LoadTable) {
400+
auto catalog = CreateAndVerifyCatalog();
401+
402+
// Create namespace and table first
403+
Namespace ns{.levels = {"test_load_table"}};
404+
CreateAndVerifyNamespace(*catalog, ns);
405+
406+
// Create schema, partition spec, and sort order using helper functions
407+
auto schema = CreateDefaultSchema();
408+
auto partition_spec = CreateDefaultPartitionSpec();
409+
auto sort_order = CreateDefaultSortOrder();
410+
411+
// Create table
412+
TableIdentifier table_id{.ns = ns, .name = "test_table"};
413+
std::unordered_map<std::string, std::string> table_properties{{"key1", "value1"}};
414+
auto create_result = catalog->CreateTable(table_id, schema, partition_spec, sort_order,
415+
"", table_properties);
416+
ASSERT_THAT(create_result, IsOk());
417+
418+
// Load the table
419+
auto load_result = catalog->LoadTable(table_id);
420+
ASSERT_THAT(load_result, IsOk());
421+
auto& loaded_table = load_result.value();
422+
423+
// Verify loaded table properties
424+
EXPECT_EQ(loaded_table->name().ns.levels, std::vector<std::string>{"test_load_table"});
425+
EXPECT_EQ(loaded_table->name().name, "test_table");
426+
EXPECT_NE(loaded_table->metadata(), nullptr);
427+
428+
// Verify schema
429+
auto loaded_schema_result = loaded_table->schema();
430+
ASSERT_THAT(loaded_schema_result, IsOk());
431+
auto loaded_schema = loaded_schema_result.value();
432+
EXPECT_TRUE(loaded_schema->schema_id().has_value()); // Server assigns schema_id
433+
EXPECT_EQ(loaded_schema->fields().size(), 2);
434+
EXPECT_EQ(loaded_schema->fields()[0].name(), "id");
435+
EXPECT_EQ(loaded_schema->fields()[1].name(), "data");
436+
}
437+
403438
} // namespace iceberg::rest

0 commit comments

Comments
 (0)