Commit 9549ca47 authored by Dominik Charousset's avatar Dominik Charousset

Omit empty fields in JSON output by default

parent 07e53a43
......@@ -33,6 +33,12 @@ public:
null, /// The literal "null" (terminal type).
};
// -- constants --------------------------------------------------------------
/// The value returned for `skip_empty_fields()` for a default-constructed
/// JSON writer.
static constexpr bool skip_empty_fields_default = true;
// -- constructors, destructors, and assignment operators --------------------
json_writer();
......@@ -71,6 +77,17 @@ public:
return indentation_factor_ == 0;
}
/// Returns whether the writer omits empty fields entirely (true) or renders
/// empty fields as `$field: null` (false).
[[nodiscard]] bool skip_empty_fields() const noexcept {
return skip_empty_fields_;
}
/// Configures whether the writer omits empty fields.
void skip_empty_fields(bool value) noexcept {
skip_empty_fields_ = value;
}
// -- modifiers --------------------------------------------------------------
/// Removes all characters from the buffer and restores the writer to its
......@@ -225,6 +242,10 @@ private:
// Bookkeeping for where we are in the current object.
std::vector<entry> stack_;
// Configures whether we omit empty fields entirely (true) or render empty
// fields as `$field: null` (false).
bool skip_empty_fields_ = skip_empty_fields_default;
};
} // namespace caf
......@@ -113,7 +113,20 @@ bool json_writer::begin_field(string_view name) {
}
bool json_writer::begin_field(string_view name, bool is_present) {
if (begin_key_value_pair()) {
if (skip_empty_fields_ && !is_present) {
auto t = top();
switch (t) {
case type::object:
push(type::member);
return true;
default: {
std::string str = "expected object, found ";
str += json_type_name(t);
emplace_error(sec::runtime_error, class_name, __func__, std::move(str));
return false;
}
}
} else if (begin_key_value_pair()) {
CAF_ASSERT(top() == type::key);
detail::print_escaped(buf_, name);
add(": ");
......
......@@ -336,6 +336,17 @@ bool inspect(Inspector& f, rectangle& x) {
return !(x == y);
}
struct dummy_user {
std::string name;
caf::optional<std::string> nickname;
};
template <class Inspector>
bool inspect(Inspector& f, dummy_user& x) {
return f.object(x).fields(f.field("name", x.name),
f.field("nickname", x.nickname));
}
// -- type IDs for for all unit test suites ------------------------------------
#define ADD_TYPE_ID(type) CAF_ADD_TYPE_ID(core_test, type)
......@@ -350,6 +361,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_test, caf::first_custom_type_id)
ADD_TYPE_ID((dummy_enum_class))
ADD_TYPE_ID((dummy_struct))
ADD_TYPE_ID((dummy_tag_type))
ADD_TYPE_ID((dummy_user))
ADD_TYPE_ID((fail_on_copy))
ADD_TYPE_ID((float_actor))
ADD_TYPE_ID((foo_actor))
......
......@@ -16,9 +16,13 @@ namespace {
struct fixture {
template <class T>
expected<std::string> to_json_string(T&& x, size_t indentation_factor) {
expected<std::string>
to_json_string(T&& x, size_t indentation,
bool skip_empty_fields
= json_writer::skip_empty_fields_default) {
json_writer writer;
writer.indentation(indentation_factor);
writer.indentation(indentation);
writer.skip_empty_fields(skip_empty_fields);
if (writer.apply(std::forward<T>(x))) {
auto buf = writer.str();
return {std::string{buf.begin(), buf.end()}};
......@@ -171,4 +175,24 @@ SCENARIO("the JSON writer converts nested structs to strings") {
}
}
SCENARIO("the JSON writer omits or nulls missing values") {
GIVEN("a dummy_user object without nickname") {
dummy_user user;
user.name = "Bjarne";
WHEN("converting it to JSON with skip_empty_fields = true (default)") {
THEN("the JSON output omits the field 'nickname'") {
std::string out = R"({"@type": "dummy_user", "name": "Bjarne"})";
CHECK_EQ(to_json_string(user, 0), out);
}
}
WHEN("converting it to JSON with skip_empty_fields = false") {
THEN("the JSON output includes the field 'nickname' with a null value") {
std::string out
= R"({"@type": "dummy_user", "name": "Bjarne", "nickname": null})";
CHECK_EQ(to_json_string(user, 0, false), out);
}
}
}
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment