Skip to content

RUST-273: Implement Create indexes #188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ md-5 = "0.8.0"
os_info = { version = "2.0.6", default-features = false }
percent-encoding = "2.0.0"
rand = "0.7.2"
serde_with = "1.3.1"
serde_with = "1.4"
sha-1 = "0.8.1"
sha2 = "0.8.0"
socket2 = "0.3.12"
Expand All @@ -47,6 +47,11 @@ typed-builder = "0.3.0"
version_check = "0.9.1"
webpki = "0.21.0"
webpki-roots = "0.18.0"
num-traits = "0.2.12"

[dependencies.either]
version = "1.6"
features = ["serde"]

[dependencies.async-std]
version = "1.6.2"
Expand Down
39 changes: 38 additions & 1 deletion src/coll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
operation::{
Aggregate,
Count,
CreateIndexes,
Delete,
Distinct,
DropCollection,
Expand All @@ -23,7 +24,7 @@ use crate::{
Insert,
Update,
},
results::{DeleteResult, InsertManyResult, InsertOneResult, UpdateResult},
results::{DeleteResult, InsertManyResult, InsertOneResult, UpdateResult, CreateIndexesResult},
selection_criteria::SelectionCriteria,
Client,
Cursor,
Expand Down Expand Up @@ -273,6 +274,42 @@ impl Collection {
})
}

/// Builds one or more indexes on a collection.
pub async fn create_indexes(
&self,
indexes: impl IntoIterator<Item = Index>,
options: impl Into<Option<CreateIndexesOptions>>,
) -> Result<CreateIndexesResult> {
let mut options = options.into();
resolve_options!(self, options, [write_concern]);
let indexes: Vec<Index> = indexes.into_iter().collect();

if indexes.is_empty() {
return Err(ErrorKind::ArgumentError {
message: "No indexes provided to create_indexes".to_string(),
}
.into());
}


let create_indexes = CreateIndexes::new(self.namespace(), indexes, options);
self.client().execute_operation(create_indexes).await
}

/// Builds one index on a collection.
// This is a wrapper of `create_indexes` because create only one index is likely to be the most use case
pub async fn create_index(
&self,
index: Index,
options: impl Into<Option<CreateIndexesOptions>>,
) -> Result<CreateIndexesResult> {
let mut options = options.into();
resolve_options!(self, options, [write_concern]);

let create_indexes = CreateIndexes::new(self.namespace(), vec![index], options);
self.client().execute_operation(create_indexes).await
}

/// Deletes all documents stored in the collection matching `query`.
pub async fn delete_many(
&self,
Expand Down
237 changes: 236 additions & 1 deletion src/coll/options.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::time::Duration;
use std::{
time::Duration,
collections::HashMap,
};

use serde::{Deserialize, Serialize, Serializer};
use serde_with::skip_serializing_none;
Expand All @@ -17,6 +20,8 @@ use crate::{
selection_criteria::SelectionCriteria,
};

use either::Either;

/// These are the valid options for creating a [`Collection`](../struct.Collection.html) with
/// [`Database::collection_with_options`](../struct.Database.html#method.collection_with_options).
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
Expand Down Expand Up @@ -877,6 +882,236 @@ pub struct FindOneOptions {
pub sort: Option<Document>,
}

/// Specifies indexes to create.
///
/// [See](https://docs.mongodb.com/manual/reference/command/createIndexes/) for more.
#[skip_serializing_none]
#[derive(Clone, Debug, Default, TypedBuilder, Serialize)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct CreateIndexesOptions {
/// The write concern for the operation.
#[builder(default)]
pub write_concern: Option<WriteConcern>,

/// Either integer or string
/// Optional. The minimum number of data-bearing voting replica set members
///
/// [See](https://docs.mongodb.com/manual/reference/command/createIndexes/#createindexes-cmd-commitquorum) for more.
#[serde(with = "either::serde_untagged_optional")]
#[builder(default)]
pub commit_quorum: Option<Either<String, i32>>,

/// Tags the query with an arbitrary string to help trace the operation through the database
/// profiler, currentOp and logs.
#[builder(default)]
pub comment: Option<Document>,
}

/// We must implement serialize on this
#[derive(Clone, Debug)]
pub enum IndexType {
Descending, // -1
Ascending, // 1
Hashed, // "hashed"
Sphere2d, // "2dsphere"
D2, // "2d"
#[deprecated]
GeoSpacial, // "geoHaystack"
Text, // "text"
}

impl Serialize for IndexType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer {
match self {
IndexType::Descending => serializer.serialize_i8(-1),
IndexType::Ascending => serializer.serialize_i8(1),
IndexType::Hashed => serializer.serialize_str("hashed"),
IndexType::Sphere2d => serializer.serialize_str("2dsphere"),
IndexType::D2 => serializer.serialize_str("2d"),
#[allow(deprecated)] IndexType::GeoSpacial => serializer.serialize_str("geoHaystack"),
IndexType::Text => serializer.serialize_str("text"),
}
}
}

/// Specifies the options to a [`Collection::create_index`](../struct.Collection.html#method.create_index)
/// operation.
/// See the
/// [documentation](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#options-for-all-index-types)
/// for more information on how to use this option.
#[skip_serializing_none]
#[derive(Debug, Default, TypedBuilder, Serialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct Index {
/// Specifies the index’s fields. For each field, specify a key-value pair in which the key is the name of the field to
/// index and the value is index type.
#[serde(rename = "key")]
pub keys: HashMap<String, IndexType>,

/// The name of the index.
pub name: String,

/// Optional. Deprecated in MongoDB 4.2.
#[deprecated]
#[builder(default)]
pub background: Option<bool>,

/// Optional. Creates a unique index so that the collection will not accept insertion or update of documents
/// where the index key value matches an existing value in the index.
///
/// Specify true to create a unique index. The default value is false.
///
/// The option is unavailable for [hashed](https://docs.mongodb.com/manual/core/index-hashed/) indexes.
#[builder(default)]
pub unique: Option<bool>,

/// Optional. If specified, the index only references documents that match the filter expression. See Partial Indexes for
/// more information.
///
/// See the [documentation](https://docs.mongodb.com/manual/core/index-partial/) for more
/// information on how to use this option.
#[builder(default)]
pub partial_filter_expression: Option<Document>,

/// Optional. If true, the index only references documents with the specified field.
///
/// These indexes use less space but behave differently in some situations (particularly sorts).
///
/// The default value is false.
///
/// See the [documentation](https://docs.mongodb.com/manual/core/index-sparse/)
/// for more information on how to use this option.
#[builder(default)]
pub sparse: Option<bool>,

/// Optional. Specifies a value, in seconds, as a TTL to control how long MongoDB retains documents in this collection.
///
/// See the [documentation](https://docs.mongodb.com/manual/tutorial/expire-data/)
/// for more information on how to use this option.
///
/// This applies only to [TTL](https://docs.mongodb.com/manual/reference/glossary/#term-ttl) indexes.
#[builder(default)]
#[serde(serialize_with = "serialize_u32_as_i32")]
pub expire_after_seconds: Option<u32>,

/// Optional. A flag that determines whether the index is hidden from the query planner. A hidden index is not evaluated as
/// part of the query plan selection.
///
/// Default is false.
///
/// See the
/// [documentation](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#method-createindex-hidden)
/// for more information on how to use this option.
#[builder(default)]
pub hidden: Option<bool>,

/// Optional. Allows users to configure the storage engine on a per-index basis when creating an index.
///
/// The storageEngine option should take the following form:
///
/// storageEngine: { <storage-engine-name>: <options> }
#[builder(default)]
pub storage_engine: Option<Document>,

/// Optional. Specifies the collation for the index.
///
/// [Collation](https://docs.mongodb.com/manual/reference/collation/) allows users to specify language-specific rules for
/// string comparison, such as rules for lettercase and accent marks.
#[builder(default)]
pub collation: Option<Collation>,

// text

/// Optional. For text indexes, a document that contains field and weight pairs.
///
/// The weight is an integer ranging from 1 to 99,999 and denotes the significance of the field relative to the other
/// indexed fields in terms of the score.
/// You can specify weights for some or all the indexed fields.
/// See [Control Search Results with Weights](https://docs.mongodb.com/manual/tutorial/control-results-of-text-search/)
/// to adjust the scores.
///
/// The default value is 1.
#[builder(default)]
pub weights: Option<Document>,

/// Optional. For text indexes, the language that determines the list of stop words and the rules for the stemmer and
/// tokenizer.
///
/// See [Text Search Languages](https://docs.mongodb.com/manual/reference/text-search-languages/#text-search-languages)
/// for the available languages and
/// [Specify a Language for Text Index](https://docs.mongodb.com/manual/tutorial/specify-language-for-text-index/) for
/// more information and examples.
///
/// The default value is english.
#[builder(default)]
pub default_language: Option<String>,

/// Optional. For text indexes, the name of the field, in the collection’s documents, that contains the override language
/// for the document. The default value is language. See
/// [Use any Field to Specify the Language for a Document](https://docs.mongodb.com/manual/tutorial/specify-language-for-text-index/#specify-language-field-text-index-example) for an example.
#[builder(default)]
pub language_override: Option<String>,

/// Optional. The text index version number. Users can use this option to override the default version number.
#[serde(serialize_with = "serialize_u32_as_i32")]
#[builder(default)]
pub text_index_version: Option<u32>,

// wildcard

/// Optional. Allows users to include or exclude specific field paths from a
/// [wildcard index](https://docs.mongodb.com/manual/core/index-wildcard/#wildcard-index-core)
/// using the { "$**" : 1} key pattern.
///
/// This is only used when you specific a wildcard index field
#[builder(default)]
pub wildcard_projection: Option<Document>,

// 2d

/// Optional. For 2d indexes, the number of precision of the stored geohash value of the location data.
/// The bits value ranges from 1 to 32 inclusive.
///
/// The default value is 26.
#[builder(default)]
#[serde(serialize_with = "serialize_u32_as_i32")]
pub bits: Option<u32>,

/// Optional. For 2d indexes, the lower inclusive boundary for the longitude and latitude values.
///
/// The default value is -180.0.
#[builder(default)]
pub min: Option<f64>,

/// Optional. For 2d indexes, the upper inclusive boundary for the longitude and latitude values.
///
/// The default value is -180.0.
#[builder(default)]
pub max: Option<f64>,

// 2dsphere

/// Optional. The 2dsphere index version number.
/// Users can use this option to override the default version number.
#[builder(default)]
#[serde(serialize_with = "serialize_u32_as_i32")]
#[serde(rename = "2dsphereIndexVersion")]
pub sphere2d_index_version: Option<u32>,

// GeoHayStack

/// For geoHaystack indexes, specify the number of units within which to group the location values;
/// i.e. group in the same bucket those location values that are within the specified number of units to each other.
///
/// The value must be greater than 0.
#[builder(default)]
bucket_size: Option<f64>,
}

/// Specifies the options to a [`Collection::drop`](../struct.Collection.html#method.drop)
/// operation.
#[derive(Debug, Default, TypedBuilder, Serialize)]
Expand Down
Loading