Add field getters to JsonObject class.

This commit is contained in:
levlam 2023-07-31 16:30:39 +03:00
parent 44d4fcfa07
commit a5a408290e
3 changed files with 344 additions and 11 deletions

View File

@ -585,6 +585,184 @@ Slice JsonValue::get_type_name(Type type) {
}
}
JsonValue JsonObject::extract_field(Slice name) {
for (auto &field_value : field_values_) {
if (field_value.first == name) {
return std::move(field_value.second);
}
}
return JsonValue();
}
Result<JsonValue> JsonObject::extract_optional_field(Slice name, JsonValueType type) {
for (auto &field_value : field_values_) {
if (field_value.first == name) {
if (type != JsonValue::Type::Null && field_value.second.type() != type) {
return Status::Error(400, PSLICE()
<< "Field \"" << name << "\" must be of type " << JsonValue::get_type_name(type));
}
return std::move(field_value.second);
}
}
return JsonValue();
}
Result<JsonValue> JsonObject::extract_required_field(Slice name, JsonValueType type) {
for (auto &field_value : field_values_) {
if (field_value.first == name) {
if (type != JsonValue::Type::Null && field_value.second.type() != type) {
return Status::Error(400, PSLICE()
<< "Field \"" << name << "\" must be of type " << JsonValue::get_type_name(type));
}
return std::move(field_value.second);
}
}
return Status::Error(400, PSLICE() << "Can't find field \"" << name << "\"");
}
const JsonValue *JsonObject::get_field(Slice name) const {
for (auto &field_value : field_values_) {
if (field_value.first == name) {
return &field_value.second;
}
}
return nullptr;
}
bool JsonObject::has_field(Slice name) const {
return get_field(name) != nullptr;
}
Result<bool> JsonObject::get_optional_bool_field(Slice name, bool default_value) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::Boolean) {
return value->get_boolean();
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type Boolean");
}
return default_value;
}
Result<bool> JsonObject::get_required_bool_field(Slice name) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::Boolean) {
return value->get_boolean();
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type Boolean");
}
return Status::Error(400, PSLICE() << "Can't find field \"" << name << '"');
}
Result<int32> JsonObject::get_optional_int_field(Slice name, int32 default_value) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::String) {
return to_integer_safe<int32>(value->get_string());
}
if (value->type() == JsonValue::Type::Number) {
return to_integer_safe<int32>(value->get_number());
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type Number");
}
return default_value;
}
Result<int32> JsonObject::get_required_int_field(Slice name) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::String) {
return to_integer_safe<int32>(value->get_string());
}
if (value->type() == JsonValue::Type::Number) {
return to_integer_safe<int32>(value->get_number());
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type Number");
}
return Status::Error(400, PSLICE() << "Can't find field \"" << name << '"');
}
Result<int64> JsonObject::get_optional_long_field(Slice name, int64 default_value) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::String) {
return to_integer_safe<int64>(value->get_string());
}
if (value->type() == JsonValue::Type::Number) {
return to_integer_safe<int64>(value->get_number());
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be a Number");
}
return default_value;
}
Result<int64> JsonObject::get_required_long_field(Slice name) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::String) {
return to_integer_safe<int64>(value->get_string());
}
if (value->type() == JsonValue::Type::Number) {
return to_integer_safe<int64>(value->get_number());
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be a Number");
}
return Status::Error(400, PSLICE() << "Can't find field \"" << name << '"');
}
Result<double> JsonObject::get_optional_double_field(Slice name, double default_value) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::Number) {
return to_double(value->get_number());
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type Number");
}
return default_value;
}
Result<double> JsonObject::get_required_double_field(Slice name) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::Number) {
return to_double(value->get_number());
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type Number");
}
return Status::Error(400, PSLICE() << "Can't find field \"" << name << '"');
}
Result<string> JsonObject::get_optional_string_field(Slice name, string default_value) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::String) {
return value->get_string().str();
}
if (value->type() == JsonValue::Type::Number) {
return value->get_number().str();
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type String");
}
return std::move(default_value);
}
Result<string> JsonObject::get_required_string_field(Slice name) const {
auto value = get_field(name);
if (value != nullptr) {
if (value->type() == JsonValue::Type::String) {
return value->get_string().str();
}
if (value->type() == JsonValue::Type::Number) {
return value->get_number().str();
}
return Status::Error(400, PSLICE() << "Field \"" << name << "\" must be of type String");
}
return Status::Error(400, PSLICE() << "Can't find field \"" << name << '"');
}
bool has_json_object_field(const JsonObject &object, Slice name) {
for (auto &field_value : object.field_values_) {
if (field_value.first == name) {

View File

@ -451,20 +451,52 @@ inline JsonArrayScope JsonBuilder::enter_array() {
class JsonValue;
enum class JsonValueType { Null, Number, Boolean, String, Array, Object };
using JsonArray = vector<JsonValue>;
class JsonObject {
const JsonValue *get_field(Slice name) const;
public:
vector<std::pair<MutableSlice, JsonValue>> field_values_;
size_t field_count() const {
return field_values_.size();
}
JsonValue extract_field(Slice name);
Result<JsonValue> extract_optional_field(Slice name, JsonValueType type);
Result<JsonValue> extract_required_field(Slice name, JsonValueType type);
bool has_field(Slice name) const;
Result<bool> get_optional_bool_field(Slice name, bool default_value = false) const;
Result<bool> get_required_bool_field(Slice name) const;
Result<int32> get_optional_int_field(Slice name, int32 default_value = 0) const;
Result<int32> get_required_int_field(Slice name) const;
Result<int64> get_optional_long_field(Slice name, int64 default_value = 0) const;
Result<int64> get_required_long_field(Slice name) const;
Result<double> get_optional_double_field(Slice name, double default_value = 0.0) const;
Result<double> get_required_double_field(Slice name) const;
Result<string> get_optional_string_field(Slice name, string default_value = string()) const;
Result<string> get_required_string_field(Slice name) const;
};
class JsonValue final : private Jsonable {
public:
enum class Type { Null, Number, Boolean, String, Array, Object };
using Type = JsonValueType;
static Slice get_type_name(Type type);

View File

@ -144,7 +144,7 @@ TEST(JSON, get_json_object_field) {
td::string encoded_object_copy = encoded_object;
auto value = td::json_decode(encoded_object_copy).move_as_ok();
auto &object = value.get_object();
const auto &object = value.get_object();
ASSERT_TRUE(td::has_json_object_field(object, "null"));
ASSERT_TRUE(td::has_json_object_field(object, "object"));
ASSERT_TRUE(!td::has_json_object_field(object, ""));
@ -154,7 +154,7 @@ TEST(JSON, get_json_object_field) {
ASSERT_TRUE(td::get_json_object_bool_field(object, "int").is_error());
ASSERT_EQ(td::get_json_object_bool_field(object, "bool").ok(), true);
ASSERT_EQ(td::get_json_object_bool_field(object, "bool").ok(), true);
ASSERT_EQ(td::get_json_object_bool_field(object, "bool", true).ok(), true);
ASSERT_EQ(td::get_json_object_bool_field(object, "bool", false).ok(), true);
ASSERT_EQ(td::get_json_object_bool_field(object, "bool3").ok(), false);
ASSERT_EQ(td::get_json_object_bool_field(object, "bool4", true, true).ok(), true);
ASSERT_TRUE(td::get_json_object_bool_field(object, "bool5", false, true).is_error());
@ -162,10 +162,10 @@ TEST(JSON, get_json_object_field) {
ASSERT_TRUE(td::get_json_object_int_field(object, "null").is_error());
ASSERT_EQ(td::get_json_object_int_field(object, "int").ok(), 1);
ASSERT_EQ(td::get_json_object_int_field(object, "int").ok(), 1);
ASSERT_EQ(td::get_json_object_int_field(object, "int", true).ok(), 1);
ASSERT_EQ(td::get_json_object_int_field(object, "int", false).ok(), 1);
ASSERT_EQ(td::get_json_object_int_field(object, "int2").ok(), 2);
ASSERT_EQ(td::get_json_object_int_field(object, "int2").ok(), 2);
ASSERT_EQ(td::get_json_object_int_field(object, "int2", true).ok(), 2);
ASSERT_EQ(td::get_json_object_int_field(object, "int2", false).ok(), 2);
ASSERT_EQ(td::get_json_object_int_field(object, "int3").ok(), 0);
ASSERT_EQ(td::get_json_object_int_field(object, "int4", true, 5).ok(), 5);
ASSERT_TRUE(td::get_json_object_int_field(object, "int5", false, 5).is_error());
@ -175,10 +175,10 @@ TEST(JSON, get_json_object_field) {
ASSERT_TRUE(td::get_json_object_long_field(object, "null").is_error());
ASSERT_EQ(td::get_json_object_long_field(object, "long").ok(), 123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long").ok(), 123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long", true).ok(), 123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long", false).ok(), 123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long2").ok(), 2123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long2").ok(), 2123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long2", true).ok(), 2123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long2", false).ok(), 2123456789012ll);
ASSERT_EQ(td::get_json_object_long_field(object, "long3").ok(), 0);
ASSERT_EQ(td::get_json_object_long_field(object, "long4", true, 5).ok(), 5);
ASSERT_TRUE(td::get_json_object_long_field(object, "long5", false, 5).is_error());
@ -192,10 +192,10 @@ TEST(JSON, get_json_object_field) {
ASSERT_TRUE(td::get_json_object_double_field(object, "null").is_error());
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "double").ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "double").ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "double", true).ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "double", false).ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "long2").ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "long2").ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "long2", true).ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "long2", false).ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "double3").ok(), 0.0));
ASSERT_TRUE(are_equal_double(td::get_json_object_double_field(object, "double4", true, -5.23).ok(), -5.23));
ASSERT_TRUE(td::get_json_object_double_field(object, "double5", false, 5).is_error());
@ -205,13 +205,136 @@ TEST(JSON, get_json_object_field) {
ASSERT_TRUE(td::get_json_object_string_field(object, "null").is_error());
ASSERT_EQ(td::get_json_object_string_field(object, "string").ok(), "string");
ASSERT_EQ(td::get_json_object_string_field(object, "string").ok(), "string");
ASSERT_EQ(td::get_json_object_string_field(object, "string", true).ok(), "string");
ASSERT_EQ(td::get_json_object_string_field(object, "string", false).ok(), "string");
ASSERT_EQ(td::get_json_object_string_field(object, "string2").ok(), "12345e+1");
ASSERT_EQ(td::get_json_object_string_field(object, "string2").ok(), "12345e+1");
ASSERT_EQ(td::get_json_object_string_field(object, "string2", true).ok(), "12345e+1");
ASSERT_EQ(td::get_json_object_string_field(object, "string2", false).ok(), "12345e+1");
ASSERT_EQ(td::get_json_object_string_field(object, "string3").ok(), td::string());
ASSERT_EQ(td::get_json_object_string_field(object, "string4", true, "abacaba").ok(), "abacaba");
ASSERT_TRUE(td::get_json_object_string_field(object, "string5", false, "test").is_error());
ASSERT_EQ(td::get_json_object_string_field(object, "int").ok(), "1");
ASSERT_EQ(td::get_json_object_string_field(object, "int2").ok(), "2");
}
TEST(JSON, json_object_get_field) {
const td::string encoded_object =
"{\"null\":null,\"bool\":true,\"int\":\"1\",\"int2\":2,\"long\":\"123456789012\",\"long2\":2123456789012,"
"\"double\":12345678901.1,\"string\":\"string\",\"string2\":12345e+1,\"array\":[],\"object\":{}}";
{
td::string encoded_object_copy = encoded_object;
auto value = td::json_decode(encoded_object_copy).move_as_ok();
auto &object = value.get_object();
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("null")), "null");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("bool")), "true");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("bool")), "null");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("int")), "\"1\"");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("int2")), "2");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("int3")), "null");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("long")), "\"123456789012\"");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("long2")), "2123456789012");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("double")), "12345678901.1");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("string")), "\"string\"");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("string2")), "12345e+1");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("array")), "[]");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("object")), "{}");
ASSERT_EQ(td::json_encode<td::string>(object.extract_field("")), "null");
}
{
td::string encoded_object_copy = encoded_object;
auto value = td::json_decode(encoded_object_copy).move_as_ok();
auto &object = value.get_object();
ASSERT_TRUE(object.extract_optional_field("int", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_optional_field("int", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_optional_field("int2", td::JsonValue::Type::Number).is_ok());
ASSERT_TRUE(object.extract_optional_field("int2", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_optional_field("int3", td::JsonValue::Type::Number).is_ok());
ASSERT_TRUE(object.extract_optional_field("int3", td::JsonValue::Type::Null).is_ok());
ASSERT_EQ(object.extract_optional_field("int", td::JsonValue::Type::String).ok().get_string(), "1");
ASSERT_TRUE(object.extract_optional_field("int", td::JsonValue::Type::Number).is_error());
ASSERT_EQ(object.extract_optional_field("int", td::JsonValue::Type::Null).ok().type(), td::JsonValue::Type::Null);
ASSERT_TRUE(object.extract_required_field("long", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_required_field("long", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_required_field("long2", td::JsonValue::Type::Number).is_ok());
ASSERT_TRUE(object.extract_required_field("long2", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_required_field("long3", td::JsonValue::Type::Number).is_error());
ASSERT_TRUE(object.extract_required_field("long3", td::JsonValue::Type::Null).is_error());
ASSERT_EQ(object.extract_required_field("long", td::JsonValue::Type::String).ok().get_string(), "123456789012");
ASSERT_TRUE(object.extract_required_field("long", td::JsonValue::Type::Number).is_error());
ASSERT_EQ(object.extract_required_field("long", td::JsonValue::Type::Null).ok().type(), td::JsonValue::Type::Null);
}
td::string encoded_object_copy = encoded_object;
auto value = td::json_decode(encoded_object_copy).move_as_ok();
const auto &object = value.get_object();
ASSERT_TRUE(object.has_field("null"));
ASSERT_TRUE(object.has_field("object"));
ASSERT_TRUE(!object.has_field(""));
ASSERT_TRUE(!object.has_field("objec"));
ASSERT_TRUE(!object.has_field("object2"));
ASSERT_TRUE(object.get_optional_bool_field("int").is_error());
ASSERT_EQ(object.get_optional_bool_field("bool").ok(), true);
ASSERT_EQ(object.get_optional_bool_field("bool", false).ok(), true);
ASSERT_EQ(object.get_required_bool_field("bool").ok(), true);
ASSERT_EQ(object.get_optional_bool_field("bool3").ok(), false);
ASSERT_EQ(object.get_optional_bool_field("bool4", true).ok(), true);
ASSERT_TRUE(object.get_required_bool_field("bool5").is_error());
ASSERT_TRUE(object.get_optional_int_field("null").is_error());
ASSERT_EQ(object.get_optional_int_field("int").ok(), 1);
ASSERT_EQ(object.get_optional_int_field("int").ok(), 1);
ASSERT_EQ(object.get_required_int_field("int").ok(), 1);
ASSERT_EQ(object.get_optional_int_field("int2").ok(), 2);
ASSERT_EQ(object.get_optional_int_field("int2").ok(), 2);
ASSERT_EQ(object.get_required_int_field("int2").ok(), 2);
ASSERT_EQ(object.get_optional_int_field("int3").ok(), 0);
ASSERT_EQ(object.get_optional_int_field("int4", 5).ok(), 5);
ASSERT_TRUE(object.get_required_int_field("int5").is_error());
ASSERT_EQ(object.get_optional_int_field("long").is_error(), true);
ASSERT_EQ(object.get_optional_int_field("long2").is_error(), true);
ASSERT_TRUE(object.get_optional_long_field("null").is_error());
ASSERT_EQ(object.get_optional_long_field("long").ok(), 123456789012ll);
ASSERT_EQ(object.get_optional_long_field("long").ok(), 123456789012ll);
ASSERT_EQ(object.get_required_long_field("long").ok(), 123456789012ll);
ASSERT_EQ(object.get_optional_long_field("long2").ok(), 2123456789012ll);
ASSERT_EQ(object.get_optional_long_field("long2").ok(), 2123456789012ll);
ASSERT_EQ(object.get_required_long_field("long2").ok(), 2123456789012ll);
ASSERT_EQ(object.get_optional_long_field("long3").ok(), 0);
ASSERT_EQ(object.get_optional_long_field("long4", 5).ok(), 5);
ASSERT_TRUE(object.get_required_long_field("long5").is_error());
ASSERT_EQ(object.get_optional_long_field("int").ok(), 1);
ASSERT_EQ(object.get_optional_long_field("int2").ok(), 2);
auto are_equal_double = [](double lhs, double rhs) {
return rhs - 1e-3 < lhs && lhs < rhs + 1e-3;
};
ASSERT_TRUE(object.get_optional_double_field("null").is_error());
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double").ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double").ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(object.get_required_double_field("double").ok(), 12345678901.1));
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("long2").ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("long2").ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(object.get_required_double_field("long2").ok(), 2123456789012.0));
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double3").ok(), 0.0));
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("double4", -5.23).ok(), -5.23));
ASSERT_TRUE(object.get_required_double_field("double5").is_error());
ASSERT_TRUE(object.get_optional_double_field("int").is_error());
ASSERT_TRUE(are_equal_double(object.get_optional_double_field("int2").ok(), 2));
ASSERT_TRUE(object.get_optional_string_field("null").is_error());
ASSERT_EQ(object.get_optional_string_field("string").ok(), "string");
ASSERT_EQ(object.get_optional_string_field("string").ok(), "string");
ASSERT_EQ(object.get_required_string_field("string").ok(), "string");
ASSERT_EQ(object.get_optional_string_field("string2").ok(), "12345e+1");
ASSERT_EQ(object.get_optional_string_field("string2").ok(), "12345e+1");
ASSERT_EQ(object.get_required_string_field("string2").ok(), "12345e+1");
ASSERT_EQ(object.get_optional_string_field("string3").ok(), td::string());
ASSERT_EQ(object.get_optional_string_field("string4", "abacaba").ok(), "abacaba");
ASSERT_TRUE(object.get_required_string_field("string5").is_error());
ASSERT_EQ(object.get_optional_string_field("int").ok(), "1");
ASSERT_EQ(object.get_optional_string_field("int2").ok(), "2");
}