pub async fn sync_indexes<CollConf: CollectionConfig>(
    db: &Database,
) -> Result<(), mongodb::error::Error> {
    let mut indexes = CollConf::indexes();

    match h_run_command(db, doc! { "listIndexes": CollConf::collection_name() }).await {
        Ok(ret) => {
            let parsed_ret: ListIndexesRet = from_bson(Bson::Document(ret))
                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;

            if parsed_ret.cursor.id != 0 {
                // batch isn't complete
                return Err(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    format!(
                        "couldn't list all indexes from '{}'",
                        CollConf::collection_name()
                    ),
                )
                .into());
            }

            let mut existing_indexes = HashMap::new();
            for index in parsed_ret.cursor.first_batch {
                if let Some(key) = index.get("key") {
                    existing_indexes.insert(key.to_string(), index);
                }
            }

            let mut already_sync = Vec::new();
            let mut to_drop = Vec::new();
            for (i, index) in indexes.0.clone().into_iter().enumerate() {
                let index_doc = index.into_document();
                let key = index_doc.get("key").ok_or_else(|| {
                    std::io::Error::new(std::io::ErrorKind::Other, "index doc is missing 'key'")
                })?;
                if let Some(mut existing_index) = existing_indexes.remove(&key.to_string()) {
                    // "ns" and "v" in the response should not be used for the comparison
                    existing_index.remove("ns");
                    existing_index.remove("v");

                    if doc_are_eq(&index_doc, &existing_index) {
                        already_sync.push(i);
                    } else {
                        // An index with the same specification already exists, we need to drop it.
                        to_drop.push(
                            index_doc
                                .get_str("name")
                                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
                                .to_owned(),
                        );
                    }
                }
            }

            // Drop all remaining existing index expect "_id_" (for the "_id" key)
            // "_id" is special and cannot be deleted.
            // https://api.mongodb.com/wiki/current/Indexes.html#Indexes-The%5CidIndex
            for existing_index in existing_indexes.values() {
                let name = existing_index
                    .get_str("name")
                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
                    .to_owned();
                if name != "_id_" {
                    to_drop.push(name);
                }
            }

            if !to_drop.is_empty() {
                // Actually send the drop command
                // Dropping multiple indexes is available only starting MongoDB 4.2
                // If this fails, we fallback to a loop dropping all indexes individually
                // TODO: it would be better to select the method by checking mongo version, but db.version()
                // is not yet exposed by the driver.
                if h_run_command(
                    db,
                    doc! { "dropIndexes": CollConf::collection_name(), "index": &to_drop },
                )
                .await
                .is_err()
                {
                    for index_name in to_drop {
                        h_run_command(
                            db,
                            doc! { "dropIndexes": CollConf::collection_name(), "index": index_name },
                        )
                        .await?;
                    }
                }
            }

            // Ignore index already in sync
            for i in already_sync.into_iter().rev() {
                indexes.0.remove(i);
            }
        }
        Err(e) => {
            match e.kind.as_ref() {
                mongodb::error::ErrorKind::Command(err) if err.code == 26 => {
                    // Namespace doesn't exists yet as such no index is present either.
                }
                _ => return Err(e),
            }
        }
    }

    if !indexes.0.is_empty() {
        h_run_command(
            db,
            indexes.create_indexes_command(CollConf::collection_name()),
        )
        .await?;
    }

    Ok(())
}
/// Synchronize backend mongo collection for a given `CollectionConfig`.
///
/// This should be called once per `CollectionConfig` on startup to synchronize indexes.
/// Indexes found in the backend and not defined in the model are destroyed except for the special index "_id".
Synchronize backend mongo collection for a given `CollectionConfig`.
This should be called once per `CollectionConfig` on startup to synchronize indexes.
Indexes found in the backend and not defined in the model are destroyed except for the special index "_id".
Synchronize backend mongo collection for a given ` CollectionConfig ` . This should be called once per ` CollectionConfig ` on startup to synchronize indexes . Indexes found in the backend and not defined in the model are destroyed except for the special index " _id " .
pub async fn sync_indexes<CollConf: CollectionConfig>(
    db: &Database,
) -> Result<(), mongodb::error::Error> {
    let mut indexes = CollConf::indexes();
    match h_run_command(db, doc! { "listIndexes": CollConf::collection_name() }).await {
        Ok(ret) => {
            let parsed_ret: ListIndexesRet = from_bson(Bson::Document(ret))
                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
            if parsed_ret.cursor.id != 0 {
                // batch isn't complete
                return Err(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    format!(
                        "couldn't list all indexes from '{}'",
                        CollConf::collection_name()
                    ),
                )
                .into());
            }
            let mut existing_indexes = HashMap::new();
            for index in parsed_ret.cursor.first_batch {
                if let Some(key) = index.get("key") {
                    existing_indexes.insert(key.to_string(), index);
                }
            }
            let mut already_sync = Vec::new();
            let mut to_drop = Vec::new();
            for (i, index) in indexes.0.clone().into_iter().enumerate() {
                let index_doc = index.into_document();
                let key = index_doc.get("key").ok_or_else(|| {
                    std::io::Error::new(std::io::ErrorKind::Other, "index doc is missing 'key'")
                })?;
                if let Some(mut existing_index) = existing_indexes.remove(&key.to_string()) {
                    // "ns" and "v" in the response should not be used for the comparison
                    existing_index.remove("ns");
                    existing_index.remove("v");
                    if doc_are_eq(&index_doc, &existing_index) {
                        already_sync.push(i);
                    } else {
                        // An index with the same specification already exists, we need to drop it.
                        to_drop.push(
                            index_doc
                                .get_str("name")
                                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
                                .to_owned(),
                        );
                    }
                }
            }
            // Drop all remaining existing index expect "_id_" (for the "_id" key)
            // "_id" is special and cannot be deleted.
            // https://api.mongodb.com/wiki/current/Indexes.html#Indexes-The%5CidIndex
            for existing_index in existing_indexes.values() {
                let name = existing_index
                    .get_str("name")
                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
                    .to_owned();
                if name != "_id_" {
                    to_drop.push(name);
                }
            }
            if !to_drop.is_empty() {
                // Actually send the drop command
                // Dropping multiple indexes is available only starting MongoDB 4.2
                // If this fails, we fallback to a loop dropping all indexes individually
                // TODO: it would be better to select the method by checking mongo version, but db.version()
                // is not yet exposed by the driver.
                if h_run_command(
                    db,
                    doc! { "dropIndexes": CollConf::collection_name(), "index": &to_drop },
                )
                .await
                .is_err()
                {
                    for index_name in to_drop {
                        h_run_command(
                            db,
                            doc! { "dropIndexes": CollConf::collection_name(), "index": index_name },
                        )
                        .await?;
                    }
                }
            }
            // Ignore index already in sync
            for i in already_sync.into_iter().rev() {
                indexes.0.remove(i);
            }
        }
        Err(e) => {
            match e.kind.as_ref() {
                mongodb::error::ErrorKind::Command(err) if err.code == 26 => {
                    // Namespace doesn't exists yet as such no index is present either.
                }
                _ => return Err(e),
            }
        }
    }
    if !indexes.0.is_empty() {
        h_run_command(
            db,
            indexes.create_indexes_command(CollConf::collection_name()),
        )
        .await?;
    }
    Ok(())
}
pub async fn sync_indexes < CollConf : CollectionConfig > ( db : & Database , ) -> Result < ( ) , mongodb :: error :: Error > { let mut indexes = CollConf :: indexes ( ) ; match h_run_command ( db , doc ! { " " CollConf collection_name ( ) } ) . await { Ok ( ret ) => { let parsed_ret : ListIndexesRet = from_bson ( Bson :: Document ( ret ) ) . map_err ( | e | std :: io :: Error :: new ( std :: io :: ErrorKind :: Other , e ) ) ? ; if parsed_ret . cursor . id != 0 { // batch isn't complete return Err ( std :: io :: Error :: new ( std :: io :: ErrorKind :: Other , format ! ( " " CollConf collection_name ( ) ) , ) . into ( ) ) ; } let mut existing_indexes = HashMap :: new ( ) ; for index in parsed_ret . cursor . first_batch { if let Some ( key ) = index . get ( " " ) { existing_indexes . insert ( key . to_string ( ) , index ) ; } } let mut already_sync = Vec :: new ( ) ; let mut to_drop = Vec :: new ( ) ; for ( i , index ) in indexes . 0 . clone ( ) . into_iter ( ) . enumerate ( ) { let index_doc = index . into_document ( ) ; let key = index_doc . get ( " " ) . ok_or_else ( | | { std :: io :: Error :: new ( std :: io :: ErrorKind :: Other , " " ) } ) ? ; if let Some ( mut existing_index ) = existing_indexes . remove ( & key . to_string ( ) ) { // "ns" and "v" in the response should not be used for the comparison existing_index . remove ( " " ) ; existing_index . remove ( " " ) ; if doc_are_eq ( & index_doc , & existing_index ) { already_sync . push ( i ) ; } else { // An index with the same specification already exists, we need to drop it. to_drop . push ( index_doc . get_str ( " " ) . map_err ( | e | std :: io :: Error :: new ( std :: io :: ErrorKind :: Other , e ) ) ? . to_owned ( ) , ) ; } } } // Drop all remaining existing index expect "_id_" (for the "_id" key) // "_id" is special and cannot be deleted. // https://api.mongodb.com/wiki/current/Indexes.html#Indexes-The%5CidIndex for existing_index in existing_indexes . values ( ) { let name = existing_index . get_str ( " " ) . map_err ( | e | std :: io :: Error :: new ( std :: io :: ErrorKind :: Other , e ) ) ? . to_owned ( ) ; if name != " " { to_drop . push ( name ) ; } } if ! to_drop . is_empty ( ) { // Actually send the drop command // Dropping multiple indexes is available only starting MongoDB 4.2 // If this fails, we fallback to a loop dropping all indexes individually // TODO: it would be better to select the method by checking mongo version, but db.version() // is not yet exposed by the driver. if h_run_command ( db , doc ! { " " CollConf collection_name ( ) " " to_drop } , ) . await . is_err ( ) { for index_name in to_drop { h_run_command ( db , doc ! { " " CollConf collection_name ( ) " " index_name } , ) . await ? ; } } } // Ignore index already in sync for i in already_sync . into_iter ( ) . rev ( ) { indexes . 0 . remove ( i ) ; } } Err ( e ) => { match e . kind . as_ref ( ) { mongodb :: error :: ErrorKind :: Command ( err ) if err . code == 26 => { // Namespace doesn't exists yet as such no index is present either. } _ => return Err ( e ) , } } } if ! indexes . 0 . is_empty ( ) { h_run_command ( db , indexes . create_indexes_command ( CollConf :: collection_name ( ) ) , ) . await ? ; } Ok ( ( ) ) }
Synchronize backend mongo collection for a given `CollectionConfig`.
Synchronize backend mongo collection for a given ` CollectionConfig ` .
db
&Database