Skip to main content

the_code_graph_cli/commands/
search.rs

1use domain::error::Result;
2use domain::use_cases::query::QueryUseCase;
3
4use crate::commands::helpers::open_graph;
5use crate::commands::SearchArgs;
6use crate::output::{print, OutputFormat};
7
8pub fn run_search(args: &SearchArgs, output_format: OutputFormat) -> Result<()> {
9    if args.semantic_only && args.fts_only {
10        return Err(domain::error::CodeGraphError::Other(
11            "--semantic-only and --fts-only are mutually exclusive".into(),
12        ));
13    }
14
15    let (store, _root) = open_graph()?;
16
17    #[cfg(feature = "embeddings")]
18    {
19        use std::sync::Arc;
20
21        use crate::config::load_config;
22        use domain::model::{HybridSearchConfig, SearchMode};
23        use domain::ports::VectorStore;
24
25        let config = load_config(&_root)?;
26        let mode = match (args.semantic_only, args.fts_only) {
27            (true, false) => SearchMode::SemanticOnly,
28            (false, true) => SearchMode::FtsOnly,
29            _ => SearchMode::Hybrid,
30        };
31
32        let hybrid_config = HybridSearchConfig {
33            rrf_k: config.search.as_ref().and_then(|s| s.rrf_k).unwrap_or(60),
34            kind_boost: config
35                .search
36                .as_ref()
37                .and_then(|s| s.kind_boost)
38                .unwrap_or(true),
39        };
40
41        let vs: Arc<dyn VectorStore> = Arc::new(store.clone());
42        if vs.has_embeddings() {
43            let model = config
44                .embeddings
45                .as_ref()
46                .and_then(|e| e.model.clone())
47                .unwrap_or_else(|| "all-MiniLM-L6-v2".into());
48            let ep: Arc<dyn domain::ports::EmbeddingProvider> = Arc::new(
49                embeddings::OnnxEmbeddingProvider::from_model_name(&model, 384)
50                    .map_err(|e| domain::error::CodeGraphError::Other(e.to_string()))?,
51            );
52            let uc = QueryUseCase::with_hybrid(store.clone(), store, Some(vs), Some(ep));
53            let results = uc.hybrid_search(&args.query, args.limit, mode, &hybrid_config)?;
54            print(&results, output_format);
55            return Ok(());
56        }
57    }
58
59    if args.semantic_only {
60        return Err(domain::error::CodeGraphError::Other(
61            "no embeddings found; run 'code-graph index --embed' first".into(),
62        ));
63    }
64    let uc = QueryUseCase::new(store.clone(), store);
65    let results = uc.search(&args.query, args.limit)?;
66    print(&results, output_format);
67    Ok(())
68}