use std::time::Duration;
use bson::serde_helpers;
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use serde_with::skip_serializing_none;
use typed_builder::TypedBuilder;
use crate::{
bson::{doc, Bson, Document},
bson_util,
concern::{ReadConcern, WriteConcern},
options::Collation,
selection_criteria::SelectionCriteria,
};
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[builder(field_defaults(default, setter(into)))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct CollectionOptions {
pub selection_criteria: Option<SelectionCriteria>,
pub read_concern: Option<ReadConcern>,
pub write_concern: Option<WriteConcern>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum ReturnDocument {
After,
Before,
}
impl<'de> Deserialize<'de> for ReturnDocument {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
match s.to_lowercase().as_str() {
"after" => Ok(ReturnDocument::After),
"before" => Ok(ReturnDocument::Before),
other => Err(D::Error::custom(format!(
"Unknown return document value: {}",
other
))),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[non_exhaustive]
pub enum Hint {
Keys(Document),
Name(String),
}
impl Hint {
pub(crate) fn to_bson(&self) -> Bson {
match self {
Hint::Keys(ref d) => Bson::Document(d.clone()),
Hint::Name(ref s) => Bson::String(s.clone()),
}
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum CursorType {
NonTailable,
Tailable,
TailableAwait,
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct InsertOneOptions {
pub bypass_document_validation: Option<bool>,
pub write_concern: Option<WriteConcern>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, TypedBuilder, Serialize, Deserialize)]
#[builder(field_defaults(default, setter(into)))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct InsertManyOptions {
pub bypass_document_validation: Option<bool>,
pub ordered: Option<bool>,
#[serde(skip_deserializing)]
pub write_concern: Option<WriteConcern>,
}
impl InsertManyOptions {
pub(crate) fn from_insert_one_options(options: InsertOneOptions) -> Self {
Self {
bypass_document_validation: options.bypass_document_validation,
ordered: None,
write_concern: options.write_concern,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[non_exhaustive]
pub enum UpdateModifications {
Document(Document),
Pipeline(Vec<Document>),
}
impl UpdateModifications {
pub(crate) fn to_bson(&self) -> Bson {
match self {
UpdateModifications::Document(ref d) => Bson::Document(d.clone()),
UpdateModifications::Pipeline(ref p) => {
Bson::Array(p.iter().map(|d| Bson::Document(d.clone())).collect())
}
}
}
}
impl From<Document> for UpdateModifications {
fn from(item: Document) -> Self {
UpdateModifications::Document(item)
}
}
impl From<Vec<Document>> for UpdateModifications {
fn from(item: Vec<Document>) -> Self {
UpdateModifications::Pipeline(item)
}
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct UpdateOptions {
pub array_filters: Option<Vec<Document>>,
pub bypass_document_validation: Option<bool>,
pub upsert: Option<bool>,
pub collation: Option<Collation>,
pub hint: Option<Hint>,
pub write_concern: Option<WriteConcern>,
}
impl UpdateOptions {
pub(crate) fn from_replace_options(options: ReplaceOptions) -> Self {
Self {
bypass_document_validation: options.bypass_document_validation,
upsert: options.upsert,
hint: options.hint,
write_concern: options.write_concern,
collation: options.collation,
..Default::default()
}
}
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct ReplaceOptions {
pub bypass_document_validation: Option<bool>,
pub upsert: Option<bool>,
pub collation: Option<Collation>,
pub hint: Option<Hint>,
pub write_concern: Option<WriteConcern>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder, Serialize)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct DeleteOptions {
pub collation: Option<Collation>,
pub write_concern: Option<WriteConcern>,
pub hint: Option<Hint>,
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct FindOneAndDeleteOptions {
pub max_time: Option<Duration>,
pub projection: Option<Document>,
pub sort: Option<Document>,
pub write_concern: Option<WriteConcern>,
pub collation: Option<Collation>,
pub hint: Option<Hint>,
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[builder(field_defaults(default, setter(into)))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct FindOneAndReplaceOptions {
pub bypass_document_validation: Option<bool>,
pub max_time: Option<Duration>,
pub projection: Option<Document>,
pub return_document: Option<ReturnDocument>,
pub sort: Option<Document>,
pub upsert: Option<bool>,
pub write_concern: Option<WriteConcern>,
pub collation: Option<Collation>,
pub hint: Option<Hint>,
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct FindOneAndUpdateOptions {
pub array_filters: Option<Vec<Document>>,
pub bypass_document_validation: Option<bool>,
pub max_time: Option<Duration>,
pub projection: Option<Document>,
pub return_document: Option<ReturnDocument>,
pub sort: Option<Document>,
pub upsert: Option<bool>,
pub write_concern: Option<WriteConcern>,
pub collation: Option<Collation>,
pub hint: Option<Hint>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder, Serialize)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct AggregateOptions {
pub allow_disk_use: Option<bool>,
#[serde(
serialize_with = "bson_util::serialize_u32_option_as_batch_size",
rename(serialize = "cursor")
)]
pub batch_size: Option<u32>,
pub bypass_document_validation: Option<bool>,
pub collation: Option<Collation>,
pub comment: Option<String>,
pub hint: Option<Hint>,
#[serde(
skip_serializing,
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis",
default
)]
pub max_await_time: Option<Duration>,
#[serde(
serialize_with = "bson_util::serialize_duration_option_as_int_millis",
rename = "maxTimeMS",
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis",
default
)]
pub max_time: Option<Duration>,
#[serde(skip_serializing)]
pub read_concern: Option<ReadConcern>,
#[serde(skip_serializing)]
#[serde(rename = "readPreference")]
pub selection_criteria: Option<SelectionCriteria>,
pub write_concern: Option<WriteConcern>,
#[serde(rename = "let")]
pub let_vars: Option<Document>,
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct CountOptions {
pub hint: Option<Hint>,
pub limit: Option<u64>,
#[serde(
default,
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis"
)]
pub max_time: Option<Duration>,
pub skip: Option<u64>,
pub collation: Option<Collation>,
pub selection_criteria: Option<SelectionCriteria>,
#[serde(skip_serializing)]
pub read_concern: Option<ReadConcern>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Default, Deserialize, TypedBuilder, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct EstimatedDocumentCountOptions {
#[serde(
default,
serialize_with = "bson_util::serialize_duration_option_as_int_millis",
rename = "maxTimeMS",
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis"
)]
pub max_time: Option<Duration>,
#[serde(skip_serializing)]
pub selection_criteria: Option<SelectionCriteria>,
#[serde(skip_serializing)]
pub read_concern: Option<ReadConcern>,
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Default, Deserialize, TypedBuilder, Serialize, Clone)]
#[builder(field_defaults(default, setter(into)))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct DistinctOptions {
#[serde(
default,
serialize_with = "bson_util::serialize_duration_option_as_int_millis",
rename = "maxTimeMS",
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis"
)]
pub max_time: Option<Duration>,
#[serde(skip_serializing)]
pub selection_criteria: Option<SelectionCriteria>,
#[serde(skip_serializing)]
pub read_concern: Option<ReadConcern>,
pub collation: Option<Collation>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder, Serialize)]
#[builder(field_defaults(default, setter(into)))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct FindOptions {
pub allow_disk_use: Option<bool>,
pub allow_partial_results: Option<bool>,
#[serde(serialize_with = "bson_util::serialize_u32_option_as_i32")]
pub batch_size: Option<u32>,
pub comment: Option<String>,
#[serde(skip)]
pub cursor_type: Option<CursorType>,
pub hint: Option<Hint>,
#[serde(serialize_with = "serialize_absolute_value")]
pub limit: Option<i64>,
pub max: Option<Document>,
#[serde(skip)]
pub max_await_time: Option<Duration>,
#[serde(serialize_with = "bson_util::serialize_u64_option_as_i64")]
pub max_scan: Option<u64>,
#[serde(
rename = "maxTimeMS",
serialize_with = "bson_util::serialize_duration_option_as_int_millis"
)]
pub max_time: Option<Duration>,
pub min: Option<Document>,
pub no_cursor_timeout: Option<bool>,
pub projection: Option<Document>,
#[serde(skip_serializing)]
pub read_concern: Option<ReadConcern>,
pub return_key: Option<bool>,
#[serde(skip)]
pub selection_criteria: Option<SelectionCriteria>,
pub show_record_id: Option<bool>,
#[serde(serialize_with = "bson_util::serialize_u64_option_as_i64")]
pub skip: Option<u64>,
pub sort: Option<Document>,
pub collation: Option<Collation>,
}
impl From<FindOneOptions> for FindOptions {
fn from(options: FindOneOptions) -> Self {
FindOptions {
allow_disk_use: None,
allow_partial_results: options.allow_partial_results,
collation: options.collation,
comment: options.comment,
hint: options.hint,
max: options.max,
max_scan: options.max_scan,
max_time: options.max_time,
min: options.min,
projection: options.projection,
read_concern: options.read_concern,
return_key: options.return_key,
selection_criteria: options.selection_criteria,
show_record_id: options.show_record_id,
skip: options.skip,
batch_size: None,
cursor_type: None,
limit: Some(-1),
max_await_time: None,
no_cursor_timeout: None,
sort: options.sort,
}
}
}
fn serialize_absolute_value<S>(
val: &Option<i64>,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match val {
Some(v) => serializer.serialize_i64(v.abs()),
None => serializer.serialize_none(),
}
}
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct FindOneOptions {
pub allow_partial_results: Option<bool>,
pub collation: Option<Collation>,
pub comment: Option<String>,
pub hint: Option<Hint>,
pub max: Option<Document>,
#[serde(serialize_with = "bson_util::serialize_u64_option_as_i64")]
pub max_scan: Option<u64>,
#[serde(deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis")]
pub max_time: Option<Duration>,
pub min: Option<Document>,
pub projection: Option<Document>,
#[serde(skip_serializing)]
pub read_concern: Option<ReadConcern>,
pub return_key: Option<bool>,
pub selection_criteria: Option<SelectionCriteria>,
pub show_record_id: Option<bool>,
#[serde(serialize_with = "bson_util::serialize_u64_option_as_i64")]
pub skip: Option<u64>,
pub sort: Option<Document>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, TypedBuilder, Serialize)]
#[builder(field_defaults(default, setter(into)))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[non_exhaustive]
pub struct CreateIndexOptions {
pub commit_quorum: Option<CommitQuorum>,
#[serde(
rename = "maxTimeMS",
default,
serialize_with = "bson_util::serialize_duration_option_as_int_millis",
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis"
)]
pub max_time: Option<Duration>,
pub write_concern: Option<WriteConcern>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder, Serialize)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct DropCollectionOptions {
pub write_concern: Option<WriteConcern>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct DropIndexOptions {
#[serde(
rename = "maxTimeMS",
default,
serialize_with = "bson_util::serialize_duration_option_as_int_millis",
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis"
)]
pub max_time: Option<Duration>,
pub write_concern: Option<WriteConcern>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct ListIndexesOptions {
#[serde(
rename = "maxTimeMS",
default,
serialize_with = "bson_util::serialize_duration_option_as_int_millis",
deserialize_with = "bson_util::deserialize_duration_option_from_u64_millis"
)]
pub max_time: Option<Duration>,
#[serde(default, skip_serializing)]
pub batch_size: Option<u32>,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum CommitQuorum {
Nodes(u32),
VotingMembers,
Majority,
Custom(String),
}
impl Serialize for CommitQuorum {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
CommitQuorum::Nodes(n) => serde_helpers::serialize_u32_as_i32(n, serializer),
CommitQuorum::VotingMembers => serializer.serialize_str("votingMembers"),
CommitQuorum::Majority => serializer.serialize_str("majority"),
CommitQuorum::Custom(s) => serializer.serialize_str(s),
}
}
}
impl<'de> Deserialize<'de> for CommitQuorum {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum IntOrString {
Int(u32),
String(String),
}
match IntOrString::deserialize(deserializer)? {
IntOrString::String(s) => {
if s == "votingMembers" {
Ok(CommitQuorum::VotingMembers)
} else if s == "majority" {
Ok(CommitQuorum::Majority)
} else {
Ok(CommitQuorum::Custom(s))
}
}
IntOrString::Int(i) => Ok(CommitQuorum::Nodes(i)),
}
}
}