iceberg-cpp
Loading...
Searching...
No Matches
json_util_internal.h
Go to the documentation of this file.
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#pragma once
21
22#include <optional>
23
24#include <nlohmann/json.hpp>
25
26#include "iceberg/result.h"
27#include "iceberg/util/macros.h"
28
31
32namespace iceberg {
33
34template <typename T>
35void SetOptionalField(nlohmann::json& json, std::string_view key,
36 const std::optional<T>& value) {
37 if (value.has_value()) {
38 json[key] = *value;
39 }
40}
41
42template <typename T>
43 requires requires(const T& t) { t.empty(); }
44void SetContainerField(nlohmann::json& json, std::string_view key, const T& value) {
45 if (!value.empty()) {
46 json[key] = value;
47 }
48}
49
50inline void SetOptionalStringField(nlohmann::json& json, std::string_view key,
51 const std::string& value) {
52 if (!value.empty()) {
53 json[key] = value;
54 }
55}
56
57inline std::string SafeDumpJson(const nlohmann::json& json) {
58 return json.dump(/*indent=*/-1, /*indent_char=*/' ', /*ensure_ascii=*/false,
59 nlohmann::detail::error_handler_t::ignore);
60}
61
62template <typename T>
63Result<T> GetTypedJsonValue(const nlohmann::json& json) {
64 try {
65 return json.get<T>();
66 } catch (const std::exception& ex) {
67 return JsonParseError("Failed to parse {}: {}", SafeDumpJson(json), ex.what());
68 }
69}
70
71template <typename T>
72Result<T> GetJsonValueImpl(const nlohmann::json& json, std::string_view key) {
73 try {
74 return json.at(key).get<T>();
75 } catch (const std::exception& ex) {
76 return JsonParseError("Failed to parse '{}' from {}: {}", key, SafeDumpJson(json),
77 ex.what());
78 }
79}
80
81template <typename T>
82Result<std::optional<T>> GetJsonValueOptional(const nlohmann::json& json,
83 std::string_view key) {
84 if (!json.contains(key) || json.at(key).is_null()) {
85 return std::nullopt;
86 }
87 ICEBERG_ASSIGN_OR_RAISE(auto value, GetJsonValueImpl<T>(json, key));
88 return std::optional<T>(std::move(value));
89}
90
91template <typename T>
92Result<T> GetJsonValue(const nlohmann::json& json, std::string_view key) {
93 if (!json.contains(key) || json.at(key).is_null()) {
94 return JsonParseError("Missing '{}' in {}", key, SafeDumpJson(json));
95 }
96 return GetJsonValueImpl<T>(json, key);
97}
98
99template <typename T>
100Result<T> GetJsonValueOrDefault(const nlohmann::json& json, std::string_view key,
101 T default_value = T{}) {
102 if (!json.contains(key) || json.at(key).is_null()) {
103 return default_value;
104 }
105 return GetJsonValueImpl<T>(json, key);
106}
107
111template <typename T>
112nlohmann::json::array_t ToJsonList(const std::vector<T>& list) {
113 return std::accumulate(list.cbegin(), list.cend(), nlohmann::json::array(),
114 [](nlohmann::json::array_t arr, const T& item) {
115 arr.push_back(ToJson(item));
116 return arr;
117 });
118}
119
121template <typename T>
122nlohmann::json::array_t ToJsonList(const std::vector<std::shared_ptr<T>>& list) {
123 return std::accumulate(list.cbegin(), list.cend(), nlohmann::json::array(),
124 [](nlohmann::json::array_t arr, const std::shared_ptr<T>& item) {
125 arr.push_back(ToJson(*item));
126 return arr;
127 });
128}
129
136template <typename T>
137Result<std::vector<T>> FromJsonList(
138 const nlohmann::json& json, std::string_view key,
139 const std::function<Result<T>(const nlohmann::json&)>& from_json) {
140 std::vector<T> list{};
141 if (json.contains(key)) {
142 ICEBERG_ASSIGN_OR_RAISE(auto list_json, GetJsonValue<nlohmann::json>(json, key));
143 if (!list_json.is_array()) {
144 return JsonParseError("Cannot parse '{}' from non-array: {}", key,
145 SafeDumpJson(list_json));
146 }
147 for (const auto& entry_json : list_json) {
148 ICEBERG_ASSIGN_OR_RAISE(auto entry, from_json(entry_json));
149 list.emplace_back(std::move(entry));
150 }
151 }
152 return list;
153}
154
161template <typename T>
162Result<std::vector<std::shared_ptr<T>>> FromJsonList(
163 const nlohmann::json& json, std::string_view key,
164 const std::function<Result<std::shared_ptr<T>>(const nlohmann::json&)>& from_json) {
165 std::vector<std::shared_ptr<T>> list{};
166 if (json.contains(key)) {
167 ICEBERG_ASSIGN_OR_RAISE(auto list_json, GetJsonValue<nlohmann::json>(json, key));
168 if (!list_json.is_array()) {
169 return JsonParseError("Cannot parse '{}' from non-array: {}", key,
170 SafeDumpJson(list_json));
171 }
172 for (const auto& entry_json : list_json) {
173 ICEBERG_ASSIGN_OR_RAISE(auto entry, from_json(entry_json));
174 list.emplace_back(std::move(entry));
175 }
176 }
177 return list;
178}
179
183template <typename T>
184nlohmann::json::object_t ToJsonMap(const std::unordered_map<std::string, T>& map) {
185 return std::accumulate(map.cbegin(), map.cend(), nlohmann::json::object(),
186 [](nlohmann::json::object_t obj, const auto& item) {
187 obj[item.first] = ToJson(item.second);
188 return obj;
189 });
190}
191
194template <typename T>
195nlohmann::json::object_t ToJsonMap(
196 const std::unordered_map<std::string, std::shared_ptr<T>>& map) {
197 return std::accumulate(map.cbegin(), map.cend(), nlohmann::json::object(),
198 [](nlohmann::json::object_t obj, const auto& item) {
199 obj[item.first] = ToJson(*item.second);
200 return obj;
201 });
202}
203
210template <typename T = std::string>
211Result<std::unordered_map<std::string, T>> FromJsonMap(
212 const nlohmann::json& json, std::string_view key,
213 const std::function<Result<T>(const nlohmann::json&)>& from_json =
214 [](const nlohmann::json& json) -> Result<T> {
215 static_assert(std::is_same_v<T, std::string>, "T must be std::string");
216 try {
217 return json.get<std::string>();
218 } catch (const std::exception& ex) {
219 return JsonParseError("Cannot parse {} to a string value: {}", SafeDumpJson(json),
220 ex.what());
221 }
222 }) {
223 std::unordered_map<std::string, T> map{};
224 if (json.contains(key)) {
225 ICEBERG_ASSIGN_OR_RAISE(auto map_json, GetJsonValue<nlohmann::json>(json, key));
226 if (!map_json.is_object()) {
227 return JsonParseError("Cannot parse '{}' from non-object: {}", key,
228 SafeDumpJson(map_json));
229 }
230 for (const auto& [key, value] : map_json.items()) {
231 ICEBERG_ASSIGN_OR_RAISE(auto entry, from_json(value));
232 map[key] = std::move(entry);
233 }
234 }
235 return map;
236}
237
238} // namespace iceberg
std::shared_ptr< MapType > map(SchemaField key, SchemaField value)
Create a MapType with the given key and value fields.
Definition type.cc:388
std::shared_ptr< ListType > list(SchemaField element)
Create a ListType with the given element field.
Definition type.cc:392
Result< std::vector< T > > FromJsonList(const nlohmann::json &json, std::string_view key, const std::function< Result< T >(const nlohmann::json &)> &from_json)
Parse a list of items from a JSON object.
Definition json_util_internal.h:137
nlohmann::json::array_t ToJsonList(const std::vector< T > &list)
Convert a list of items to a json array.
Definition json_util_internal.h:112
nlohmann::json::object_t ToJsonMap(const std::unordered_map< std::string, T > &map)
Convert a map of type <std::string, T> to a json object.
Definition json_util_internal.h:184
Result< std::unordered_map< std::string, T > > FromJsonMap(const nlohmann::json &json, std::string_view key, const std::function< Result< T >(const nlohmann::json &)> &from_json=[](const nlohmann::json &json) -> Result< T > { static_assert(std::is_same_v< T, std::string >, "T must be std::string");try { return json.get< std::string >();} catch(const std::exception &ex) { return JsonParseError("Cannot parse {} to a string value: {}", SafeDumpJson(json), ex.what());} })
Parse a map of type <std::string, T> from a JSON object.
Definition json_util_internal.h:211