Trait wither::prelude::Model[][src]

pub trait Model where
    Self: Serialize + DeserializeOwned
{ const COLLECTION_NAME: &'static str; fn id(&self) -> Option<ObjectId>;
fn set_id(&mut self, id: ObjectId); fn read_concern() -> Option<ReadConcern> { ... }
fn write_concern() -> Option<WriteConcern> { ... }
fn selection_criteria() -> Option<SelectionCriteria> { ... }
fn collection(db: &Database) -> Collection { ... }
#[must_use] fn find<'life0, 'async_trait, F, O>(
        db: &'life0 Database,
        filter: F,
        options: O
    ) -> Pin<Box<dyn Future<Output = Result<ModelCursor<Self>>> + Send + 'async_trait>>
    where
        F: Into<Option<Document>> + Send,
        O: Into<Option<FindOptions>> + Send,
        F: 'async_trait,
        O: 'async_trait,
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn find_one<'life0, 'async_trait, F, O>(
        db: &'life0 Database,
        filter: F,
        options: O
    ) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>>
    where
        F: Into<Option<Document>> + Send,
        O: Into<Option<FindOneOptions>> + Send,
        F: 'async_trait,
        O: 'async_trait,
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn find_one_and_delete<'life0, 'async_trait, O>(
        db: &'life0 Database,
        filter: Document,
        options: O
    ) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>>
    where
        O: Into<Option<FindOneAndDeleteOptions>> + Send,
        O: 'async_trait,
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn find_one_and_replace<'life0, 'async_trait, O>(
        db: &'life0 Database,
        filter: Document,
        replacement: Document,
        options: O
    ) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>>
    where
        O: Into<Option<FindOneAndReplaceOptions>> + Send,
        O: 'async_trait,
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn find_one_and_update<'life0, 'async_trait, U, O>(
        db: &'life0 Database,
        filter: Document,
        update: U,
        options: O
    ) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>>
    where
        U: Into<UpdateModifications> + Send,
        O: Into<Option<FindOneAndUpdateOptions>> + Send,
        U: 'async_trait,
        O: 'async_trait,
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn save<'life0, 'life1, 'async_trait>(
        &'life0 mut self,
        db: &'life1 Database,
        filter: Option<Document>
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn update<'life0, 'async_trait>(
        self,
        db: &'life0 Database,
        filter: Option<Document>,
        update: Document,
        opts: Option<FindOneAndUpdateOptions>
    ) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn delete<'life0, 'life1, 'async_trait>(
        &'life0 self,
        db: &'life1 Database
    ) -> Pin<Box<dyn Future<Output = Result<DeleteResult>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        Self: Sync + 'async_trait
, { ... }
#[must_use] fn delete_many<'life0, 'async_trait, O>(
        db: &'life0 Database,
        filter: Document,
        options: O
    ) -> Pin<Box<dyn Future<Output = Result<DeleteResult>> + Send + 'async_trait>>
    where
        O: Into<Option<DeleteOptions>> + Send,
        O: 'async_trait,
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
fn instance_from_document(document: Document) -> Result<Self> { ... }
fn document_from_instance(&self) -> Result<Document> { ... }
fn indexes() -> Vec<IndexModel> { ... }
#[must_use] fn sync<'life0, 'async_trait>(
        db: &'life0 Database
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... }
#[must_use] fn get_current_indexes<'life0, 'async_trait>(
        db: &'life0 Database
    ) -> Pin<Box<dyn Future<Output = Result<HashMap<String, IndexModel>>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: Send + 'async_trait
, { ... } }

This trait provides data modeling behaviors for interacting with MongoDB database collections.

Wither models are a thin abstraction over a standard MongoDB collection. Typically, the value gained from using a model-based approach to working with your data will come about when reading from and writing to the model's collection. For everything else, simply call the collection method for direct access to the model's underlying collection handle.

Any read_concern, write_concern or selection_criteria options configured for the model, either derived or manually, will be used for collection interactions. Derive the Model trait on your data model structs.

All Model attributes are declared inside of model(...) attributes as such: #[model(<attrs>)].

derive

Deriving Model for your struct is straightforward.

  • Ensure that your struct has at least the following derivations: #[derive(Model, Serialize, Deserialize)].
  • Ensure that you have a field named id, of type Option<ObjectId>, with at least the following serde attributes: #[serde(rename="_id", skip_serializing_if="Option::is_none")].

For now, it seems logical to disallow customization of the PK. An argument could be made for allowing full customization of the PK for a MongoDB collection, but there really is no end-all reasoning for this argument which I am aware of. If you need to treat a different field as PK, then just add the needed index to the field, and you are good to go. More on indexing soon.

If you need to implement Serialize and/or Deserialize manually, add the #[model(skip_serde_checks)] struct attribute, then you may remove the respective derivations mentioned above. If you are handling the id field manually as well, then you may remove the rename & skip_serializing_if attributes as well. However, take care to ensure that you are replicating the serde behavior of these two attributes, else you may run into strange behavior.

all available model attributes

All attributes available for use when deriving a model are described below:

  • collection_name="...": this allows you to specify your model name explicitly. By default, your model's name will be pluralized, and then formatted as a standard table name (with underscores, EG OrgPermission becomes org_permissions).
  • skip_serde_checks: including this attribute will disable any checks which are normally performed to ensure that serde is setup properly on your model. If you disable serde checks, you're on your own :).
  • read_concern: include this attribute to define the read-concern which is to be used when reading data from the model's collection.
  • write_concern: include this attribute to define the write-concern which is to be used when writing data to the model's collection.
  • selection_criteria: include this attribute to define the server selection algorithm to use when interacting with the database.
  • index: include one or more of these attributes to define the set of indexes which should build on the model's collection. PLEASE NOTE: as of 0.9.0-alpha.0 index management has been temporarily disabled due to limitations in the underlying driver. We are hoping to get this functionality back soon.

read concern

To derive this attribute, specify one of the canonical values for read_concern recognized by MongoDB. #[model(read_concern="linearizable")] will configure the linearizable read concern.

For custom configuration, use this pattern: #[model(read_concern(custom="custom-concern"))]. The value of custom must be a string literal.

write_concern

To derive this attribute, specify the write concern options which you would like to configure as so: #[model(write_concern(w="majority", w_timeout=10, journal=true))]. Any combination of these options is allow, as long as options are not repeated and as long as one option is specified.

For custom configuration, use this pattern: #[model(write_concern(w(custom="custom")))].

selection_criteria

To configure a selection criteria, we had to use a slightly more roundabout approach: #[model(selection_criteria="MyModel::get_selection_criteria")]. Here, the value of selection_criteria must be a valid Rust path to a function which will return your desired selection criteria.

This pattern is used to address some of the complexities with deriving all possible values which may be specified for selection criteria. If this pattern does not work for your use case, please open an issue and let us know.

indexing

Index derivations have been GREATLY simplified, and future-proofed, as of wither@0.9.0. Now, all indexes are specified using the following pattern.

#[model(
    index(keys=r#"doc!{"id": 1}"#),
    index(keys=r#"doc!{"id": -1}"#, options=r#"doc!{"unique": true}"#),
    index(keys=r#"doc!{"some.nested.field": 1}"#),
)]
struct MyModel {

This pattern is impervious to any future changes made to the keys and options documents expected by MongoDB. All values must be quoted, may use r# strings (specify any number of # symbols after the r, followed by "..." and a matching number of # symbols following the closing quote), and are expected to be bson::doc! invocations, providing the compile time BSON validation we all love.

I am personally quite happy with this approach. It is just another example of the core philosophy behind Wither: provide maximum convenience, but don't get in the way.

sync

Model::sync will synchronize your model's indexes with the database. It is an integral component of this system & allows you to delegate a majority of your database administration tasks to your services which are actually using the database.

This routine should be called once per model, early on at boot-time. This routine will destroy any indexes found on this model's collection which are not defined on this model (barring the default index on _id).

logging

This crate uses the rust standard logging facade, and integrating it with any other logging/tracing framework based on the standard logging facade should be seamless. Getting started with with env_logger, tracing or other similar frameworks is usually quite simple.

underlying driver

If at any point in time you need direct access to the underlying driver, it is always available. All of the Model interface methods take a handle to the database, which is part of the underlying driver. You can use the Model::collection to directly access the model's collection, while still using the model's configured read concern, write concern and selection criteria. You can also use the various model convenience methods for serialization, such as the Model::instance_from_document method.

Associated Constants

const COLLECTION_NAME: &'static str[src]

The name of the collection where this model's data is stored.

Loading content...

Required methods

fn id(&self) -> Option<ObjectId>[src]

Get the ID for this model instance.

fn set_id(&mut self, id: ObjectId)[src]

Set the ID for this model.

Loading content...

Provided methods

fn read_concern() -> Option<ReadConcern>[src]

The model's read concern.

fn write_concern() -> Option<WriteConcern>[src]

The model's write concern.

fn selection_criteria() -> Option<SelectionCriteria>[src]

The model's selection criteria.

When deriving a model, a function or an associated function should be specified which should be used to produce the desired value.

fn collection(db: &Database) -> Collection[src]

Get a handle to this model's collection.

If there are any methods available on the underlying driver's collection object which are not available on the model interface, this is how you should access them. Typically, only methods which would be modified to deal with a model instance are actually wrapped by the model interface. Everything else should be accessed via this collection method.

This method uses the model's selection_criteria, read_concern & write_concern when constructing the collection handle.

#[must_use]fn find<'life0, 'async_trait, F, O>(
    db: &'life0 Database,
    filter: F,
    options: O
) -> Pin<Box<dyn Future<Output = Result<ModelCursor<Self>>> + Send + 'async_trait>> where
    F: Into<Option<Document>> + Send,
    O: Into<Option<FindOptions>> + Send,
    F: 'async_trait,
    O: 'async_trait,
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Find all instances of this model matching the given query.

#[must_use]fn find_one<'life0, 'async_trait, F, O>(
    db: &'life0 Database,
    filter: F,
    options: O
) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>> where
    F: Into<Option<Document>> + Send,
    O: Into<Option<FindOneOptions>> + Send,
    F: 'async_trait,
    O: 'async_trait,
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Find the one model record matching your query, returning a model instance.

#[must_use]fn find_one_and_delete<'life0, 'async_trait, O>(
    db: &'life0 Database,
    filter: Document,
    options: O
) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>> where
    O: Into<Option<FindOneAndDeleteOptions>> + Send,
    O: 'async_trait,
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Finds a single document and deletes it, returning the original.

#[must_use]fn find_one_and_replace<'life0, 'async_trait, O>(
    db: &'life0 Database,
    filter: Document,
    replacement: Document,
    options: O
) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>> where
    O: Into<Option<FindOneAndReplaceOptions>> + Send,
    O: 'async_trait,
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Finds a single document and replaces it, returning either the original or replaced document.

#[must_use]fn find_one_and_update<'life0, 'async_trait, U, O>(
    db: &'life0 Database,
    filter: Document,
    update: U,
    options: O
) -> Pin<Box<dyn Future<Output = Result<Option<Self>>> + Send + 'async_trait>> where
    U: Into<UpdateModifications> + Send,
    O: Into<Option<FindOneAndUpdateOptions>> + Send,
    U: 'async_trait,
    O: 'async_trait,
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Finds a single document and updates it, returning either the original or updated document.

#[must_use]fn save<'life0, 'life1, 'async_trait>(
    &'life0 mut self,
    db: &'life1 Database,
    filter: Option<Document>
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Save the current model instance.

In order to make this method as flexible as possible, its behavior varies a little based on the input and the state of the instance.

When the instance already has an ID, this method will operate purely based on the instance ID. If no ID is present, and no filter has been specified, then an ID will be generated.

If a filter is specified, and no ID exists for the instance, then the filter will be used and the first document matching the filter will be replaced by this instance. This is useful when the model has unique indexes on fields which need to be the target of the save operation.

NOTE WELL: in order to ensure needed behavior of this method, it will force journaled write concern.

#[must_use]fn update<'life0, 'async_trait>(
    self,
    db: &'life0 Database,
    filter: Option<Document>,
    update: Document,
    opts: Option<FindOneAndUpdateOptions>
) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Update the current model instance.

This operation will always target the model instance by the instance's ID. If its ID is None, this method will return an error. If a filter document is provided, this method will ensure that the key _id is set to this model's ID.

This method will consume self, and will return a new instance of Self based on the given return options (ReturnDocument::Before | ReturnDocument:: After).

In order to provide consistent behavior, this method will also ensure that the operation's write concern journaling is set to true, so that we can receive a complete output document.

If this model instance was never written to the database, this operation will return an error.

#[must_use]fn delete<'life0, 'life1, 'async_trait>(
    &'life0 self,
    db: &'life1 Database
) -> Pin<Box<dyn Future<Output = Result<DeleteResult>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: Sync + 'async_trait, 
[src]

Delete this model instance by ID.

Wraps the driver's Collection.delete_one method.

#[must_use]fn delete_many<'life0, 'async_trait, O>(
    db: &'life0 Database,
    filter: Document,
    options: O
) -> Pin<Box<dyn Future<Output = Result<DeleteResult>> + Send + 'async_trait>> where
    O: Into<Option<DeleteOptions>> + Send,
    O: 'async_trait,
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Deletes all documents stored in the collection matching filter.

Wraps the driver's Collection.delete_many method.

fn instance_from_document(document: Document) -> Result<Self>[src]

Attempt to serialize the given bson document into an instance of this model.

fn document_from_instance(&self) -> Result<Document>[src]

Attempt to serialize an instance of this model into a bson document.

fn indexes() -> Vec<IndexModel>[src]

Get the vector of index models for this model.

#[must_use]fn sync<'life0, 'async_trait>(
    db: &'life0 Database
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Synchronize this model with the backend.

This routine should be called once per model, early on at boottime. It will synchronize any indexes defined on this model with the backend.

This routine will destroy any indexes found on this model's collection which are not defined in this model's indexes method.

#[must_use]fn get_current_indexes<'life0, 'async_trait>(
    db: &'life0 Database
) -> Pin<Box<dyn Future<Output = Result<HashMap<String, IndexModel>>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: Send + 'async_trait, 
[src]

Get current collection indexes, if any.

Loading content...

Implementors

Loading content...