use std::{collections::HashMap, fmt};
use crate::{
bson::oid::ObjectId,
client::options::ServerAddress,
sdam::{ServerInfo, TopologyType},
selection_criteria::{ReadPreference, SelectionCriteria},
};
#[derive(Clone)]
pub struct TopologyDescription {
pub(crate) description: crate::sdam::TopologyDescription,
}
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()
}
}
impl fmt::Display for TopologyDescription {
fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
write!(f, "{{ Type: {:?}", self.description.topology_type)?;
if let Some(ref set_name) = self.description.set_name {
write!(f, ", Set Name: {}", set_name)?;
}
if let Some(max_set_version) = self.description.max_set_version {
write!(f, ", Max Set Version: {}", max_set_version)?;
}
if let Some(max_election_id) = self.description.max_election_id {
write!(f, ", Max Election ID: {}", max_election_id)?;
}
if let Some(ref compatibility_error) = self.description.compatibility_error {
write!(f, ", Compatibility Error: {}", compatibility_error)?;
}
if !self.description.servers.is_empty() {
write!(f, ", Servers: ")?;
let mut iter = self.description.servers.values();
if let Some(server) = iter.next() {
write!(f, "{}", ServerInfo::new_borrowed(server))?;
}
for server in iter {
write!(f, ", {}", ServerInfo::new_borrowed(server))?;
}
}
write!(f, " }}")
}
}