MXS-1220: Add JSON Pointer support for json_t objects
Using the JSON Pointer syntax specified in RFC 6901 (https://tools.ietf.org/html/rfc6901) allows for a convenient way to access values deep in a JSON object.
This commit is contained in:
@ -61,4 +61,13 @@ json_t* mxs_json_relationship(const char* host, const char* endpoint);
|
|||||||
*/
|
*/
|
||||||
void mxs_json_add_relation(json_t* rel, const char* id, const char* type);
|
void mxs_json_add_relation(json_t* rel, const char* id, const char* type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return value at provided JSON Pointer
|
||||||
|
*
|
||||||
|
* @param json JSON object
|
||||||
|
* @param json_ptr JSON Pointer to object
|
||||||
|
* @return Pointed value or NULL if no value is found
|
||||||
|
*/
|
||||||
|
json_t* mxs_json_pointer(json_t* json, const char* json_ptr);
|
||||||
|
|
||||||
MXS_END_DECLS
|
MXS_END_DECLS
|
||||||
|
|||||||
@ -61,3 +61,73 @@ void mxs_json_add_relation(json_t* rel, const char* id, const char* type)
|
|||||||
json_object_set_new(obj, CN_TYPE, json_string(type));
|
json_object_set_new(obj, CN_TYPE, json_string(type));
|
||||||
json_array_append(data, obj);
|
json_array_append(data, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string grab_next_component(string* s)
|
||||||
|
{
|
||||||
|
std::string& str = *s;
|
||||||
|
|
||||||
|
while (str.length() > 0 && str[0] == '/')
|
||||||
|
{
|
||||||
|
str.erase(str.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pos = str.find("/");
|
||||||
|
string rval;
|
||||||
|
|
||||||
|
if (pos != string::npos)
|
||||||
|
{
|
||||||
|
rval = str.substr(0, pos);
|
||||||
|
str.erase(0, pos);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = str;
|
||||||
|
str.erase(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_integer(const string& str)
|
||||||
|
{
|
||||||
|
char* end;
|
||||||
|
return strtol(str.c_str(), &end, 10) >= 0 && *end == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_t* mxs_json_pointer_internal(json_t* json, string str)
|
||||||
|
{
|
||||||
|
json_t* rval = NULL;
|
||||||
|
string comp = grab_next_component(&str);
|
||||||
|
|
||||||
|
if (comp.length() == 0)
|
||||||
|
{
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_is_array(json) && is_integer(comp))
|
||||||
|
{
|
||||||
|
size_t idx = strtol(comp.c_str(), NULL, 10);
|
||||||
|
|
||||||
|
if (idx < json_array_size(json))
|
||||||
|
{
|
||||||
|
rval = mxs_json_pointer_internal(json_array_get(json, idx), str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (json_is_object(json))
|
||||||
|
{
|
||||||
|
json_t* obj = json_object_get(json, comp.c_str());
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
rval = mxs_json_pointer_internal(obj, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t* mxs_json_pointer(json_t* json, const char* json_ptr)
|
||||||
|
{
|
||||||
|
return mxs_json_pointer_internal(json, json_ptr);
|
||||||
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ add_executable(testmaxscalepcre2 testmaxscalepcre2.cc)
|
|||||||
add_executable(testmodulecmd testmodulecmd.cc)
|
add_executable(testmodulecmd testmodulecmd.cc)
|
||||||
add_executable(testconfig testconfig.cc)
|
add_executable(testconfig testconfig.cc)
|
||||||
add_executable(trxboundaryparser_profile trxboundaryparser_profile.cc)
|
add_executable(trxboundaryparser_profile trxboundaryparser_profile.cc)
|
||||||
|
add_executable(testjson testjson.cc)
|
||||||
target_link_libraries(test_atomic maxscale-common)
|
target_link_libraries(test_atomic maxscale-common)
|
||||||
target_link_libraries(test_adminusers maxscale-common)
|
target_link_libraries(test_adminusers maxscale-common)
|
||||||
target_link_libraries(test_buffer maxscale-common)
|
target_link_libraries(test_buffer maxscale-common)
|
||||||
@ -48,6 +49,7 @@ target_link_libraries(testmaxscalepcre2 maxscale-common)
|
|||||||
target_link_libraries(testmodulecmd maxscale-common)
|
target_link_libraries(testmodulecmd maxscale-common)
|
||||||
target_link_libraries(testconfig maxscale-common)
|
target_link_libraries(testconfig maxscale-common)
|
||||||
target_link_libraries(trxboundaryparser_profile maxscale-common)
|
target_link_libraries(trxboundaryparser_profile maxscale-common)
|
||||||
|
target_link_libraries(testjson maxscale-common)
|
||||||
add_test(TestAtomic test_atomic)
|
add_test(TestAtomic test_atomic)
|
||||||
add_test(TestAdminUsers test_adminusers)
|
add_test(TestAdminUsers test_adminusers)
|
||||||
add_test(TestBuffer test_buffer)
|
add_test(TestBuffer test_buffer)
|
||||||
@ -79,6 +81,7 @@ add_test(TestTrxCompare_Select test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../..
|
|||||||
add_test(TestTrxCompare_Set test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/set.test)
|
add_test(TestTrxCompare_Set test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/set.test)
|
||||||
add_test(TestTrxCompare_Update test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/update.test)
|
add_test(TestTrxCompare_Update test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/update.test)
|
||||||
add_test(TestTrxCompare_MaxScale test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/maxscale.test)
|
add_test(TestTrxCompare_MaxScale test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/maxscale.test)
|
||||||
|
add_test(TestJson testjson)
|
||||||
|
|
||||||
# This test requires external dependencies and thus cannot be run
|
# This test requires external dependencies and thus cannot be run
|
||||||
# as a part of the core test set
|
# as a part of the core test set
|
||||||
|
|||||||
297
server/core/test/testjson.cc
Normal file
297
server/core/test/testjson.cc
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <maxscale/cppdefs.hh>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <maxscale/debug.h>
|
||||||
|
#include <maxscale/jansson.hh>
|
||||||
|
#include <maxscale/json_api.h>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
const char* test1_json =
|
||||||
|
"{"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/servers/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"server1\","
|
||||||
|
" \"type\": \"servers\","
|
||||||
|
" \"relationships\": {"
|
||||||
|
" \"services\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/services/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"SchemaRouter-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Hint-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"Read-Connection-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" },"
|
||||||
|
" \"monitors\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/monitors/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"MySQL-Monitor\","
|
||||||
|
" \"type\": \"monitors\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" \"attributes\": {"
|
||||||
|
" \"parameters\": {"
|
||||||
|
" \"address\": \"127.0.0.1\","
|
||||||
|
" \"port\": 3000,"
|
||||||
|
" \"protocol\": \"MySQLBackend\""
|
||||||
|
" },"
|
||||||
|
" \"status\": \"Master, Running\","
|
||||||
|
" \"version_string\": \"10.1.19-MariaDB-1~jessie\","
|
||||||
|
" \"node_id\": 3000,"
|
||||||
|
" \"master_id\": -1,"
|
||||||
|
" \"replication_depth\": 0,"
|
||||||
|
" \"slaves\": ["
|
||||||
|
" 3001,"
|
||||||
|
" 3002,"
|
||||||
|
" 3003"
|
||||||
|
" ],"
|
||||||
|
" \"statictics\": {"
|
||||||
|
" \"connections\": 0,"
|
||||||
|
" \"total_connections\": 0,"
|
||||||
|
" \"active_operations\": 0"
|
||||||
|
" }"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"server2\","
|
||||||
|
" \"type\": \"servers\","
|
||||||
|
" \"relationships\": {"
|
||||||
|
" \"services\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/services/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"SchemaRouter-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Hint-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" },"
|
||||||
|
" \"monitors\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/monitors/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"MySQL-Monitor\","
|
||||||
|
" \"type\": \"monitors\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" \"attributes\": {"
|
||||||
|
" \"parameters\": {"
|
||||||
|
" \"address\": \"127.0.0.1\","
|
||||||
|
" \"port\": 3001,"
|
||||||
|
" \"protocol\": \"MySQLBackend\""
|
||||||
|
" },"
|
||||||
|
" \"status\": \"Slave, Running\","
|
||||||
|
" \"version_string\": \"10.1.19-MariaDB-1~jessie\","
|
||||||
|
" \"node_id\": 3001,"
|
||||||
|
" \"master_id\": 3000,"
|
||||||
|
" \"replication_depth\": 1,"
|
||||||
|
" \"slaves\": [],"
|
||||||
|
" \"statictics\": {"
|
||||||
|
" \"connections\": 0,"
|
||||||
|
" \"total_connections\": 0,"
|
||||||
|
" \"active_operations\": 0"
|
||||||
|
" }"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"server3\","
|
||||||
|
" \"type\": \"servers\","
|
||||||
|
" \"relationships\": {"
|
||||||
|
" \"services\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/services/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"SchemaRouter-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Hint-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" },"
|
||||||
|
" \"monitors\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/monitors/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"MySQL-Monitor\","
|
||||||
|
" \"type\": \"monitors\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" \"attributes\": {"
|
||||||
|
" \"parameters\": {"
|
||||||
|
" \"address\": \"127.0.0.1\","
|
||||||
|
" \"port\": 3002,"
|
||||||
|
" \"protocol\": \"MySQLBackend\""
|
||||||
|
" },"
|
||||||
|
" \"status\": \"Slave, Running\","
|
||||||
|
" \"version_string\": \"10.1.19-MariaDB-1~jessie\","
|
||||||
|
" \"node_id\": 3002,"
|
||||||
|
" \"master_id\": 3000,"
|
||||||
|
" \"replication_depth\": 1,"
|
||||||
|
" \"slaves\": [],"
|
||||||
|
" \"statictics\": {"
|
||||||
|
" \"connections\": 0,"
|
||||||
|
" \"total_connections\": 0,"
|
||||||
|
" \"active_operations\": 0"
|
||||||
|
" }"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"server4\","
|
||||||
|
" \"type\": \"servers\","
|
||||||
|
" \"relationships\": {"
|
||||||
|
" \"services\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/services/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"SchemaRouter-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"id\": \"RW-Split-Hint-Router\","
|
||||||
|
" \"type\": \"services\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" },"
|
||||||
|
" \"monitors\": {"
|
||||||
|
" \"links\": {"
|
||||||
|
" \"self\": \"http://localhost:8989/v1/monitors/\""
|
||||||
|
" },"
|
||||||
|
" \"data\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": \"MySQL-Monitor\","
|
||||||
|
" \"type\": \"monitors\""
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" }"
|
||||||
|
" },"
|
||||||
|
" \"attributes\": {"
|
||||||
|
" \"parameters\": {"
|
||||||
|
" \"address\": \"127.0.0.1\","
|
||||||
|
" \"port\": 3003,"
|
||||||
|
" \"protocol\": \"MySQLBackend\""
|
||||||
|
" },"
|
||||||
|
" \"status\": \"Slave, Running\","
|
||||||
|
" \"version_string\": \"10.1.19-MariaDB-1~jessie\","
|
||||||
|
" \"node_id\": 3003,"
|
||||||
|
" \"master_id\": 3000,"
|
||||||
|
" \"replication_depth\": 1,"
|
||||||
|
" \"slaves\": [],"
|
||||||
|
" \"statictics\": {"
|
||||||
|
" \"connections\": 0,"
|
||||||
|
" \"total_connections\": 0,"
|
||||||
|
" \"active_operations\": 0"
|
||||||
|
" }"
|
||||||
|
" }"
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
int test1()
|
||||||
|
{
|
||||||
|
json_error_t err = {};
|
||||||
|
json_t* json = json_loads(test1_json, 0, &err);
|
||||||
|
|
||||||
|
ss_dassert(json);
|
||||||
|
|
||||||
|
ss_dassert(mxs_json_pointer(json, "") == json);
|
||||||
|
ss_dassert(mxs_json_pointer(json, "links") == json_object_get(json, "links"));
|
||||||
|
ss_dassert(json_is_string(mxs_json_pointer(json, "links/self")));
|
||||||
|
|
||||||
|
ss_dassert(mxs_json_pointer(json, "data") == json_object_get(json, "data"));
|
||||||
|
ss_dassert(json_is_array(mxs_json_pointer(json, "data")));
|
||||||
|
|
||||||
|
ss_dassert(json_is_object(mxs_json_pointer(json, "data/0")));
|
||||||
|
ss_dassert(json_is_string(mxs_json_pointer(json, "data/0/id")));
|
||||||
|
string s = json_string_value(mxs_json_pointer(json, "data/0/id"));
|
||||||
|
ss_dassert(s == "server1");
|
||||||
|
|
||||||
|
ss_dassert(json_is_object(mxs_json_pointer(json, "data/1")));
|
||||||
|
ss_dassert(json_is_string(mxs_json_pointer(json, "data/1/id")));
|
||||||
|
s = json_string_value(mxs_json_pointer(json, "data/1/id"));
|
||||||
|
ss_dassert(s == "server2");
|
||||||
|
|
||||||
|
ss_dassert(json_is_object(mxs_json_pointer(json, "data/0/attributes")));
|
||||||
|
ss_dassert(json_is_object(mxs_json_pointer(json, "data/0/attributes/parameters")));
|
||||||
|
ss_dassert(json_is_integer(mxs_json_pointer(json, "data/0/attributes/parameters/port")));
|
||||||
|
int i = json_integer_value(mxs_json_pointer(json, "data/0/attributes/parameters/port"));
|
||||||
|
ss_dassert(i == 3000);
|
||||||
|
|
||||||
|
ss_dassert(json_is_array(mxs_json_pointer(json, "data/0/attributes/slaves")));
|
||||||
|
ss_dassert(json_array_size(mxs_json_pointer(json, "data/0/attributes/slaves")) == 3);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
test1();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user