use std::ops::{BitAnd, BitOr};
use std::vec;
use crate::{combine_query, LdapValue};
pub trait ToLdapFilter {
fn to_ldap_filter(&self) -> String;
}
#[derive(Debug, Clone)]
pub struct Condition<'a, V: LdapValue = &'a str> {
attribute: &'a str,
value: Option<V>,
not: bool,
}
impl<'a, V: LdapValue> Condition<'a, V> {
pub fn new(attribute: &str) -> Condition<V> {
Condition {
attribute,
value: None,
not: false
}
}
pub fn value(mut self, value: V) -> Condition<'a, V> {
self.value = Some(value);
self.clone()
}
pub fn not(mut self) -> Condition<'a, V> {
self.not = !self.not;
self.clone()
}
}
impl<'a, V: LdapValue> From<&Condition<'a, V>> for Group<'a, V> {
fn from(value: &Condition<'a, V>) -> Self {
Group {
t: ConditionType::Single,
conditions: vec![GroupWrapper::Condition(value.clone())],
not: false
}
}
}
impl<'a, V: LdapValue> BitAnd for Condition<'a, V> {
type Output = Group<'a, V>;
fn bitand(self, rhs: Self) -> Self::Output {
Group::to_group(self, rhs, ConditionType::And)
}
}
impl<'a, V: LdapValue> BitAnd for &Condition<'a, V> {
type Output = Group<'a, V>;
fn bitand(self, rhs: Self) -> Self::Output {
self.clone() & rhs.clone()
}
}
impl<'a, V: LdapValue> BitOr for Condition<'a, V> {
type Output = Group<'a, V>;
fn bitor(self, rhs: Self) -> Self::Output {
Group::to_group(self, rhs, ConditionType::Or)
}
}
impl<'a, V: LdapValue> BitOr for &Condition<'a, V> {
type Output = Group<'a, V>;
fn bitor(self, rhs: Self) -> Self::Output {
self.clone() | rhs.clone()
}
}
impl<'a, V: LdapValue> BitOr<&Group<'a, V>> for &Condition<'a, V> {
type Output = Group<'a, V>;
fn bitor(self, rhs: &Group<'a, V>) -> Self::Output {
rhs.clone().add_to_group(self.clone().clone(), ConditionType::Or)
}
}
impl<'a, V: LdapValue> BitOr<&Condition<'a, V>> for &Group<'a, V> {
type Output = Group<'a, V>;
fn bitor(self, rhs: &Condition<'a, V>) -> Self::Output {
self.clone().add_to_group(rhs.clone().clone(), ConditionType::Or)
}
}
impl<'a, V: LdapValue> BitAnd<&Group<'a, V>> for &Condition<'a, V> {
type Output = Group<'a, V>;
fn bitand(self, rhs: &Group<'a, V>) -> Self::Output {
rhs.clone().add_to_group(self.clone().clone(), ConditionType::And)
}
}
impl<'a, V: LdapValue> BitAnd<&Condition<'a, V>> for &Group<'a, V> {
type Output = Group<'a, V>;
fn bitand(self, rhs: &Condition<'a, V>) -> Self::Output {
self.clone().add_to_group(rhs.clone().clone(), ConditionType::And)
}
}
combine_query!{BitOr, bitor, ConditionType::Or, Condition, Group}
combine_query!{BitOr, bitor, ConditionType::Or, Group, Condition}
combine_query!{BitAnd, bitand, ConditionType::And, Condition, Group}
combine_query!{BitAnd, bitand, ConditionType::And, Group, Condition}
impl<V: LdapValue> ToLdapFilter for &Condition<'_, V> {
fn to_ldap_filter(&self) -> String {
let inner_query = format!("{}={}", &self.attribute, &self.value.as_ref().map(|v| v.to_string()).unwrap_or(String::from("*")));
let query = if self.not {
format!("!({})", inner_query)
} else {
inner_query
};
format!("({})", query)
}
}
impl<V: LdapValue> ToLdapFilter for Condition<'_, V> {
fn to_ldap_filter(&self) -> String {
(&self).to_ldap_filter()
}
}
#[derive(Debug, Clone, PartialEq)]
enum ConditionType {
Single,
And,
Or
}
#[derive(Debug, Clone)]
enum GroupWrapper<'a, V: LdapValue> {
Condition(Condition<'a, V>),
Group(Group<'a, V>),
}
impl<'a, V: LdapValue> ToLdapFilter for GroupWrapper<'a, V> {
fn to_ldap_filter(&self) -> String {
match self {
GroupWrapper::Condition(c) => c.to_ldap_filter(),
GroupWrapper::Group(g) => g.to_ldap_filter()
}
}
}
impl<'a, V: LdapValue> From<Condition<'a, V>> for GroupWrapper<'a, V> {
fn from(value: Condition<'a, V>) -> Self {
GroupWrapper::Condition(value)
}
}
impl<'a, V: LdapValue> From<&Condition<'a, V>> for GroupWrapper<'a, V> {
fn from(value: &Condition<'a, V>) -> Self {
value.clone().into()
}
}
impl<'a, V: LdapValue> From<Group<'a, V>> for GroupWrapper<'a, V> {
fn from(value: Group<'a, V>) -> Self {
GroupWrapper::Group(value)
}
}
impl<'a, V: LdapValue> From<&Group<'a, V>> for GroupWrapper<'a, V> {
fn from(value: &Group<'a, V>) -> Self {
value.clone().into()
}
}
#[derive(Debug, Clone)]
pub struct Group<'a, V: LdapValue> {
t: ConditionType,
conditions: Vec<GroupWrapper<'a, V>>,
not: bool,
}
impl<'a, V: LdapValue> Group<'a, V> {
pub fn not(mut self) -> Self {
self.not = !self.not;
self
}
fn to_group<L: Into<GroupWrapper<'a, V>>, R: Into<GroupWrapper<'a, V>>>(lhs: L, rhs: R, op: ConditionType) -> Self {
Group {
t: op,
conditions: vec![lhs.into(), rhs.into()],
not: false
}
}
fn add_to_group(&mut self, rhs: Condition<'a, V>, op: ConditionType) -> Group<'a, V> {
if self.t == op {
self.conditions.push(rhs.into());
self.clone()
} else {
Group {
t: op,
conditions: vec![self.clone().into(), rhs.into()],
not: false
}
}
}
}
impl<'a, V: LdapValue> BitAnd for Group<'a, V> {
type Output = Group<'a, V>;
fn bitand(self, rhs: Self) -> Self::Output {
Group::to_group(&self, &rhs, ConditionType::And)
}
}
impl<'a, V: LdapValue> BitOr for Group<'a, V> {
type Output = Group<'a, V>;
fn bitor(self, rhs: Self) -> Self::Output {
Group::to_group(&self, &rhs, ConditionType::Or)
}
}
impl<V: LdapValue> ToLdapFilter for &Group<'_, V> {
fn to_ldap_filter(&self) -> String {
let query = if self.conditions.len() == 0 {
String::from("()")
} else if self.conditions.len() == 1 {
self.conditions[0].to_ldap_filter()
} else {
let conditions = self.conditions.iter().fold(String::new(), |str, b| format!("{}{}", str, b.to_ldap_filter()));
match self.t {
ConditionType::Single => conditions,
ConditionType::And => format!("(&{})", conditions),
ConditionType::Or => format!("(|{})", conditions)
}
};
if self.not {
format!("(!{})", query)
} else {
query
}
}
}
impl<V: LdapValue> ToLdapFilter for Group<'_, V> {
fn to_ldap_filter(&self) -> String {
(&self).to_ldap_filter()
}
}