1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use self::options::*;
use crate::{
    bson::Document,
    coll::options::AggregateOptions,
    error::{Error, Result},
    operation::{CreateSearchIndexes, DropSearchIndex, UpdateSearchIndex},
    Collection,
    Cursor,
};

use bson::doc;
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;

impl<T> Collection<T> {
    /// Convenience method for creating a single search index.
    pub async fn create_search_index(
        &self,
        model: SearchIndexModel,
        options: impl Into<Option<CreateSearchIndexOptions>>,
    ) -> Result<String> {
        let mut names = self.create_search_indexes(Some(model), options).await?;
        match names.len() {
            1 => Ok(names.pop().unwrap()),
            n => Err(Error::internal(format!("expected 1 index name, got {}", n))),
        }
    }

    /// Creates multiple search indexes on the collection.
    pub async fn create_search_indexes(
        &self,
        models: impl IntoIterator<Item = SearchIndexModel>,
        _options: impl Into<Option<CreateSearchIndexOptions>>,
    ) -> Result<Vec<String>> {
        let op = CreateSearchIndexes::new(self.namespace(), models.into_iter().collect());
        self.client().execute_operation(op, None).await
    }

    /// Updates the search index with the given name to use the provided definition.
    pub async fn update_search_index(
        &self,
        name: impl AsRef<str>,
        definition: Document,
        _options: impl Into<Option<UpdateSearchIndexOptions>>,
    ) -> Result<()> {
        let op = UpdateSearchIndex::new(
            self.namespace(),
            name.as_ref().to_string(),
            definition.clone(),
        );
        self.client().execute_operation(op, None).await
    }

    /// Drops the search index with the given name.
    pub async fn drop_search_index(
        &self,
        name: impl AsRef<str>,
        _options: impl Into<Option<DropSearchIndexOptions>>,
    ) -> Result<()> {
        let op = DropSearchIndex::new(self.namespace(), name.as_ref().to_string());
        self.client().execute_operation(op, None).await
    }

    /// Gets index information for one or more search indexes in the collection.
    ///
    /// If name is not specified, information for all indexes on the specified collection will be
    /// returned.
    pub async fn list_search_indexes(
        &self,
        name: impl Into<Option<&str>>,
        aggregation_options: impl Into<Option<AggregateOptions>>,
        _list_index_options: impl Into<Option<ListSearchIndexOptions>>,
    ) -> Result<Cursor<Document>> {
        let mut inner = doc! {};
        if let Some(name) = name.into() {
            inner.insert("name", name.to_string());
        }
        self.clone_unconcerned()
            .aggregate(
                vec![doc! {
                    "$listSearchIndexes": inner,
                }],
                aggregation_options,
            )
            .await
    }
}

/// Specifies the options for a search index.
#[derive(Debug, Clone, Default, TypedBuilder, Serialize, Deserialize)]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct SearchIndexModel {
    /// The definition for this index.
    pub definition: Document,

    /// The name for this index, if present.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

pub mod options {
    #[cfg(docsrs)]
    use crate::Collection;
    use serde::Deserialize;
    use typed_builder::TypedBuilder;

    /// Options for [Collection::create_search_index].  Present to allow additional options to be
    /// added in the future as a non-breaking change.
    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
    #[builder(field_defaults(default, setter(into)))]
    #[non_exhaustive]
    pub struct CreateSearchIndexOptions {}

    /// Options for [Collection::update_search_index].  Present to allow additional options to be
    /// added in the future as a non-breaking change.
    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
    #[builder(field_defaults(default, setter(into)))]
    #[non_exhaustive]
    pub struct UpdateSearchIndexOptions {}

    /// Options for [Collection::list_search_indexes].  Present to allow additional options to be
    /// added in the future as a non-breaking change.
    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
    #[builder(field_defaults(default, setter(into)))]
    #[non_exhaustive]
    pub struct ListSearchIndexOptions {}

    /// Options for [Collection::drop_search_index].  Present to allow additional options to be
    /// added in the future as a non-breaking change.
    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
    #[builder(field_defaults(default, setter(into)))]
    #[non_exhaustive]
    pub struct DropSearchIndexOptions {}
}