use std::convert::TryFrom;
use diesel::{
dsl::{count_star, exists},
prelude::*,
};
use crate::admin::store::{
diesel::schema::{proposed_circuit, proposed_node},
error::AdminServiceStoreError,
CircuitPredicate,
};
use crate::error::InternalError;
use super::AdminServiceStoreOperations;
pub(in crate::admin::store::diesel) trait AdminServiceStoreCountProposalsOperation {
fn count_proposals(
&self,
predicates: &[CircuitPredicate],
) -> Result<u32, AdminServiceStoreError>;
}
impl<'a, C> AdminServiceStoreCountProposalsOperation for AdminServiceStoreOperations<'a, C>
where
C: diesel::Connection,
i64: diesel::deserialize::FromSql<diesel::sql_types::BigInt, C::Backend>,
{
fn count_proposals(
&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();
self.conn.transaction::<u32, _, _>(|| {
let mut query = proposed_circuit::table
.into_boxed()
.select(proposed_circuit::all_columns);
if !members.is_empty() {
query = query.filter(exists(
proposed_node::table.filter(
proposed_node::circuit_id
.eq(proposed_circuit::circuit_id)
.and(proposed_node::node_id.eq_any(members)),
),
))
}
if !management_types.is_empty() {
query = query
.filter(proposed_circuit::circuit_management_type.eq_any(management_types));
}
let count = query.select(count_star()).first::<i64>(self.conn)?;
u32::try_from(count).map_err(|_| {
AdminServiceStoreError::InternalError(InternalError::with_message(
"The number of proposals is larger than the max u32".to_string(),
))
})
})
}
}