use std::convert::TryFrom;
use diesel::{
dsl::{count_star, exists},
prelude::*,
};
use crate::admin::store::{
diesel::{
models::CircuitStatusModel,
schema::{circuit, circuit_member},
},
error::AdminServiceStoreError,
CircuitPredicate,
};
use crate::error::InternalError;
use super::AdminServiceStoreOperations;
pub(in crate::admin::store::diesel) trait AdminServiceStoreCountCircuitsOperation {
fn count_circuits(
&self,
predicates: &[CircuitPredicate],
) -> Result<u32, AdminServiceStoreError>;
}
impl<'a, C> AdminServiceStoreCountCircuitsOperation for AdminServiceStoreOperations<'a, C>
where
C: diesel::Connection,
i64: diesel::deserialize::FromSql<diesel::sql_types::BigInt, C::Backend>,
{
fn count_circuits(
&self,
predicates: &[CircuitPredicate],
) -> Result<u32, AdminServiceStoreError> {
let management_types: Vec<String> = predicates
.iter()
.filter_map(|pred| match pred {
CircuitPredicate::ManagementTypeEq(man_type) => Some(man_type.to_string()),
_ => None,
})
.collect::<Vec<String>>();
let members: Vec<String> = predicates
.iter()
.filter_map(|pred| match pred {
CircuitPredicate::MembersInclude(members) => Some(members.to_vec()),
_ => None,
})
.flatten()
.collect();
let statuses: Vec<CircuitStatusModel> = predicates
.iter()
.filter_map(|pred| match pred {
CircuitPredicate::CircuitStatus(status) => Some(CircuitStatusModel::from(status)),
_ => None,
})
.collect();
self.conn.transaction::<u32, _, _>(|| {
let mut query = circuit::table.into_boxed().select(circuit::all_columns);
if !management_types.is_empty() {
query = query.filter(circuit::circuit_management_type.eq_any(management_types));
}
if !members.is_empty() {
query = query.filter(exists(
circuit_member::table.filter(
circuit_member::circuit_id
.eq(circuit::circuit_id)
.and(circuit_member::node_id.eq_any(members)),
),
));
}
if statuses.is_empty() {
query = query.filter(circuit::circuit_status.eq(CircuitStatusModel::Active));
} else {
query = query.filter(
circuit::circuit_status.eq_any(statuses),
);
}
let count = query.select(count_star()).first::<i64>(self.conn)?;
u32::try_from(count).map_err(|_| {
AdminServiceStoreError::InternalError(InternalError::with_message(
"The number of circuits is larger than the max u32".to_string(),
))
})
})
}
}