Skip to main content

sqlite_graphrag/commands/
namespace_detect.rs

1use crate::errors::AppError;
2use crate::namespace;
3use crate::output;
4use serde::Serialize;
5
6#[derive(clap::Args)]
7pub struct NamespaceDetectArgs {
8    #[arg(long)]
9    pub namespace: Option<String>,
10    /// Flag explícita de saída JSON. Aceita como no-op pois o output já é JSON por default.
11    #[arg(long, default_value_t = false)]
12    pub json: bool,
13}
14
15#[derive(Serialize)]
16struct NamespaceDetectResponse {
17    namespace: String,
18    source: namespace::NamespaceSource,
19    cwd: String,
20    /// Tempo total de execução em milissegundos desde início do handler até serialização.
21    elapsed_ms: u64,
22}
23
24pub fn run(args: NamespaceDetectArgs) -> Result<(), AppError> {
25    let inicio = std::time::Instant::now();
26    let _ = args.json; // --json é no-op pois output já é JSON por default
27    let resolution = namespace::detect_namespace(args.namespace.as_deref())?;
28    output::emit_json(&NamespaceDetectResponse {
29        namespace: resolution.namespace,
30        source: resolution.source,
31        cwd: resolution.cwd,
32        elapsed_ms: inicio.elapsed().as_millis() as u64,
33    })?;
34    Ok(())
35}
36
37#[cfg(test)]
38mod testes {
39    use super::*;
40    use crate::namespace::NamespaceSource;
41    use serial_test::serial;
42
43    #[test]
44    #[serial]
45    fn namespace_detect_default_retorna_global_via_detect() {
46        // Garante que sem flag e sem env, detect_namespace retorna "global"
47        std::env::remove_var("SQLITE_GRAPHRAG_NAMESPACE");
48        let resolution = namespace::detect_namespace(None).unwrap();
49        assert_eq!(resolution.namespace, "global");
50        assert_eq!(resolution.source, NamespaceSource::Default);
51    }
52
53    #[test]
54    #[serial]
55    fn namespace_detect_explicit_flag_sobrepoe_env() {
56        std::env::set_var("SQLITE_GRAPHRAG_NAMESPACE", "env-namespace");
57        let resolution = namespace::detect_namespace(Some("flag-namespace")).unwrap();
58        assert_eq!(resolution.namespace, "flag-namespace");
59        assert_eq!(resolution.source, NamespaceSource::ExplicitFlag);
60        std::env::remove_var("SQLITE_GRAPHRAG_NAMESPACE");
61    }
62
63    #[test]
64    #[serial]
65    fn namespace_detect_env_var_usada_quando_sem_flag() {
66        std::env::remove_var("SQLITE_GRAPHRAG_NAMESPACE");
67        std::env::set_var("SQLITE_GRAPHRAG_NAMESPACE", "namespace-de-env");
68        let resolution = namespace::detect_namespace(None).unwrap();
69        assert_eq!(resolution.namespace, "namespace-de-env");
70        assert_eq!(resolution.source, NamespaceSource::Environment);
71        std::env::remove_var("SQLITE_GRAPHRAG_NAMESPACE");
72    }
73
74    #[test]
75    fn namespace_detect_response_serializa_todos_campos() {
76        let resp = NamespaceDetectResponse {
77            namespace: "meu-projeto".to_string(),
78            source: NamespaceSource::ExplicitFlag,
79            cwd: "/home/usuario/projeto".to_string(),
80            elapsed_ms: 3,
81        };
82        let json = serde_json::to_value(&resp).unwrap();
83        assert_eq!(json["namespace"], "meu-projeto");
84        assert_eq!(json["source"], "explicit_flag");
85        assert!(json["cwd"].is_string());
86        assert_eq!(json["elapsed_ms"], 3);
87    }
88
89    #[test]
90    fn namespace_source_serializa_em_snake_case() {
91        let casos = vec![
92            (NamespaceSource::ExplicitFlag, "explicit_flag"),
93            (NamespaceSource::Environment, "environment"),
94            (NamespaceSource::Default, "default"),
95        ];
96        for (source, esperado) in casos {
97            let json = serde_json::to_value(source).unwrap();
98            assert_eq!(
99                json, esperado,
100                "NamespaceSource::{source:?} deve serializar como \"{esperado}\""
101            );
102        }
103    }
104}