summaryrefslogtreecommitdiffstats
path: root/library/cpp/json/ordered_maps
diff options
context:
space:
mode:
authorilnurkh <[email protected]>2025-09-21 17:27:52 +0300
committerilnurkh <[email protected]>2025-09-21 17:45:29 +0300
commitb8d4d45acc8974872dc28167f0b07d886b7bfe15 (patch)
tree5c04866ad5faefd4f4b582f5e55435ebc457ccc0 /library/cpp/json/ordered_maps
parentca3f87b02dc3b458e8f33f532eaaca1b9afcbe54 (diff)
implement appending `[]` and reverse-lookup `[-1]` in json *ByValue methods
commit_hash:27ed69b5a37eb0d58449fb062147aaeb67ec51ba
Diffstat (limited to 'library/cpp/json/ordered_maps')
-rw-r--r--library/cpp/json/ordered_maps/json_value_ordered.cpp22
-rw-r--r--library/cpp/json/ordered_maps/json_value_ordered.h6
-rw-r--r--library/cpp/json/ordered_maps/ut/json_value_ordered_ut.cpp27
3 files changed, 53 insertions, 2 deletions
diff --git a/library/cpp/json/ordered_maps/json_value_ordered.cpp b/library/cpp/json/ordered_maps/json_value_ordered.cpp
index b25ca97b71a..b5e1a0dd7ff 100644
--- a/library/cpp/json/ordered_maps/json_value_ordered.cpp
+++ b/library/cpp/json/ordered_maps/json_value_ordered.cpp
@@ -900,7 +900,7 @@ namespace NJson::NOrderedJson {
template <class TPtr, class T>
TPtr* CreateOrNullptr(const TPtr* p, T key, std::false_type /*create*/) noexcept {
const TPtr* const next = &(*p)[key];
- return next->IsDefined() ? const_cast<TPtr*>(next) : nullptr;
+ return next->GetType() != JSON_UNDEFINED ? const_cast<TPtr*>(next) : nullptr;
}
template <bool Create, class TJsonPtr>
@@ -910,11 +910,29 @@ namespace NJson::NOrderedJson {
"TJsonPtr must be a `TJsonValue*` if `Create` is true");
constexpr std::integral_constant<bool, Create> create_tag{};
+
while (!path.empty()) {
- size_t index = 0;
+ i64 index = 0;
const TStringBuf step = path.NextTok(delimiter);
if (step.size() > 2 && *step.begin() == '[' && step.back() == ']' && TryFromString(step.substr(1, step.size() - 2), index)) {
+ if (index < 0) {
+ if constexpr (Create) {
+ currentJson->SetType(JSON_ARRAY);
+ TJsonArray::TArray& dst = currentJson->GetArraySafe();
+ while (i64(dst.size()) < -index) {
+ dst.push_front({JSON_NULL});
+ }
+ }
+ index = i64(currentJson->GetArray().size()) - (-index);
+ }
+ if (index < 0) {
+ return nullptr;
+ }
currentJson = CreateOrNullptr(currentJson, index, create_tag);
+ } else if (Create && step == "[]") {
+ if constexpr (Create) {
+ currentJson = &currentJson->AppendValue({});
+ }
} else {
currentJson = CreateOrNullptr(currentJson, step, create_tag);
}
diff --git a/library/cpp/json/ordered_maps/json_value_ordered.h b/library/cpp/json/ordered_maps/json_value_ordered.h
index bb7476a552b..305d600e402 100644
--- a/library/cpp/json/ordered_maps/json_value_ordered.h
+++ b/library/cpp/json/ordered_maps/json_value_ordered.h
@@ -94,6 +94,12 @@ namespace NJson::NOrderedJson {
TJsonValue& Back() Y_LIFETIME_BOUND;
const TJsonValue& Back() const Y_LIFETIME_BOUND;
+ // path lookup syntax
+ // 1. steps delimited by delimiter char
+ // 2. if step is use square brackets `[1]` - array lookup by index will be performed
+ // 2.1 negative `[-1]` indexes allow to lookup array-items from end
+ // 2.2 empty brackets `[]` in modification methods allow to create an item
+ // 3. otherwise - dict lookup by string-key will be performed
bool GetValueByPath(TStringBuf path, TJsonValue& result, char delimiter = '.') const;
bool SetValueByPath(TStringBuf path, const TJsonValue& value, char delimiter = '.');
bool SetValueByPath(TStringBuf path, TJsonValue&& value, char delimiter = '.');
diff --git a/library/cpp/json/ordered_maps/ut/json_value_ordered_ut.cpp b/library/cpp/json/ordered_maps/ut/json_value_ordered_ut.cpp
index 5fad165cf37..d9c798410bc 100644
--- a/library/cpp/json/ordered_maps/ut/json_value_ordered_ut.cpp
+++ b/library/cpp/json/ordered_maps/ut/json_value_ordered_ut.cpp
@@ -289,6 +289,33 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) {
UNIT_ASSERT(lhs.SetValueByPath("l/a/c/se", "h", '/'));
UNIT_ASSERT(lhs.GetValueByPath("l/a/c/se", result, '/'));
UNIT_ASSERT(result.GetStringRobust() == "h");
+
+ UNIT_ASSERT(lhs.SetValueByPath("l/b/[]", "new_array_elem1", '/'));
+ UNIT_ASSERT(lhs.SetValueByPath("l/b/[]", "new_array_elem2", '/'));
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[0]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem1");
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[1]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem2");
+
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-1]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem2");
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-2]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem1");
+ UNIT_ASSERT(!lhs.GetValueByPath("l/b/[-5]", result, '/'));
+
+ UNIT_ASSERT(lhs.SetValueByPath("l/b/[-5]", "new_array_elem_min5", '/'));
+
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-1]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem2");
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-2]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem1");
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-5]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "new_array_elem_min5");
+
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-4]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "null");
+ UNIT_ASSERT(lhs.GetValueByPath("l/b/[-3]", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "null");
}
}