use std::{collections::HashMap, fmt};
use serde::Serialize;
use crate::{
bson::oid::ObjectId,
client::options::ServerAddress,
sdam::{ServerInfo, TopologyType},
selection_criteria::{ReadPreference, SelectionCriteria},
};
#[derive(Clone, derive_more::Display)]
#[display(fmt = "{}", description)]
pub struct TopologyDescription {
pub(crate) description: crate::sdam::TopologyDescription,
}
impl Serialize for TopologyDescription {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.description.serialize(serializer)
}
}
impl From<crate::sdam::TopologyDescription> for TopologyDescription {
fn from(description: crate::sdam::TopologyDescription) -> Self {
Self { description }
}
}
impl TopologyDescription {
pub fn has_readable_server(&self, selection_criteria: Option<SelectionCriteria>) -> bool {
match self.description.suitable_servers_in_latency_window(
&selection_criteria
.unwrap_or(SelectionCriteria::ReadPreference(ReadPreference::Primary)),
) {
Ok(servers) => !servers.is_empty(),
Err(_) => false,
}
}
pub fn has_writable_server(&self) -> bool {
match self.description.topology_type {
TopologyType::Unknown | TopologyType::ReplicaSetNoPrimary => false,
TopologyType::Single | TopologyType::Sharded => {
self.description.has_available_servers()
}
TopologyType::ReplicaSetWithPrimary | TopologyType::LoadBalanced => true,
}
}
pub fn topology_type(&self) -> TopologyType {
self.description.topology_type
}
pub fn set_name(&self) -> Option<&String> {
self.description.set_name.as_ref()
}
pub fn max_set_version(&self) -> Option<i32> {
self.description.max_set_version
}
pub fn max_election_id(&self) -> Option<ObjectId> {
self.description.max_election_id
}
pub fn compatibility_error(&self) -> Option<&String> {
self.description.compatibility_error.as_ref()
}
pub fn servers(&self) -> HashMap<&ServerAddress, ServerInfo> {
self.description
.servers
.iter()
.map(|(address, description)| (address, ServerInfo::new_borrowed(description)))
.collect()
}
}
impl fmt::Debug for TopologyDescription {
fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
f.debug_struct("Topology Description")
.field("Type", &self.topology_type())
.field("Set Name", &self.set_name())
.field("Max Set Version", &self.max_set_version())
.field("Max Election ID", &self.max_election_id())
.field("Compatibility Error", &self.compatibility_error())
.field("Servers", &self.servers().values())
.finish()
}
}