$filter Query parameter support for nested keys added
Implemented the code to identify the '/' character in the
key and perform the level by level search
Testing :
Tested query parameter with path separated by / example
curl -k -u root:0penBmc https://<IP>/redfish/v1/Systems/
Baseboard/LogServices/FaultLog/Entries?$filter=CPER/Oem/
OEM/IpSignature eq 'DRAM-CHANNELS'
Results having 'DRAM-CHANNELS' in nested path "CPER/Oem/
OEM/IpSignature" are listed.
Change-Id: Ie6cf796026a29ec7a3e8a0366bbfd0c658d0ac7e
Signed-off-by: Chandramohan Harkude <chandramohan.harkude@gmail.com>
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp
index 966593d..c93174c 100644
--- a/redfish-core/include/utils/json_utils.hpp
+++ b/redfish-core/include/utils/json_utils.hpp
@@ -685,6 +685,41 @@
return {std::move(*object)};
}
+inline const nlohmann::json* findNestedKey(std::string_view key,
+ const nlohmann::json& value)
+{
+ size_t keysplitIndex = key.find('/');
+ std::string_view leftover;
+ nlohmann::json::const_iterator it;
+ if (keysplitIndex != std::string_view::npos)
+ {
+ const nlohmann::json::object_t* obj =
+ value.get_ptr<const nlohmann::json::object_t*>();
+ if (obj == nullptr || obj->empty())
+ {
+ BMCWEB_LOG_ERROR("Requested key wasn't an object");
+ return nullptr;
+ }
+
+ leftover = key.substr(keysplitIndex + 1);
+ std::string_view keypart = key.substr(0, keysplitIndex);
+ it = value.find(keypart);
+ if (it == value.end())
+ {
+ // Entry didn't have key
+ return nullptr;
+ }
+ return findNestedKey(leftover, it.value());
+ }
+
+ it = value.find(key);
+ if (it == value.end())
+ {
+ return nullptr;
+ }
+ return &*it;
+}
+
template <typename... UnpackTypes>
bool readJsonPatch(const crow::Request& req, crow::Response& res,
std::string_view key, UnpackTypes&&... in)
diff --git a/redfish-core/src/filter_expr_executor.cpp b/redfish-core/src/filter_expr_executor.cpp
index df22ec2..4d92ea1 100644
--- a/redfish-core/src/filter_expr_executor.cpp
+++ b/redfish-core/src/filter_expr_executor.cpp
@@ -5,6 +5,7 @@
#include "filter_expr_parser_ast.hpp"
#include "human_sort.hpp"
#include "logging.hpp"
+#include "utils/json_utils.hpp"
#include "utils/time_utils.hpp"
#include <nlohmann/json.hpp>
@@ -129,26 +130,29 @@
ValueVisitor::result_type
ValueVisitor::operator()(const filter_ast::UnquotedString& x)
{
- // Future, handle paths with / in them
- nlohmann::json::const_iterator entry = body.find(x);
- if (entry == body.end())
+ // find key including paths with / in them
+ const nlohmann::json* it =
+ json_util::findNestedKey(static_cast<std::string_view>(x), body);
+ if (it == nullptr)
{
BMCWEB_LOG_ERROR("Key {} doesn't exist in output, cannot filter",
static_cast<std::string>(x));
BMCWEB_LOG_DEBUG("Output {}", body.dump());
return {};
}
- const double* dValue = entry->get_ptr<const double*>();
+
+ const nlohmann::json& entry = *it;
+ const double* dValue = entry.get_ptr<const double*>();
if (dValue != nullptr)
{
return {*dValue};
}
- const int64_t* iValue = entry->get_ptr<const int64_t*>();
+ const int64_t* iValue = entry.get_ptr<const int64_t*>();
if (iValue != nullptr)
{
return {*iValue};
}
- const std::string* strValue = entry->get_ptr<const std::string*>();
+ const std::string* strValue = entry.get_ptr<const std::string*>();
if (strValue != nullptr)
{
if (DateTimeString::isDateTimeKey(x))
@@ -160,7 +164,7 @@
BMCWEB_LOG_ERROR(
"Type for key {} was {} which does not have a comparison operator",
- static_cast<std::string>(x), static_cast<int>(entry->type()));
+ static_cast<std::string>(x), static_cast<int>(entry.type()));
return {};
}
diff --git a/test/redfish-core/include/filter_expr_executor_test.cpp b/test/redfish-core/include/filter_expr_executor_test.cpp
index cc38a1c..bebe668 100644
--- a/test/redfish-core/include/filter_expr_executor_test.cpp
+++ b/test/redfish-core/include/filter_expr_executor_test.cpp
@@ -251,4 +251,21 @@
filterFalse("'2021-11-30T22:41:35.124+00:00' le Created", members);
}
+TEST(FilterParser, NestedProperty)
+{
+ const nlohmann::json members = R"({"Members": [{"Oem": {
+ "OEM": {
+ "@odata.type": "#OEMLogEntry.v1_1_0.OEMLogEntry",
+ "Key": "Switch_1",
+ "ErrorId": "SWITCH_EC_STRAP_MISMATCH"
+ }
+ }}]})"_json;
+ // Forward true conditions
+ filterTrue("Oem/OEM/ErrorId eq 'SWITCH_EC_STRAP_MISMATCH'", members);
+ filterTrue("Oem/OEM/Key eq 'Switch_1'", members);
+ filterFalse("Oem/OEM/ErrorId eq 'EC_STRAP_MISMATCH'", members);
+ filterFalse("Oem/OEM/ErrorId eq 'CX7_EC_STRAP_MISMATCH'", members);
+ filterFalse("Oem/OEM/ErrorId ne 'SWITCH_EC_STRAP_MISMATCH'", members);
+}
+
} // namespace redfish