NeoGraph 0.10.0
A C++17 Graph Agent Engine Library — LangGraph for C++
Loading...
Searching...
No Matches
json_path.h
Go to the documentation of this file.
1
14#pragma once
15
16#include <neograph/json.h>
17#include <optional>
18#include <string>
19#include <vector>
20
21namespace neograph::llm {
22
23using json = neograph::json;
24
25namespace json_path {
26
28inline std::vector<std::string> split_path(const std::string& path) {
29 std::vector<std::string> segments;
30 if (path.empty()) return segments;
31
32 std::string::size_type start = 0;
33 while (start < path.size()) {
34 auto dot = path.find('.', start);
35 if (dot == std::string::npos) {
36 segments.push_back(path.substr(start));
37 break;
38 }
39 segments.push_back(path.substr(start, dot - start));
40 start = dot + 1;
41 }
42 return segments;
43}
44
46inline bool is_index(const std::string& s) {
47 if (s.empty()) return false;
48 for (char c : s) {
49 if (c < '0' || c > '9') return false;
50 }
51 return true;
52}
53
55inline std::optional<json> at_path(const json& root, const std::string& path) {
56 if (path.empty()) return root;
57
58 auto segments = split_path(path);
59 json current = root;
60
61 for (const auto& seg : segments) {
62 if (current.is_object()) {
63 if (!current.contains(seg)) return std::nullopt;
64 current = current[seg];
65 } else if (current.is_array() && is_index(seg)) {
66 size_t idx = std::stoul(seg);
67 if (idx >= current.size()) return std::nullopt;
68 current = current[idx];
69 } else {
70 return std::nullopt;
71 }
72 }
73 return current;
74}
75
77inline bool has_path(const json& root, const std::string& path) {
78 return at_path(root, path).has_value();
79}
80
82template<typename T>
83inline T get_path(const json& root, const std::string& path, const T& default_val) {
84 auto node = at_path(root, path);
85 if (!node) return default_val;
86 try {
87 return node->template get<T>();
88 } catch (...) {
89 return default_val;
90 }
91}
92
93namespace detail {
94// Recursive walker that uses operator[] at each level. Each operator[]
95// returns a write-through handle; the recursion hands that handle down
96// by value (move), preserving parent info so mutations propagate upward.
97inline void set_path_walk(json parent, const std::vector<std::string>& segs,
98 size_t i, const json& value) {
99 if (i + 1 == segs.size()) {
100 parent[segs[i]] = value;
101 return;
102 }
103 set_path_walk(parent[segs[i]], segs, i + 1, value);
104}
105} // namespace detail
106
108inline void set_path(json& root, const std::string& path, const json& value) {
109 if (path.empty()) {
110 root = value;
111 return;
112 }
113 auto segments = split_path(path);
114 if (segments.size() == 1) {
115 root[segments[0]] = value;
116 return;
117 }
118 detail::set_path_walk(root[segments[0]], segments, 1, value);
119}
120
121} // namespace json_path
122} // namespace neograph::llm
Thin C++ RAII wrapper around yyjson with nlohmann-compatible API.
bool has_path(const json &root, const std::string &path)
True if path exists in root.
Definition json_path.h:77
std::vector< std::string > split_path(const std::string &path)
Split "a.b.0.c" into ["a","b","0","c"].
Definition json_path.h:28
void set_path(json &root, const std::string &path, const json &value)
Set value at path, creating intermediate objects as needed.
Definition json_path.h:108
bool is_index(const std::string &s)
True if every char is a digit.
Definition json_path.h:46
std::optional< json > at_path(const json &root, const std::string &path)
Navigate into root by dot-path. Returns nullopt if path doesn't resolve.
Definition json_path.h:55
T get_path(const json &root, const std::string &path, const T &default_val)
Fetch value at path or return default_val on missing/wrong-type.
Definition json_path.h:83