| 3772 | } |
| 3773 | |
| 3774 | static char *handle_query_graph(cbm_mcp_server_t *srv, const char *args) { |
| 3775 | char *query = cbm_mcp_get_string_arg(args, "query"); |
| 3776 | char *project = get_project_arg(args); |
| 3777 | cbm_store_t *store = resolve_store(srv, project); |
| 3778 | int max_rows = cbm_mcp_get_int_arg(args, "max_rows", 0); |
| 3779 | |
| 3780 | /* graph="missed" (#963): run the SAME cypher against the derived |
| 3781 | * miss-graph view (shadow project "<project>::missed") instead of the |
| 3782 | * code graph — file structure of not-fully-indexed files only. */ |
| 3783 | char *graph_arg = cbm_mcp_get_string_arg(args, "graph"); |
| 3784 | bool missed_graph = graph_arg && strcmp(graph_arg, "missed") == 0; |
| 3785 | free(graph_arg); |
| 3786 | |
| 3787 | if (!query) { |
| 3788 | free(project); |
| 3789 | return cbm_mcp_text_result("query is required", true); |
| 3790 | } |
| 3791 | if (missed_graph && !project) { |
| 3792 | free(query); |
| 3793 | return cbm_mcp_text_result("project is required when graph=\"missed\"", true); |
| 3794 | } |
| 3795 | if (!store) { |
| 3796 | char *_err = build_project_list_error("project not found or not indexed"); |
| 3797 | char *_res = cbm_mcp_text_result(_err, true); |
| 3798 | free(_err); |
| 3799 | free(project); |
| 3800 | free(query); |
| 3801 | return _res; |
| 3802 | } |
| 3803 | |
| 3804 | char *not_indexed = verify_project_indexed(store, project); |
| 3805 | if (not_indexed) { |
| 3806 | free(project); |
| 3807 | free(query); |
| 3808 | return not_indexed; |
| 3809 | } |
| 3810 | |
| 3811 | char covproj[CBM_SZ_512]; |
| 3812 | const char *cypher_project = project; |
| 3813 | if (missed_graph) { |
| 3814 | cbm_store_coverage_shadow_project(covproj, sizeof(covproj), project); |
| 3815 | cypher_project = covproj; |
| 3816 | } |
| 3817 | |
| 3818 | cbm_cypher_result_t result = {0}; |
| 3819 | int rc = cbm_cypher_execute(store, query, cypher_project, max_rows, &result); |
| 3820 | |
| 3821 | if (rc < 0) { |
| 3822 | char *err_msg = result.error ? result.error : "query execution failed"; |
| 3823 | char *resp = cbm_mcp_text_result(err_msg, true); |
| 3824 | cbm_cypher_result_free(&result); |
| 3825 | free(query); |
| 3826 | free(project); |
| 3827 | return resp; |
| 3828 | } |
| 3829 | |
| 3830 | /* Response encoding: TOON table by default (the columns double as the |
| 3831 | * table header); format:"json" restores the legacy columns/rows arrays. */ |
no test coverage detected