Skip to content

Commit b624071

Browse files
committed
feat: Implement JSON serialization for REST Catalog API types
1 parent 4ebf729 commit b624071

File tree

7 files changed

+1066
-25
lines changed

7 files changed

+1066
-25
lines changed

src/iceberg/catalog/rest/CMakeLists.txt

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,35 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
set(ICEBERG_REST_SOURCES rest_catalog.cc)
18+
set(ICEBERG_REST_SOURCES rest_catalog.cc json_internal.cc)
1919

2020
set(ICEBERG_REST_STATIC_BUILD_INTERFACE_LIBS)
2121
set(ICEBERG_REST_SHARED_BUILD_INTERFACE_LIBS)
2222
set(ICEBERG_REST_STATIC_INSTALL_INTERFACE_LIBS)
2323
set(ICEBERG_REST_SHARED_INSTALL_INTERFACE_LIBS)
2424

25-
list(APPEND ICEBERG_REST_STATIC_BUILD_INTERFACE_LIBS
26-
"$<IF:$<TARGET_EXISTS:iceberg_static>,iceberg_static,iceberg_shared>" cpr::cpr)
27-
list(APPEND ICEBERG_REST_SHARED_BUILD_INTERFACE_LIBS
28-
"$<IF:$<TARGET_EXISTS:iceberg_shared>,iceberg_shared,iceberg_static>" cpr::cpr)
25+
list(APPEND
26+
ICEBERG_REST_STATIC_BUILD_INTERFACE_LIBS
27+
"$<IF:$<TARGET_EXISTS:iceberg_static>,iceberg_static,iceberg_shared>"
28+
cpr::cpr
29+
nlohmann_json::nlohmann_json)
30+
list(APPEND
31+
ICEBERG_REST_SHARED_BUILD_INTERFACE_LIBS
32+
"$<IF:$<TARGET_EXISTS:iceberg_shared>,iceberg_shared,iceberg_static>"
33+
cpr::cpr
34+
nlohmann_json::nlohmann_json)
2935
list(APPEND
3036
ICEBERG_REST_STATIC_INSTALL_INTERFACE_LIBS
3137
"$<IF:$<TARGET_EXISTS:Iceberg::iceberg_static>,Iceberg::iceberg_static,Iceberg::iceberg_shared>"
32-
"$<IF:$<BOOL:${CPR_VENDORED}>,Iceberg::cpr,cpr::cpr>")
38+
"$<IF:$<BOOL:${CPR_VENDORED}>,Iceberg::cpr,cpr::cpr>"
39+
"$<IF:$<BOOL:${NLOHMANN_JSON_VENDORED}>,Iceberg::nlohmann_json,nlohmann_json::nlohmann_json>"
40+
)
3341
list(APPEND
3442
ICEBERG_REST_SHARED_INSTALL_INTERFACE_LIBS
3543
"$<IF:$<TARGET_EXISTS:Iceberg::iceberg_shared>,Iceberg::iceberg_shared,Iceberg::iceberg_static>"
36-
"$<IF:$<BOOL:${CPR_VENDORED}>,Iceberg::cpr,cpr::cpr>")
37-
44+
"$<IF:$<BOOL:${CPR_VENDORED}>,Iceberg::cpr,cpr::cpr>"
45+
"$<IF:$<BOOL:${NLOHMANN_JSON_VENDORED}>,Iceberg::nlohmann_json,nlohmann_json::nlohmann_json>"
46+
)
3847
add_iceberg_lib(iceberg_rest
3948
SOURCES
4049
${ICEBERG_REST_SOURCES}
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/catalog/rest/json_internal.h"
21+
22+
#include <string>
23+
#include <unordered_map>
24+
#include <vector>
25+
26+
#include <nlohmann/json.hpp>
27+
28+
#include "iceberg/json_internal.h"
29+
#include "iceberg/result.h"
30+
#include "iceberg/table_identifier.h"
31+
#include "iceberg/table_metadata.h"
32+
#include "iceberg/util/json_util_internal.h"
33+
#include "iceberg/util/macros.h"
34+
35+
namespace iceberg::rest {
36+
37+
namespace {
38+
39+
// REST API JSON field constants
40+
constexpr std::string_view kNamespaces = "namespaces";
41+
constexpr std::string_view kRemovals = "removals";
42+
constexpr std::string_view kUpdates = "updates";
43+
constexpr std::string_view kUpdated = "updated";
44+
constexpr std::string_view kRemoved = "removed";
45+
constexpr std::string_view kMissing = "missing";
46+
constexpr std::string_view kIdentifiers = "identifiers";
47+
constexpr std::string_view kSource = "source";
48+
constexpr std::string_view kDestination = "destination";
49+
constexpr std::string_view kMetadataLocation = "metadata-location";
50+
constexpr std::string_view kMetadata = "metadata";
51+
constexpr std::string_view kConfig = "config";
52+
constexpr std::string_view kName = "name";
53+
constexpr std::string_view kLocation = "location";
54+
constexpr std::string_view kSchema = "schema";
55+
constexpr std::string_view kPartitionSpec = "partition-spec";
56+
constexpr std::string_view kWriteOrder = "write-order";
57+
constexpr std::string_view kStageCreate = "stage-create";
58+
constexpr std::string_view kProperties = "properties";
59+
constexpr std::string_view kOverwrite = "overwrite";
60+
constexpr std::string_view kNamespace = "namespace";
61+
62+
/// Helper function to convert TableIdentifier to JSON
63+
nlohmann::json TableIdentifierToJson(const TableIdentifier& identifier) {
64+
nlohmann::json json;
65+
json[kNamespace] = identifier.ns.levels;
66+
json[kName] = identifier.name;
67+
return json;
68+
}
69+
70+
/// Helper function to parse TableIdentifier from JSON
71+
Result<TableIdentifier> TableIdentifierFromJson(const nlohmann::json& json) {
72+
TableIdentifier identifier;
73+
74+
ICEBERG_ASSIGN_OR_RAISE(identifier.ns.levels,
75+
GetJsonValue<std::vector<std::string>>(json, kNamespace));
76+
ICEBERG_ASSIGN_OR_RAISE(identifier.name, GetJsonValue<std::string>(json, kName));
77+
78+
return identifier;
79+
}
80+
81+
} // namespace
82+
83+
nlohmann::json ToJson(const ListNamespaceResponse& response) {
84+
nlohmann::json json;
85+
json[kNamespaces] = response.namespaces;
86+
return json;
87+
}
88+
89+
Result<ListNamespaceResponse> ListNamespaceResponseFromJson(const nlohmann::json& json) {
90+
ListNamespaceResponse response;
91+
92+
ICEBERG_ASSIGN_OR_RAISE(
93+
response.namespaces,
94+
GetJsonValue<std::vector<std::vector<std::string>>>(json, kNamespaces));
95+
return response;
96+
}
97+
98+
nlohmann::json ToJson(const CreateNamespaceRequest& request) {
99+
nlohmann::json json;
100+
json[kNamespaces] = request.namespaces;
101+
SetOptionalField(json, kProperties, request.properties);
102+
return json;
103+
}
104+
105+
Result<CreateNamespaceRequest> CreateNamespaceRequestFromJson(
106+
const nlohmann::json& json) {
107+
CreateNamespaceRequest request;
108+
109+
ICEBERG_ASSIGN_OR_RAISE(request.namespaces,
110+
GetJsonValue<std::vector<std::string>>(json, kNamespaces));
111+
using MapType = std::unordered_map<std::string, std::string>;
112+
ICEBERG_ASSIGN_OR_RAISE(request.properties,
113+
GetJsonValueOptional<MapType>(json, kProperties));
114+
115+
return request;
116+
}
117+
118+
nlohmann::json ToJson(const CreateNamespaceResponse& response) {
119+
nlohmann::json json;
120+
json[kNamespaces] = response.namespaces;
121+
SetOptionalField(json, kProperties, response.properties);
122+
return json;
123+
}
124+
125+
Result<CreateNamespaceResponse> CreateNamespaceResponseFromJson(
126+
const nlohmann::json& json) {
127+
CreateNamespaceResponse response;
128+
129+
ICEBERG_ASSIGN_OR_RAISE(response.namespaces,
130+
GetJsonValue<std::vector<std::string>>(json, kNamespaces));
131+
using MapType = std::unordered_map<std::string, std::string>;
132+
ICEBERG_ASSIGN_OR_RAISE(response.properties,
133+
GetJsonValueOptional<MapType>(json, kProperties));
134+
135+
return response;
136+
}
137+
138+
nlohmann::json ToJson(const GetNamespacePropertiesResponse& response) {
139+
nlohmann::json json;
140+
json[kNamespaces] = response.namespaces;
141+
json[kProperties] = response.properties;
142+
return json;
143+
}
144+
145+
Result<GetNamespacePropertiesResponse> GetNamespacePropertiesResponseFromJson(
146+
const nlohmann::json& json) {
147+
GetNamespacePropertiesResponse response;
148+
149+
ICEBERG_ASSIGN_OR_RAISE(response.namespaces,
150+
GetJsonValue<std::vector<std::string>>(json, kNamespaces));
151+
using MapType = std::unordered_map<std::string, std::string>;
152+
ICEBERG_ASSIGN_OR_RAISE(response.properties, GetJsonValue<MapType>(json, kProperties));
153+
154+
return response;
155+
}
156+
157+
nlohmann::json ToJson(const UpdateNamespacePropsRequest& request) {
158+
nlohmann::json json;
159+
SetOptionalField(json, kRemovals, request.removals);
160+
SetOptionalField(json, kUpdates, request.updates);
161+
return json;
162+
}
163+
164+
Result<UpdateNamespacePropsRequest> UpdateNamespacePropsRequestFromJson(
165+
const nlohmann::json& json) {
166+
UpdateNamespacePropsRequest request;
167+
168+
ICEBERG_ASSIGN_OR_RAISE(
169+
request.removals, GetJsonValueOptional<std::vector<std::string>>(json, kRemovals));
170+
using MapType = std::unordered_map<std::string, std::string>;
171+
ICEBERG_ASSIGN_OR_RAISE(request.updates, GetJsonValueOptional<MapType>(json, kUpdates));
172+
173+
return request;
174+
}
175+
176+
nlohmann::json ToJson(const UpdateNamespacePropsResponse& response) {
177+
nlohmann::json json;
178+
json[kUpdated] = response.updated;
179+
json[kRemoved] = response.removed;
180+
SetOptionalField(json, kMissing, response.missing);
181+
return json;
182+
}
183+
184+
Result<UpdateNamespacePropsResponse> UpdateNamespacePropsResponseFromJson(
185+
const nlohmann::json& json) {
186+
UpdateNamespacePropsResponse response;
187+
188+
ICEBERG_ASSIGN_OR_RAISE(response.updated,
189+
GetJsonValue<std::vector<std::string>>(json, kUpdated));
190+
ICEBERG_ASSIGN_OR_RAISE(response.removed,
191+
GetJsonValue<std::vector<std::string>>(json, kRemoved));
192+
ICEBERG_ASSIGN_OR_RAISE(response.missing,
193+
GetJsonValueOptional<std::vector<std::string>>(json, kMissing));
194+
195+
return response;
196+
}
197+
198+
nlohmann::json ToJson(const ListTableResponse& response) {
199+
nlohmann::json json;
200+
201+
nlohmann::json identifiers_json = nlohmann::json::array();
202+
for (const auto& identifier : response.identifiers) {
203+
identifiers_json.push_back(TableIdentifierToJson(identifier));
204+
}
205+
json[kIdentifiers] = identifiers_json;
206+
return json;
207+
}
208+
209+
Result<ListTableResponse> ListTableResponseFromJson(const nlohmann::json& json) {
210+
ListTableResponse response;
211+
212+
for (const auto& id_json : json[kIdentifiers]) {
213+
ICEBERG_ASSIGN_OR_RAISE(auto identifier, TableIdentifierFromJson(id_json));
214+
response.identifiers.push_back(std::move(identifier));
215+
}
216+
return response;
217+
}
218+
219+
nlohmann::json ToJson(const CreateTableRequest& request) {
220+
nlohmann::json json;
221+
json[kName] = request.name;
222+
SetOptionalField(json, kLocation, request.location);
223+
json[kSchema] = ToJson(*request.schema);
224+
225+
if (request.partition_spec) {
226+
json[kPartitionSpec] = ToJson(*request.partition_spec);
227+
}
228+
229+
if (request.write_order) {
230+
json[kWriteOrder] = ToJson(*request.write_order);
231+
}
232+
233+
SetOptionalField(json, kStageCreate, request.stage_create);
234+
SetOptionalField(json, kProperties, request.properties);
235+
return json;
236+
}
237+
238+
Result<CreateTableRequest> CreateTableRequestFromJson(const nlohmann::json& json) {
239+
CreateTableRequest request;
240+
241+
ICEBERG_ASSIGN_OR_RAISE(request.name, GetJsonValue<std::string>(json, kName));
242+
243+
ICEBERG_ASSIGN_OR_RAISE(request.location,
244+
GetJsonValueOptional<std::string>(json, kLocation));
245+
246+
ICEBERG_ASSIGN_OR_RAISE(auto schema_json, GetJsonValue<nlohmann::json>(json, kSchema));
247+
ICEBERG_ASSIGN_OR_RAISE(auto schema_ptr, iceberg::SchemaFromJson(schema_json));
248+
request.schema = std::move(schema_ptr);
249+
250+
if (json.contains(kPartitionSpec)) {
251+
ICEBERG_ASSIGN_OR_RAISE(auto partition_spec_json,
252+
GetJsonValue<nlohmann::json>(json, kPartitionSpec));
253+
ICEBERG_ASSIGN_OR_RAISE(
254+
request.partition_spec,
255+
iceberg::PartitionSpecFromJson(request.schema, partition_spec_json));
256+
} else {
257+
request.partition_spec = nullptr;
258+
}
259+
260+
if (json.contains(kWriteOrder)) {
261+
ICEBERG_ASSIGN_OR_RAISE(auto write_order_json,
262+
GetJsonValue<nlohmann::json>(json, kWriteOrder));
263+
ICEBERG_ASSIGN_OR_RAISE(request.write_order,
264+
iceberg::SortOrderFromJson(write_order_json));
265+
} else {
266+
request.write_order = nullptr;
267+
}
268+
269+
ICEBERG_ASSIGN_OR_RAISE(request.stage_create,
270+
GetJsonValueOptional<bool>(json, kStageCreate));
271+
272+
using MapType = std::unordered_map<std::string, std::string>;
273+
ICEBERG_ASSIGN_OR_RAISE(request.properties,
274+
GetJsonValueOptional<MapType>(json, kProperties));
275+
276+
return request;
277+
}
278+
279+
nlohmann::json ToJson(const RegisterTableRequest& request) {
280+
nlohmann::json json;
281+
json[kName] = request.name;
282+
json[kMetadataLocation] = request.metadata_location;
283+
SetOptionalField(json, kOverwrite, request.overwrite);
284+
return json;
285+
}
286+
287+
Result<RegisterTableRequest> RegisterTableRequestFromJson(const nlohmann::json& json) {
288+
RegisterTableRequest request;
289+
290+
ICEBERG_ASSIGN_OR_RAISE(request.name, GetJsonValue<std::string>(json, kName));
291+
ICEBERG_ASSIGN_OR_RAISE(request.metadata_location,
292+
GetJsonValue<std::string>(json, kMetadataLocation));
293+
ICEBERG_ASSIGN_OR_RAISE(request.overwrite,
294+
GetJsonValueOptional<bool>(json, kOverwrite));
295+
296+
return request;
297+
}
298+
299+
nlohmann::json ToJson(const RenameTableRequest& request) {
300+
nlohmann::json json;
301+
json[kSource] = TableIdentifierToJson(request.source);
302+
json[kDestination] = TableIdentifierToJson(request.destination);
303+
return json;
304+
}
305+
306+
Result<RenameTableRequest> RenameTableRequestFromJson(const nlohmann::json& json) {
307+
RenameTableRequest request;
308+
309+
ICEBERG_ASSIGN_OR_RAISE(auto source_json, GetJsonValue<nlohmann::json>(json, kSource));
310+
ICEBERG_ASSIGN_OR_RAISE(request.source, TableIdentifierFromJson(source_json));
311+
312+
ICEBERG_ASSIGN_OR_RAISE(auto dest_json,
313+
GetJsonValue<nlohmann::json>(json, kDestination));
314+
ICEBERG_ASSIGN_OR_RAISE(request.destination, TableIdentifierFromJson(dest_json));
315+
316+
return request;
317+
}
318+
319+
nlohmann::json ToJson(const LoadTableResponse& response) {
320+
nlohmann::json json;
321+
322+
SetOptionalField(json, kMetadataLocation, response.metadata_location);
323+
json[kMetadata] = iceberg::ToJson(response.metadata);
324+
SetOptionalField(json, kConfig, response.config);
325+
326+
return json;
327+
}
328+
329+
Result<LoadTableResponse> LoadTableResponseFromJson(const nlohmann::json& json) {
330+
LoadTableResponse response;
331+
332+
ICEBERG_ASSIGN_OR_RAISE(response.metadata_location,
333+
GetJsonValueOptional<std::string>(json, kMetadataLocation));
334+
335+
ICEBERG_ASSIGN_OR_RAISE(auto metadata_json,
336+
GetJsonValue<nlohmann::json>(json, kMetadata));
337+
ICEBERG_ASSIGN_OR_RAISE(auto metadata_ptr,
338+
iceberg::TableMetadataFromJson(metadata_json));
339+
response.metadata = std::move(*metadata_ptr);
340+
341+
using MapType = std::unordered_map<std::string, std::string>;
342+
ICEBERG_ASSIGN_OR_RAISE(response.config, GetJsonValueOptional<MapType>(json, kConfig));
343+
344+
return response;
345+
}
346+
347+
} // namespace iceberg::rest

0 commit comments

Comments
 (0)