| 289 | /// @{ |
| 290 | |
| 291 | void extract_jsonb_path(Node* expr, std::vector<std::string>& path, Node** base_col) |
| 292 | { |
| 293 | if (IsA(expr, OpExpr)) { |
| 294 | OpExpr* op = (OpExpr*)expr; |
| 295 | char* opname = get_opname(op->opno); |
| 296 | |
| 297 | if (opname && (strcmp(opname, "->") == 0 || strcmp(opname, "->>") == 0)) { |
| 298 | Node* left = (Node*)linitial(op->args); |
| 299 | Node* right = (Node*)lsecond(op->args); |
| 300 | |
| 301 | // Recursively extract path from left side |
| 302 | extract_jsonb_path(left, path, base_col); |
| 303 | |
| 304 | // Add current key to path |
| 305 | if (IsA(right, Const)) { |
| 306 | Const* kc = (Const*)right; |
| 307 | if (kc->consttype == TEXTOID && !kc->constisnull) { |
| 308 | char* key = text_to_cstring(DatumGetTextPP(kc->constvalue)); |
| 309 | path.push_back(std::string(key)); |
| 310 | pfree(key); |
| 311 | } |
| 312 | } |
| 313 | } else { |
| 314 | *base_col = expr; |
| 315 | } |
| 316 | |
| 317 | if (opname) |
| 318 | pfree(opname); |
| 319 | } else { |
| 320 | *base_col = expr; |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | // Build nested JSON from path: ["a", "b", "c"] with value "v" -> {"a": {"b": {"c": "v"}}} |
| 325 | std::string build_nested_json(const std::vector<std::string>& path, const std::string& value) |
no test coverage detected