mod action;
pub mod options;
use std::{fmt, fmt::Debug, str::FromStr, sync::Arc};
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
use self::options::*;
use crate::{
bson::doc,
client::options::ServerAddress,
cmap::conn::PinnedConnectionHandle,
concern::{ReadConcern, WriteConcern},
error::{Error, Result},
selection_criteria::SelectionCriteria,
Client,
Database,
};
#[derive(Debug)]
pub struct Collection<T>
where
T: Send + Sync,
{
inner: Arc<CollectionInner>,
_phantom: std::marker::PhantomData<fn() -> T>,
}
impl<T> Clone for Collection<T>
where
T: Send + Sync,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_phantom: Default::default(),
}
}
}
#[derive(Debug, Clone)]
struct CollectionInner {
client: Client,
db: Database,
name: String,
selection_criteria: Option<SelectionCriteria>,
read_concern: Option<ReadConcern>,
write_concern: Option<WriteConcern>,
}
impl<T> Collection<T>
where
T: Send + Sync,
{
pub(crate) fn new(db: Database, name: &str, options: Option<CollectionOptions>) -> Self {
let options = options.unwrap_or_default();
let selection_criteria = options
.selection_criteria
.or_else(|| db.selection_criteria().cloned());
let read_concern = options.read_concern.or_else(|| db.read_concern().cloned());
let write_concern = options
.write_concern
.or_else(|| db.write_concern().cloned());
Self {
inner: Arc::new(CollectionInner {
client: db.client().clone(),
db,
name: name.to_string(),
selection_criteria,
read_concern,
write_concern,
}),
_phantom: Default::default(),
}
}
pub fn clone_with_type<U: Send + Sync>(&self) -> Collection<U> {
Collection {
inner: self.inner.clone(),
_phantom: Default::default(),
}
}
pub(crate) fn clone_unconcerned(&self) -> Self {
let mut new_inner = CollectionInner::clone(&self.inner);
new_inner.write_concern = None;
new_inner.read_concern = None;
Self {
inner: Arc::new(new_inner),
_phantom: Default::default(),
}
}
pub fn client(&self) -> &Client {
&self.inner.client
}
pub fn name(&self) -> &str {
&self.inner.name
}
pub fn namespace(&self) -> Namespace {
Namespace {
db: self.inner.db.name().into(),
coll: self.name().into(),
}
}
pub fn selection_criteria(&self) -> Option<&SelectionCriteria> {
self.inner.selection_criteria.as_ref()
}
pub fn read_concern(&self) -> Option<&ReadConcern> {
self.inner.read_concern.as_ref()
}
pub fn write_concern(&self) -> Option<&WriteConcern> {
self.inner.write_concern.as_ref()
}
pub(super) async fn kill_cursor(
&self,
cursor_id: i64,
pinned_connection: Option<&PinnedConnectionHandle>,
drop_address: Option<ServerAddress>,
) -> Result<()> {
let ns = self.namespace();
let op = crate::operation::run_command::RunCommand::new(
ns.db,
doc! {
"killCursors": ns.coll.as_str(),
"cursors": [cursor_id]
},
drop_address.map(SelectionCriteria::from_address),
pinned_connection,
)?;
self.client().execute_operation(op, None).await?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Namespace {
pub db: String,
pub coll: String,
}
impl Namespace {
pub fn new(db: impl Into<String>, coll: impl Into<String>) -> Self {
Self {
db: db.into(),
coll: coll.into(),
}
}
pub(crate) fn from_str(s: &str) -> Option<Self> {
let mut parts = s.split('.');
let db = parts.next();
let coll = parts.collect::<Vec<_>>().join(".");
match (db, coll) {
(Some(db), coll) if !coll.is_empty() => Some(Self {
db: db.to_string(),
coll,
}),
_ => None,
}
}
}
impl fmt::Display for Namespace {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}.{}", self.db, self.coll)
}
}
impl<'de> Deserialize<'de> for Namespace {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
Self::from_str(&s)
.ok_or_else(|| D::Error::custom("Missing one or more fields in namespace"))
}
}
impl Serialize for Namespace {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&(self.db.clone() + "." + &self.coll))
}
}
impl FromStr for Namespace {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let mut parts = s.split('.');
let db = parts.next();
let coll = parts.collect::<Vec<_>>().join(".");
match (db, coll) {
(Some(db), coll) if !coll.is_empty() => Ok(Self {
db: db.to_string(),
coll,
}),
_ => Err(Self::Err::invalid_argument(
"Missing one or more fields in namespace",
)),
}
}
}