33 #include <unordered_set> 45 static std::size_t
skip_whitespaces (
const std::string &path, std::size_t token_begin);
47 std::size_t start = 0, std::size_t end = 0);
72 std::size_t
i = token_begin + 1;
73 bool unescaped_backslash =
false;
75 for (; i < path.length () && (path[
i] !=
'"' || unescaped_backslash); ++
i)
79 unescaped_backslash = !unescaped_backslash;
83 unescaped_backslash =
false;
87 if (i == path.length ())
106 std::size_t
i = token_begin;
108 if (validation_result)
111 path.insert (token_begin,
"\"");
112 path.insert (i + 1,
"\"");
116 return validation_result;
126 return ch ==
'_' || std::isalpha (ch);
138 return ch ==
'_' || std::isalnum (ch);
156 std::size_t
i = token_begin;
196 unsigned long &
index, std::size_t start, std::size_t end)
218 std::size_t last_non_space = end - 1;
219 for (; last_non_space > start && str[last_non_space] ==
' '; --last_non_space);
220 if (allow_wildcards && start == last_non_space && str[start] ==
'*')
230 for (
auto it = str.cbegin () + start; it < str.cbegin () + last_non_space + 1; ++it)
232 if (!std::isdigit (static_cast<unsigned char> (*it)))
240 index = std::strtoul (str.c_str () + start, &end_str, 10);
268 for (; pos < path.length () && path[pos] ==
' '; ++pos);
275 return std::isspace (ch) != 0;
282 auto first_non_space = std::find_if_not (path_string.begin (), path_string.end (),
db_json_isspace);
283 path_string.erase (path_string.begin (), first_non_space);
291 if (path_string.empty () || path_string[0] !=
'$')
312 if (sql_path.empty ())
319 if (sql_path[0] !=
'$')
328 while (i < sql_path.length ())
338 std::size_t end_bracket_offset;
341 end_bracket_offset = sql_path.find_first_of (
']', i);
342 if (end_bracket_offset == std::string::npos)
356 if (sql_path[i] ==
'*')
358 push_array_index_wildcard ();
364 push_array_index (index);
371 if (i == sql_path.length ())
386 push_object_key (sql_path.substr (old_idx, i - old_idx));
390 push_object_key_wildcard ();
402 push_object_key (sql_path.substr (old_idx, i - old_idx));
410 if (++i >= sql_path.length () || sql_path[
i] !=
'*')
415 push_double_wildcard ();
417 if (i == sql_path.length ())
435 std::vector<std::string> &split_path)
437 std::size_t start = 0;
438 std::size_t end = path.find_first_of (delim, start);
440 while (end != std::string::npos)
442 if (path[end] ==
'"')
444 std::size_t index_of_closing_quote = path.find_first_of (
'"', end + 1);
445 if (index_of_closing_quote == std::string::npos)
455 split_path.push_back (path.substr (end + 1, index_of_closing_quote - end - 1));
456 end = index_of_closing_quote;
461 else if (path[end] !=
'"' || ((end >= 1) && path[end - 1] !=
'\\'))
463 const std::string &substring = path.substr (start, end - start);
464 if (!substring.empty () || allow_empty)
466 split_path.push_back (substring);
471 end = path.find_first_of (delim, end + 1);
474 const std::string &substring = path.substr (start, end);
475 if (!substring.empty () || allow_empty)
477 split_path.push_back (substring);
480 std::size_t tokens_size = split_path.size ();
481 for (std::size_t
i = 0;
i < tokens_size;
i++)
500 const JSON_PATH &path,
const JSON_PATH::token_containter_type::const_iterator &it2)
521 MATCH_RESULT advance_pattern = match_pattern (pattern, it1 + 1, path, it2);
522 if (advance_pattern == FULL_MATCH)
525 return advance_pattern;
528 MATCH_RESULT advance_path = match_pattern (pattern, it1, path, it2 + 1);
529 if (advance_path == FULL_MATCH)
533 return (advance_pattern == PREFIX_MATCH || advance_path == PREFIX_MATCH) ? PREFIX_MATCH : NO_MATCH;
557 std::vector<std::string> tokens;
564 std::string res =
"$";
566 assert (!tokens.empty () && tokens[0] ==
"$");
567 for (std::size_t
i = 1;
i < tokens.size(); ++
i)
569 if (tokens[
i][0] ==
'"')
572 std::string unquoted = tokens[
i].substr (1, tokens[
i].length () - 2);
573 std::size_t start = 0;
577 res.append (unquoted);
591 sql_path = std::move (res);
605 auto first_non_zero = std::find_if_not (index.begin (), index.end (),
db_json_iszero);
606 index.erase (index.begin (), first_non_zero);
615 : m_type (array_index)
681 m_path_tokens.emplace_back (PATH_TOKEN::token_type::array_index, idx);
687 m_path_tokens.emplace_back (PATH_TOKEN::token_type::array_index_wildcard, std::string (
"*"));
693 m_path_tokens.emplace_back (PATH_TOKEN::token_type::object_key, std::move (
object_key));
699 m_path_tokens.emplace_back (PATH_TOKEN::token_type::object_key_wildcard, std::string (
"*"));
705 m_path_tokens.emplace_back (PATH_TOKEN::token_type::double_wildcard, std::string (
"**"));
711 m_path_tokens.pop_back ();
719 if (tkn.is_wildcard ())
730 std::string res =
"$";
732 for (
const auto &tkn : m_path_tokens)
738 res += std::to_string (tkn.get_array_index ());
746 res += tkn.get_object_key ();
796 case PATH_TOKEN::token_type::array_index:
797 case PATH_TOKEN::token_type::array_end_index:
798 if (!val->IsArray ())
803 case PATH_TOKEN::token_type::object_key:
804 if (!val->IsObject ())
809 case PATH_TOKEN::token_type::array_index_wildcard:
810 case PATH_TOKEN::token_type::object_key_wildcard:
811 case PATH_TOKEN::token_type::double_wildcard:
819 JSON_VALUE::Array arr = val->GetArray ();
820 if (tkn.m_type == PATH_TOKEN::token_type::array_end_index)
823 arr.PushBack (
JSON_VALUE ().SetNull (), allocator);
824 val = &val->GetArray ()[val->GetArray ().Size () - 1];
828 rapidjson::SizeType idx = (rapidjson::SizeType) tkn.get_array_index ();
829 while (idx >= arr.Size ())
831 arr.PushBack (
JSON_VALUE ().SetNull (), allocator);
833 val = &val->GetArray ()[idx];
836 else if (val->IsObject ())
839 JSON_VALUE::MemberIterator m = val->FindMember (encoded_key.c_str ());
840 if (m == val->MemberEnd ())
843 unsigned int len = (rapidjson::SizeType) encoded_key.length ();
844 val->AddMember (
JSON_VALUE (encoded_key.c_str (), len, allocator),
JSON_VALUE ().SetNull (), allocator);
846 val = & (--val->MemberEnd ())->value;
855 val->CopyFrom (jv, allocator);
878 if (tkn.m_type != PATH_TOKEN::token_type::array_index)
883 unsigned idx = tkn.get_array_index ();
884 if (idx >= val->GetArray ().Size ())
889 val = &val->GetArray ()[idx];
891 else if (val->IsObject ())
893 if (tkn.m_type != PATH_TOKEN::token_type::object_key)
898 JSON_VALUE::ConstMemberIterator m = val->FindMember (encoded_key.c_str ());
899 if (m == val->MemberEnd ())
915 std::unordered_set<const JSON_VALUE *> &vals_hash_set,
916 std::vector<const JSON_VALUE *> &vals)
923 if (vals_hash_set.find (&jv) == vals_hash_set.end ())
925 vals_hash_set.insert (&jv);
926 vals.push_back (&jv);
936 case PATH_TOKEN::token_type::array_index:
939 if (idx >= jv.GetArray ().Size ())
943 extract_from_subtree (path, tkn_array_offset + 1, jv.GetArray ()[idx], vals_hash_set, vals);
946 case PATH_TOKEN::token_type::array_index_wildcard:
947 for (rapidjson::SizeType
i = 0;
i < jv.GetArray ().Size (); ++
i)
949 extract_from_subtree (path, tkn_array_offset + 1, jv.GetArray ()[
i], vals_hash_set, vals);
952 case PATH_TOKEN::token_type::double_wildcard:
954 extract_from_subtree (path, tkn_array_offset + 1, jv, vals_hash_set, vals);
955 for (rapidjson::SizeType
i = 0;
i < jv.GetArray ().Size (); ++
i)
958 extract_from_subtree (path, tkn_array_offset, jv.GetArray ()[
i], vals_hash_set, vals);
965 else if (jv.IsObject ())
969 case PATH_TOKEN::token_type::object_key:
972 JSON_VALUE::ConstMemberIterator m = jv.FindMember (encoded_key.c_str ());
973 if (m == jv.MemberEnd ())
977 extract_from_subtree (path, tkn_array_offset + 1, m->value, vals_hash_set, vals);
980 case PATH_TOKEN::token_type::object_key_wildcard:
981 for (JSON_VALUE::ConstMemberIterator m = jv.MemberBegin (); m != jv.MemberEnd (); ++m)
983 extract_from_subtree (path, tkn_array_offset + 1, m->value, vals_hash_set, vals);
986 case PATH_TOKEN::token_type::double_wildcard:
988 extract_from_subtree (path, tkn_array_offset + 1, jv, vals_hash_set, vals);
989 for (JSON_VALUE::ConstMemberIterator m = jv.MemberBegin (); m != jv.MemberEnd (); ++m)
992 extract_from_subtree (path, tkn_array_offset, m->value, vals_hash_set, vals);
1002 std::vector<const JSON_VALUE *>
1005 std::unordered_set<const JSON_VALUE *> vals_hash_set;
1006 std::vector<const JSON_VALUE *> res;
1016 if (get_token_count () == 0)
1022 if (value ==
nullptr)
1027 const PATH_TOKEN &tkn = m_path_tokens.back ();
1029 if (value->IsArray ())
1031 if (!is_last_array_index_less_than (value->GetArray ().Size ()))
1038 else if (value->IsObject ())
1045 return value->EraseMember (encoded_key.c_str ());
1054 return get_token_count () > 0 ? &m_path_tokens[get_token_count () - 1] :
NULL;
1060 return m_path_tokens.size ();
1066 return get_token_count () == 0;
1072 if (get_token_count () == 0)
1091 const PATH_TOKEN *last_token = get_last_token ();
1100 return is_last_array_index_less_than (1);
1106 const PATH_TOKEN *last_token = get_last_token ();
1114 if (get_token_count () == 0)
1119 if (get_parent ().
get (jd) !=
NULL)
1137 std::string sql_path_string (path);
1143 int error_code = from_json_pointer (sql_path_string);
1151 int error_code = validate_and_create_from_json_path (sql_path_string);
1162 typedef rapidjson::GenericPointer<JSON_VALUE>::Token TOKEN;
1163 static const rapidjson::SizeType kPointerInvalidIndex = rapidjson::kPointerInvalidIndex;
1165 typedef rapidjson::GenericPointer<JSON_VALUE> JSON_POINTER;
1167 JSON_POINTER jp (pointer_path.c_str ());
1174 size_t tkn_cnt = jp.GetTokenCount ();
1175 const TOKEN *tokens = jp.GetTokens ();
1178 for (
size_t i = 0;
i < tkn_cnt; ++
i)
1180 const TOKEN &rapid_token = tokens[
i];
1182 if (rapid_token.index != kPointerInvalidIndex)
1185 push_array_index (rapid_token.index);
1187 else if (rapid_token.length == 1 && rapid_token.name[0] ==
'-' )
1190 m_path_tokens.emplace_back (PATH_TOKEN::token_type::array_end_index,
"-");
1196 size_t escaped_size;
1199 push_object_key (escaped);
JSON_VALUE & db_json_doc_to_value(JSON_DOC &doc)
token_containter_type m_path_tokens
const std::string & get_object_key() const
static bool match_pattern(const PATH_TOKEN &matcher, const PATH_TOKEN &matchee)
bool parent_exists(JSON_DOC &jd) const
bool points_to_array_cell() const
static bool db_json_path_is_valid_identifier_start_char(unsigned char ch)
int parse(const char *path)
static bool db_json_path_is_token_valid_quoted_object_key(const std::string &path, std::size_t &token_begin)
bool is_last_array_index_less_than(size_t size) const
bool contains_wildcard() const
bool is_root_path() const
const PATH_TOKEN * get_last_token() const
void push_array_index(unsigned long idx)
static bool db_json_iszero(const unsigned char &ch)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
rapidjson::MemoryPoolAllocator< JSON_PRIVATE_ALLOCATOR > JSON_PRIVATE_MEMPOOL
int prm_get_integer_value(PARAM_ID prm_id)
std::vector< const JSON_VALUE * > extract(const JSON_DOC &) const
void push_object_key(std::string &&object_key)
static int db_json_path_is_token_valid_array_index(const std::string &str, bool allow_wildcards, unsigned long &index, std::size_t start=0, std::size_t end=0)
JSON_PATH get_parent() const
void push_object_key_wildcard()
static bool db_json_path_quote_and_validate_unquoted_object_key(std::string &path, std::size_t &token_begin)
std::string dump_json_path() const
#define db_private_free(thrd, ptr)
#define ER_JSON_ARRAY_INDEX_TOO_LARGE
static void db_json_remove_leading_zeros_index(std::string &index)
int db_json_path_unquote_object_keys(std::string &sql_path)
static std::size_t skip_whitespaces(const std::string &path, std::size_t token_begin)
static void db_json_trim_leading_spaces(std::string &path_string)
static void extract_from_subtree(const JSON_PATH &path, size_t tkn_array_offset, const JSON_VALUE &jv, std::unordered_set< const JSON_VALUE * > &unique_elements, std::vector< const JSON_VALUE * > &vals)
#define ER_JSON_INVALID_PATH
unsigned long get_array_index() const
void set(JSON_DOC &jd, const JSON_VALUE &jv) const
int db_string_escape_str(const char *src_str, size_t src_size, char **res_string, size_t *dest_size)
bool is_last_token_array_index_zero() const
void push_double_wildcard()
JSON_VALUE * get(JSON_DOC &jd) const
std::string db_json_json_string_as_utf8(std::string raw_json_string)
static bool db_json_path_is_valid_identifier_char(unsigned char ch)
static bool db_json_path_is_token_valid_unquoted_object_key(const std::string &path, std::size_t &token_begin)
int db_json_split_path_by_delimiters(const std::string &path, const std::string &delim, bool allow_empty, std::vector< std::string > &split_path)
rapidjson::GenericValue< JSON_ENCODING, JSON_PRIVATE_MEMPOOL > JSON_VALUE
static MATCH_RESULT match_pattern(const JSON_PATH &pattern, const JSON_PATH &path)
int validate_and_create_from_json_path(std::string &sql_path)
size_t get_token_count() const
unsigned long m_array_idx
void push_array_index_wildcard()
bool erase(JSON_DOC &jd) const
static JSON_PATH_TYPE db_json_get_path_type(std::string &path_string)
int from_json_pointer(const std::string &pointer_path)
static bool db_json_isspace(const unsigned char &ch)