Merge pull request #1325 from Enferlain/fix/1284-list-valued-fields

fix(search): preserve compound requested fields
This commit is contained in:
Martin Vogel authored and GitHub committed 2026-08-18 00:04:55 +02:00
commit 2397d58da6
2 files changed
+50 -33

No files matched your search

+27 -30
View File
@@ -3241,6 +3241,27 @@ static int sg_parse_fields(const char *args, const char *out[], int max_out, yyj
return n;
}
/* Append a property as one compact-output cell. Compound values stay one
* column by using their compact JSON representation; the cell emitter quotes
* and escapes that representation as needed. */
static void sg_toon_property_cell(cbm_sb_t *sb, yyjson_val *v) {
if (v && yyjson_is_str(v)) {
cbm_tree_cell_str(sb, yyjson_get_str(v), false);
} else if (v && yyjson_is_bool(v)) {
cbm_tree_cell_bool(sb, yyjson_get_bool(v), false);
} else if (v && yyjson_is_int(v)) {
cbm_tree_cell_int(sb, yyjson_get_int(v), false);
} else if (v && yyjson_is_real(v)) {
cbm_tree_cell_real(sb, yyjson_get_real(v), false);
} else if (v && !yyjson_is_null(v)) {
char *json = yyjson_val_write(v, 0, NULL);
cbm_tree_cell_str(sb, json ? json : "", false);
free(json);
} else {
cbm_tree_cell_str(sb, "", false);
}
}
/* Append one row's extra-field cells, pulled from the node's properties. */
static void sg_toon_extra_cells(cbm_sb_t *sb, const char *props_json, const char *const *fields,
int nfields) {
@@ -3249,17 +3270,7 @@ static void sg_toon_extra_cells(cbm_sb_t *sb, const char *props_json, const char
yyjson_val *pr = pd ? yyjson_doc_get_root(pd) : NULL;
for (int f = 0; f < nfields; f++) {
yyjson_val *v = (pr && yyjson_is_obj(pr)) ? yyjson_obj_get(pr, fields[f]) : NULL;
if (v && yyjson_is_str(v)) {
cbm_tree_cell_str(sb, yyjson_get_str(v), false);
} else if (v && yyjson_is_bool(v)) {
cbm_tree_cell_bool(sb, yyjson_get_bool(v), false);
} else if (v && yyjson_is_int(v)) {
cbm_tree_cell_int(sb, yyjson_get_int(v), false);
} else if (v && yyjson_is_real(v)) {
cbm_tree_cell_real(sb, yyjson_get_real(v), false);
} else {
cbm_tree_cell_str(sb, "", false);
}
sg_toon_property_cell(sb, v);
}
if (pd) {
yyjson_doc_free(pd);
@@ -3391,17 +3402,7 @@ static void emit_search_results_tree(cbm_sb_t *sb, cbm_search_output_t *out, int
yyjson_val *pr = pd ? yyjson_doc_get_root(pd) : NULL;
for (int f = 0; f < nfields; f++) {
yyjson_val *v = (pr && yyjson_is_obj(pr)) ? yyjson_obj_get(pr, fields[f]) : NULL;
if (v && yyjson_is_str(v)) {
cbm_tree_cell_str(sb, yyjson_get_str(v), false);
} else if (v && yyjson_is_int(v)) {
cbm_tree_cell_int(sb, yyjson_get_int(v), false);
} else if (v && yyjson_is_real(v)) {
cbm_tree_cell_real(sb, yyjson_get_real(v), false);
} else if (v && yyjson_is_bool(v)) {
cbm_tree_cell_bool(sb, yyjson_get_bool(v), false);
} else {
cbm_tree_cell_str(sb, "", false); /* emits "-" */
}
sg_toon_property_cell(sb, v);
}
if (pd) {
yyjson_doc_free(pd);
@@ -3483,14 +3484,10 @@ static void emit_search_results_tree_json(yyjson_mut_doc *doc, yyjson_mut_val *r
yyjson_val *pr = pd ? yyjson_doc_get_root(pd) : NULL;
for (int f = 0; f < nfields; f++) {
yyjson_val *v = (pr && yyjson_is_obj(pr)) ? yyjson_obj_get(pr, fields[f]) : NULL;
if (v && yyjson_is_str(v)) {
yyjson_mut_arr_add_strcpy(doc, row, yyjson_get_str(v));
} else if (v && yyjson_is_int(v)) {
yyjson_mut_arr_add_int(doc, row, yyjson_get_int(v));
} else if (v && yyjson_is_real(v)) {
yyjson_mut_arr_add_real(doc, row, yyjson_get_real(v));
} else if (v && yyjson_is_bool(v)) {
yyjson_mut_arr_add_bool(doc, row, yyjson_get_bool(v));
yyjson_mut_val *copy =
(v && !yyjson_is_null(v)) ? yyjson_val_mut_copy(doc, v) : NULL;
if (copy) {
yyjson_mut_arr_add_val(row, copy);
} else {
yyjson_mut_arr_add_null(doc, row);
}
+23 -3
View File
@@ -2084,15 +2084,32 @@ TEST(tool_search_graph_includes_node_properties) {
free(inner);
free(resp);
/* List-valued fields are compact JSON in text output, rather than an
* empty placeholder. */
resp = cbm_mcp_server_handle(
srv, "{\"jsonrpc\":\"2.0\",\"id\":431,\"method\":\"tools/call\","
"\"params\":{\"name\":\"search_graph\","
"\"arguments\":{\"project\":\"test-project\",\"label\":\"Function\","
"\"name_pattern\":\"HandleRequest\",\"fields\":[\"base_classes\"],"
"\"limit\":5}}}");
ASSERT_NOT_NULL(resp);
inner = extract_text_content(resp);
ASSERT_NOT_NULL(inner);
ASSERT_NOT_NULL(strstr(inner, "base_classes"));
ASSERT_NOT_NULL(strstr(inner, "HandlerBase"));
ASSERT_NOT_NULL(strstr(inner, "Audited"));
free(inner);
free(resp);
/* format:"json" = json-stringified tree: same grouped model, column-
* ordered row arrays — never per-row key envelopes or property blobs.
* fields adds columns there too. */
* fields adds columns there too and preserves compound JSON types. */
resp = cbm_mcp_server_handle(
srv, "{\"jsonrpc\":\"2.0\",\"id\":44,\"method\":\"tools/call\","
"\"params\":{\"name\":\"search_graph\","
"\"arguments\":{\"project\":\"test-project\",\"label\":\"Function\","
"\"name_pattern\":\"HandleRequest\",\"format\":\"json\","
"\"fields\":[\"signature\"],\"limit\":5}}}");
"\"fields\":[\"signature\",\"base_classes\"],\"limit\":5}}}");
ASSERT_NOT_NULL(resp);
inner = extract_text_content(resp);
ASSERT_NOT_NULL(inner);
@@ -2101,6 +2118,8 @@ TEST(tool_search_graph_includes_node_properties) {
ASSERT_NOT_NULL(strstr(inner, "\"rows\""));
ASSERT_NOT_NULL(strstr(inner, "\"signature\"")); /* requested column */
ASSERT_NOT_NULL(strstr(inner, "func HandleRequest")); /* its value */
ASSERT_NOT_NULL(strstr(inner, "\"base_classes\""));
ASSERT_NOT_NULL(strstr(inner, "[\"HandlerBase\",\"Audited\"]"));
ASSERT_NULL(strstr(inner, "is_exported")); /* blob never spills */
free(inner);
free(resp);
@@ -7411,7 +7430,8 @@ static cbm_mcp_server_t *setup_snippet_server(char *tmp_dir, size_t tmp_sz) {
n_hr.end_line = 5;
n_hr.properties_json = "{\"signature\":\"func HandleRequest() error\","
"\"return_type\":\"error\","
"\"is_exported\":true}";
"\"is_exported\":true,"
"\"base_classes\":[\"HandlerBase\",\"Audited\"]}";
int64_t id_hr = cbm_store_upsert_node(st, &n_hr);
cbm_node_t n_po = {0};