sqry_core/query/builder/
condition.rs1use std::borrow::Cow;
4
5use crate::query::{Condition, Field, FieldRegistry, Operator, Span, Value};
6
7#[derive(Clone, Debug)]
15pub struct ConditionBuilder {
16 field: Cow<'static, str>,
19 operator: Operator,
21 value: Value,
23}
24
25impl ConditionBuilder {
26 #[must_use]
31 pub fn new_static(field: &'static str, operator: Operator, value: Value) -> Self {
32 Self {
33 field: Cow::Borrowed(field),
34 operator,
35 value,
36 }
37 }
38
39 pub fn new(field: impl Into<String>, operator: Operator, value: Value) -> Self {
44 Self {
45 field: Cow::Owned(field.into()),
46 operator,
47 value,
48 }
49 }
50
51 #[must_use]
53 pub fn field(&self) -> &str {
54 &self.field
55 }
56
57 #[must_use]
59 pub fn operator(&self) -> &Operator {
60 &self.operator
61 }
62
63 #[must_use]
65 pub fn value(&self) -> &Value {
66 &self.value
67 }
68
69 #[must_use]
74 pub fn into_condition(self, registry: &FieldRegistry) -> Condition {
75 let field = self.field;
77 let canonical_name = match registry.resolve_canonical(field.as_ref()) {
78 Some(canonical) => canonical.to_string(),
79 None => field.into_owned(),
80 };
81
82 Condition {
83 field: Field::new(canonical_name),
84 operator: self.operator,
85 value: self.value,
86 span: Span::synthetic(),
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use crate::query::FieldRegistry;
95
96 #[test]
97 fn test_new_static() {
98 let cond = ConditionBuilder::new_static(
99 "kind",
100 Operator::Equal,
101 Value::String("function".to_string()),
102 );
103 assert_eq!(cond.field(), "kind");
104 assert_eq!(cond.operator(), &Operator::Equal);
105 assert!(matches!(cond.value(), Value::String(s) if s == "function"));
106 }
107
108 #[test]
109 fn test_new_dynamic() {
110 let field_name = String::from("custom_field");
111 let cond = ConditionBuilder::new(
112 field_name,
113 Operator::Regex,
114 Value::String("pattern".to_string()),
115 );
116 assert_eq!(cond.field(), "custom_field");
117 assert_eq!(cond.operator(), &Operator::Regex);
118 }
119
120 #[test]
121 fn test_into_condition_canonical() {
122 let registry = FieldRegistry::with_core_fields();
123 let cond = ConditionBuilder::new_static(
124 "kind",
125 Operator::Equal,
126 Value::String("function".to_string()),
127 );
128 let condition = cond.into_condition(®istry);
129 assert_eq!(condition.field.as_str(), "kind");
130 assert!(condition.span.is_synthetic());
131 }
132
133 #[test]
134 fn test_into_condition_alias_resolution() {
135 let registry = FieldRegistry::with_core_fields();
136
137 let cond = ConditionBuilder::new_static(
139 "file",
140 Operator::Equal,
141 Value::String("src/main.rs".to_string()),
142 );
143 let condition = cond.into_condition(®istry);
144 assert_eq!(condition.field.as_str(), "path");
145
146 let cond = ConditionBuilder::new_static(
148 "language",
149 Operator::Equal,
150 Value::String("rust".to_string()),
151 );
152 let condition = cond.into_condition(®istry);
153 assert_eq!(condition.field.as_str(), "lang");
154 }
155
156 #[test]
157 fn test_into_condition_unknown_field_kept() {
158 let registry = FieldRegistry::with_core_fields();
159
160 let cond = ConditionBuilder::new(
162 "unknown_field",
163 Operator::Equal,
164 Value::String("value".to_string()),
165 );
166 let condition = cond.into_condition(®istry);
167 assert_eq!(condition.field.as_str(), "unknown_field");
168 }
169
170 #[test]
171 fn test_clone() {
172 let cond = ConditionBuilder::new_static(
173 "name",
174 Operator::Regex,
175 Value::String("test.*".to_string()),
176 );
177 let cloned = cond.clone();
178 assert_eq!(cloned.field(), "name");
179 assert_eq!(cloned.operator(), &Operator::Regex);
180 }
181}