use std::borrow::Cow;
use crate::query::{Condition, Field, FieldRegistry, Operator, Span, Value};
#[derive(Clone, Debug)]
pub struct ConditionBuilder {
field: Cow<'static, str>,
operator: Operator,
value: Value,
}
impl ConditionBuilder {
#[must_use]
pub fn new_static(field: &'static str, operator: Operator, value: Value) -> Self {
Self {
field: Cow::Borrowed(field),
operator,
value,
}
}
pub fn new(field: impl Into<String>, operator: Operator, value: Value) -> Self {
Self {
field: Cow::Owned(field.into()),
operator,
value,
}
}
#[must_use]
pub fn field(&self) -> &str {
&self.field
}
#[must_use]
pub fn operator(&self) -> &Operator {
&self.operator
}
#[must_use]
pub fn value(&self) -> &Value {
&self.value
}
#[must_use]
pub fn into_condition(self, registry: &FieldRegistry) -> Condition {
let field = self.field;
let canonical_name = match registry.resolve_canonical(field.as_ref()) {
Some(canonical) => canonical.to_string(),
None => field.into_owned(),
};
Condition {
field: Field::new(canonical_name),
operator: self.operator,
value: self.value,
span: Span::synthetic(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::query::FieldRegistry;
#[test]
fn test_new_static() {
let cond = ConditionBuilder::new_static(
"kind",
Operator::Equal,
Value::String("function".to_string()),
);
assert_eq!(cond.field(), "kind");
assert_eq!(cond.operator(), &Operator::Equal);
assert!(matches!(cond.value(), Value::String(s) if s == "function"));
}
#[test]
fn test_new_dynamic() {
let field_name = String::from("custom_field");
let cond = ConditionBuilder::new(
field_name,
Operator::Regex,
Value::String("pattern".to_string()),
);
assert_eq!(cond.field(), "custom_field");
assert_eq!(cond.operator(), &Operator::Regex);
}
#[test]
fn test_into_condition_canonical() {
let registry = FieldRegistry::with_core_fields();
let cond = ConditionBuilder::new_static(
"kind",
Operator::Equal,
Value::String("function".to_string()),
);
let condition = cond.into_condition(®istry);
assert_eq!(condition.field.as_str(), "kind");
assert!(condition.span.is_synthetic());
}
#[test]
fn test_into_condition_alias_resolution() {
let registry = FieldRegistry::with_core_fields();
let cond = ConditionBuilder::new_static(
"file",
Operator::Equal,
Value::String("src/main.rs".to_string()),
);
let condition = cond.into_condition(®istry);
assert_eq!(condition.field.as_str(), "path");
let cond = ConditionBuilder::new_static(
"language",
Operator::Equal,
Value::String("rust".to_string()),
);
let condition = cond.into_condition(®istry);
assert_eq!(condition.field.as_str(), "lang");
}
#[test]
fn test_into_condition_unknown_field_kept() {
let registry = FieldRegistry::with_core_fields();
let cond = ConditionBuilder::new(
"unknown_field",
Operator::Equal,
Value::String("value".to_string()),
);
let condition = cond.into_condition(®istry);
assert_eq!(condition.field.as_str(), "unknown_field");
}
#[test]
fn test_clone() {
let cond = ConditionBuilder::new_static(
"name",
Operator::Regex,
Value::String("test.*".to_string()),
);
let cloned = cond.clone();
assert_eq!(cloned.field(), "name");
assert_eq!(cloned.operator(), &Operator::Regex);
}
}