diff options
| author | ilnurkh <[email protected]> | 2025-09-21 17:27:52 +0300 |
|---|---|---|
| committer | ilnurkh <[email protected]> | 2025-09-21 17:45:29 +0300 |
| commit | b8d4d45acc8974872dc28167f0b07d886b7bfe15 (patch) | |
| tree | 5c04866ad5faefd4f4b582f5e55435ebc457ccc0 /library/cpp/json/ordered_maps | |
| parent | ca3f87b02dc3b458e8f33f532eaaca1b9afcbe54 (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.cpp | 22 | ||||
| -rw-r--r-- | library/cpp/json/ordered_maps/json_value_ordered.h | 6 | ||||
| -rw-r--r-- | library/cpp/json/ordered_maps/ut/json_value_ordered_ut.cpp | 27 |
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 = ¤tJson->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"); } } |
