1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use std::fmt::{Display, Formatter, Result};

use crate::query::Comparison;

#[derive(Clone, Debug)]
enum Operator {
    AND,
    OR,
}

impl Display for Operator {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "{}",
            match self {
                Self::AND => "&&",
                Self::OR => "||",
            }
        )
    }
}

/// Allows to filter a query according to different [`Comparison`].
/// as an AQL string with the [`to_aql`] method.
///
/// [`to_aql`]: struct.Filter.html#method.to_aql
/// [`Comparison`]: struct.Comparison.html
#[derive(Clone, Debug)]
pub struct Filter {
    comparisons: Vec<Comparison>,
    operators: Vec<Operator>,
}

impl Filter {
    /// Instantiates a new query filter from a comparison item
    ///
    /// # Example
    ///
    /// ```rust
    /// # use aragog::query::{Comparison, Filter};
    /// let filter = Filter::new(Comparison::field("age").greater_than(10));
    /// ```
    pub fn new(comparison: Comparison) -> Self {
        Self {
            comparisons: vec![comparison],
            operators: vec![],
        }
    }

    /// Appends the filter current condition(s) with a new one with a `AND` logic.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use aragog::query::{Comparison, Filter};
    /// let mut filter = Filter::new(Comparison::field("age").greater_than(10));
    /// filter = filter.and(Comparison::field("username").in_str_array(&["felix", "felixm"]));
    /// ```
    ///
    pub fn and(mut self, comparison: Comparison) -> Self {
        self.comparisons.push(comparison);
        self.operators.push(Operator::AND);
        self
    }

    /// Appends the filter current condition(s) with a new one with a `OR` logic.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use aragog::query::{Comparison, Filter};
    /// let mut filter = Filter::new(Comparison::field("age").greater_than(10));
    /// filter = filter.or(Comparison::field("username").in_str_array(&["felix", "felixm"]));
    /// ```
    ///
    pub fn or(mut self, comparison: Comparison) -> Self {
        self.comparisons.push(comparison);
        self.operators.push(Operator::OR);
        self
    }

    /// Renders the AQL string corresponding to the current `Filter`. The query will go out of scope.
    ///
    /// # Example
    ///
    /// ```rust
    /// # use aragog::query::{Comparison, Filter};
    /// let mut filter = Filter::new(Comparison::field("age").greater_than(10)).
    ///     or(Comparison::field("username").in_str_array(&["felix", "felixm"]));
    /// assert_eq!(filter.to_aql("i"), String::from(r#"i.age > 10 || i.username IN ["felix", "felixm"]"#));
    /// ```
    pub fn to_aql(&self, collection_id: &str) -> String {
        let mut res = String::new();
        for (i, comparison) in self.comparisons.iter().enumerate() {
            let operator_str = if i >= self.operators.len() {
                String::new()
            } else {
                format!(" {}", self.operators[i].to_string())
            };
            res = format!(
                "{} {}{}",
                res,
                comparison.to_aql(collection_id),
                operator_str
            )
        }
        String::from(res.trim_start())
    }
}