organizational_intelligence_plugin/
query.rs

1//! Natural Language Query Parser
2//!
3//! Implements Section 10: Query System & Natural Language Interface
4//! Phase 1: Basic pattern matching for common queries
5
6use anyhow::Result;
7
8/// Query type extracted from natural language
9#[derive(Debug, Clone, PartialEq)]
10pub enum QueryType {
11    /// "show me most common defect"
12    MostCommonDefect,
13    /// "count defects by category"
14    CountByCategory,
15    /// "show all defects"
16    ListAll,
17    /// Unknown query
18    Unknown(String),
19}
20
21/// Parsed query with parameters
22#[derive(Debug, Clone)]
23pub struct Query {
24    pub query_type: QueryType,
25    pub original: String,
26}
27
28/// Natural language query parser
29pub struct QueryParser;
30
31impl QueryParser {
32    pub fn new() -> Self {
33        Self
34    }
35
36    /// Parse natural language query into structured query
37    pub fn parse(&self, input: &str) -> Result<Query> {
38        let lower = input.to_lowercase();
39
40        let query_type = if lower.contains("most common") || lower.contains("top defect") {
41            QueryType::MostCommonDefect
42        } else if lower.contains("count")
43            && (lower.contains("category") || lower.contains("defect"))
44        {
45            QueryType::CountByCategory
46        } else if lower.contains("show") && lower.contains("all") {
47            QueryType::ListAll
48        } else {
49            QueryType::Unknown(input.to_string())
50        };
51
52        Ok(Query {
53            query_type,
54            original: input.to_string(),
55        })
56    }
57}
58
59impl Default for QueryParser {
60    fn default() -> Self {
61        Self::new()
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_parser_creation() {
71        let _parser = QueryParser::new();
72    }
73
74    #[test]
75    fn test_most_common_defect() {
76        let parser = QueryParser::new();
77
78        let q1 = parser.parse("show me most common defect").unwrap();
79        assert_eq!(q1.query_type, QueryType::MostCommonDefect);
80
81        let q2 = parser.parse("what is the top defect?").unwrap();
82        assert_eq!(q2.query_type, QueryType::MostCommonDefect);
83    }
84
85    #[test]
86    fn test_count_by_category() {
87        let parser = QueryParser::new();
88
89        let q = parser.parse("count defects by category").unwrap();
90        assert_eq!(q.query_type, QueryType::CountByCategory);
91    }
92
93    #[test]
94    fn test_list_all() {
95        let parser = QueryParser::new();
96
97        let q = parser.parse("show all defects").unwrap();
98        assert_eq!(q.query_type, QueryType::ListAll);
99    }
100
101    #[test]
102    fn test_unknown_query() {
103        let parser = QueryParser::new();
104
105        let q = parser.parse("hello world").unwrap();
106        assert!(matches!(q.query_type, QueryType::Unknown(_)));
107    }
108
109    #[test]
110    fn test_parser_default() {
111        let parser = QueryParser;
112        let q = parser.parse("show me most common defect").unwrap();
113        assert_eq!(q.query_type, QueryType::MostCommonDefect);
114    }
115
116    #[test]
117    fn test_query_original_preserved() {
118        let parser = QueryParser::new();
119        let input = "Count Defects BY Category";
120        let q = parser.parse(input).unwrap();
121        assert_eq!(q.original, input);
122        assert_eq!(q.query_type, QueryType::CountByCategory);
123    }
124
125    #[test]
126    fn test_count_with_category_keyword() {
127        let parser = QueryParser::new();
128        let q = parser.parse("count by category").unwrap();
129        assert_eq!(q.query_type, QueryType::CountByCategory);
130    }
131
132    #[test]
133    fn test_count_with_defect_keyword() {
134        let parser = QueryParser::new();
135        let q = parser.parse("count defect types").unwrap();
136        assert_eq!(q.query_type, QueryType::CountByCategory);
137    }
138
139    #[test]
140    fn test_case_insensitive_parsing() {
141        let parser = QueryParser::new();
142
143        let q1 = parser.parse("SHOW ALL DEFECTS").unwrap();
144        assert_eq!(q1.query_type, QueryType::ListAll);
145
146        let q2 = parser.parse("Most Common Defect").unwrap();
147        assert_eq!(q2.query_type, QueryType::MostCommonDefect);
148    }
149
150    #[test]
151    fn test_unknown_with_original_string() {
152        let parser = QueryParser::new();
153        let q = parser.parse("random query").unwrap();
154
155        if let QueryType::Unknown(original) = q.query_type {
156            assert_eq!(original, "random query");
157        } else {
158            panic!("Expected Unknown query type");
159        }
160    }
161
162    #[test]
163    fn test_query_type_clone() {
164        let qt1 = QueryType::MostCommonDefect;
165        let qt2 = qt1.clone();
166        assert_eq!(qt1, qt2);
167    }
168
169    #[test]
170    fn test_query_struct_clone() {
171        let q1 = Query {
172            query_type: QueryType::ListAll,
173            original: "test".to_string(),
174        };
175        let q2 = q1.clone();
176        assert_eq!(q2.original, "test");
177    }
178}