| 3803 | } |
| 3804 | |
| 3805 | static char *handle_query_graph(cbm_mcp_server_t *srv, const char *args) { |
| 3806 | char *query = cbm_mcp_get_string_arg(args, "query"); |
| 3807 | char *project = get_project_arg(args); |
| 3808 | cbm_store_t *store = resolve_store(srv, project); |
| 3809 | int max_rows = cbm_mcp_get_int_arg(args, "max_rows", 0); |
| 3810 | |
| 3811 | /* graph="missed" (#963): run the SAME cypher against the derived |
| 3812 | * miss-graph view (shadow project "<project>::missed") instead of the |
| 3813 | * code graph — file structure of not-fully-indexed files only. */ |
| 3814 | char *graph_arg = cbm_mcp_get_string_arg(args, "graph"); |
| 3815 | bool missed_graph = graph_arg && strcmp(graph_arg, "missed") == 0; |
| 3816 | free(graph_arg); |
| 3817 | |
| 3818 | if (!query) { |
| 3819 | free(project); |
| 3820 | return cbm_mcp_text_result("query is required", true); |
| 3821 | } |
| 3822 | if (missed_graph && !project) { |
| 3823 | free(query); |
| 3824 | return cbm_mcp_text_result("project is required when graph=\"missed\"", true); |
| 3825 | } |
| 3826 | if (!store) { |
| 3827 | char *_err = build_project_list_error("project not found or not indexed"); |
| 3828 | char *_res = cbm_mcp_text_result(_err, true); |
| 3829 | free(_err); |
| 3830 | free(project); |
| 3831 | free(query); |
| 3832 | return _res; |
| 3833 | } |
| 3834 | |
| 3835 | char *not_indexed = verify_project_indexed(store, project); |
| 3836 | if (not_indexed) { |
| 3837 | free(project); |
| 3838 | free(query); |
| 3839 | return not_indexed; |
| 3840 | } |
| 3841 | |
| 3842 | char covproj[CBM_SZ_512]; |
| 3843 | const char *cypher_project = project; |
| 3844 | if (missed_graph) { |
| 3845 | cbm_store_coverage_shadow_project(covproj, sizeof(covproj), project); |
| 3846 | cypher_project = covproj; |
| 3847 | } |
| 3848 | |
| 3849 | cbm_cypher_result_t result = {0}; |
| 3850 | int rc = cbm_cypher_execute(store, query, cypher_project, max_rows, &result); |
| 3851 | |
| 3852 | if (rc < 0) { |
| 3853 | char *err_msg = result.error ? result.error : "query execution failed"; |
| 3854 | char *resp = cbm_mcp_text_result(err_msg, true); |
| 3855 | cbm_cypher_result_free(&result); |
| 3856 | free(query); |
| 3857 | free(project); |
| 3858 | return resp; |
| 3859 | } |
| 3860 | |
| 3861 | /* Response encoding: TOON table by default (the columns double as the |
| 3862 | * table header); format:"json" restores the legacy columns/rows arrays. */ |
no test coverage detected