Merge pull request #13 from thijsc/documentation

Documentation
pull/15/head
Thijs Cadier 9 years ago
commit f6ea1ddb15

@ -10,9 +10,12 @@ Bson encoding and decoding is handled by the [bson crate](https://github.com/zon
The API should still be considered experimental, but I'm not expecting changes at the moment.
[Documentation](http://thijsc.github.io/mongo-rust-driver/mongo_driver/)
## Compatibility
The driver currently only builds on Unix, tested on Mac Os X and Linux so far.
The driver currently only builds on Unix, tested on Mac Os X and Linux so far. It's compatible with MongoDB 2.4 up to 3.2 and
has full replica set and SSL support.
## Logging

@ -1,196 +0,0 @@
use mongoc::bindings;
use bson::Document;
use super::BsoncError;
use super::bsonc::Bsonc;
use super::collection::Collection;
use super::Result;
pub struct BulkOperation<'a> {
_collection: &'a Collection<'a>,
inner: *mut bindings::mongoc_bulk_operation_t
}
impl<'a> BulkOperation<'a> {
pub fn new(
collection: &'a Collection<'a>,
inner: *mut bindings::mongoc_bulk_operation_t
) -> BulkOperation<'a> {
assert!(!inner.is_null());
BulkOperation {
_collection: collection,
inner: inner
}
}
/// Queue an insert of a single document into a bulk operation.
/// The insert is not performed until `execute` is called.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_insert.html
pub fn insert(
&self,
document: &Document
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_insert(
self.inner,
try!(Bsonc::from_document(&document)).inner()
)
}
Ok(())
}
/// Queue removal of al documents matching selector into a bulk operation.
/// The removal is not performed until `execute` is called.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_remove.html
pub fn remove(
&self,
selector: &Document
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_remove(
self.inner,
try!(Bsonc::from_document(&selector)).inner()
)
}
Ok(())
}
/// Queue removal of a single document into a bulk operation.
/// The removal is not performed until `execute` is called.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_remove_one.html
pub fn remove_one(
&self,
selector: &Document
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_remove_one(
self.inner,
try!(Bsonc::from_document(&selector)).inner()
)
}
Ok(())
}
/// Queue replacement of a single document into a bulk operation.
/// The replacement is not performed until `execute` is called.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_remove_one.html
pub fn replace_one(
&self,
selector: &Document,
document: &Document,
upsert: bool
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_replace_one(
self.inner,
try!(Bsonc::from_document(&selector)).inner(),
try!(Bsonc::from_document(&document)).inner(),
upsert as u8
)
}
Ok(())
}
/// Queue update of a single documents into a bulk operation.
/// The update is not performed until `execute` is called.
///
/// TODO: document must only contain fields whose key starts
/// with $, these is no error handling for this.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_update_one.html
pub fn update_one(
&self,
selector: &Document,
document: &Document,
upsert: bool
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_update_one(
self.inner,
try!(Bsonc::from_document(&selector)).inner(),
try!(Bsonc::from_document(&document)).inner(),
upsert as u8
)
}
Ok(())
}
/// Queue update of multiple documents into a bulk operation.
/// The update is not performed until `execute` is called.
///
/// TODO: document must only contain fields whose key starts
/// with $, these is no error handling for this.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_update_one.html
pub fn update(
&self,
selector: &Document,
document: &Document,
upsert: bool
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_update(
self.inner,
try!(Bsonc::from_document(&selector)).inner(),
try!(Bsonc::from_document(&document)).inner(),
upsert as u8
)
}
Ok(())
}
/// This function executes all operations queued into this bulk operation.
/// If ordered was set true, forward progress will be stopped upon the first error.
///
/// This function takes ownership because it is not possible to execute a bulk operation
/// multiple times.
///
/// Returns a document with an overview of the bulk operation if successfull.
///
/// See: http://api.mongodb.org/c/current/mongoc_bulk_operation_execute.html
pub fn execute(self) -> Result<Document> {
// Bsonc to store the reply
let mut reply = Bsonc::new();
// Empty error that might be filled
let mut error = BsoncError::empty();
// Execute the operation. This returns a non-zero hint of the peer node on
// success, otherwise 0 and error is set.
let return_value = unsafe {
bindings::mongoc_bulk_operation_execute(
self.inner,
reply.mut_inner(),
error.mut_inner()
)
};
if return_value != 0 {
match reply.as_document() {
Ok(document) => return Ok(document),
Err(error) => return Err(error.into())
}
} else {
Err(error.into())
}
}
}
impl<'a> Drop for BulkOperation<'a> {
fn drop(&mut self) {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_destroy(self.inner);
}
}
}

@ -1,5 +1,10 @@
//! Client to access a MongoDB node, replica set or sharded cluster.
//!
//! Get started by creating a `ClientPool` you can use to pop a `Client`.
use std::borrow::Cow;
use std::fmt;
use std::ffi::CString;
use std::ffi::{CStr,CString};
use std::path::PathBuf;
use std::mem;
use std::ptr;
@ -17,16 +22,16 @@ use super::collection;
use super::collection::Collection;
use super::database;
use super::database::Database;
use super::uri::Uri;
use super::read_prefs::ReadPrefs;
/// Client pool to a MongoDB cluster.
/// Pool that allows usage of clients out of a single pool from multiple threads.
///
/// This client pool cannot be cloned, but it can be shared between threads by using an `Arc`.
/// Use the pool to pop a client and do operations. The client will be automatically added
/// back to the pool when it goes out of scope.
///
/// See: http://api.mongodb.org/c/current/mongoc_client_pool_t.html
/// This client pool cannot be cloned, but it can be use from different threads by using an `Arc`.
/// Clients cannot be shared between threads, pop a client from the pool for very single thread
/// where you need a connection.
pub struct ClientPool {
// Uri and SslOptions need to be present for the lifetime of this pool otherwise the C driver
// loses access to resources it needs.
@ -36,10 +41,9 @@ pub struct ClientPool {
}
impl ClientPool {
/// Create a new ClientPool with optionally SSL options
///
/// See: http://api.mongodb.org/c/current/mongoc_client_pool_t.html
/// And: http://api.mongodb.org/c/current/mongoc_ssl_opt_t.html
/// Create a new ClientPool with that can provide clients pointing to the specified uri.
/// The pool will connect via SSL if you add `?ssl=true` to the uri. You can optionally pass
/// in SSL options to configure SSL certificate usage and so on.
pub fn new(uri: Uri, ssl_options: Option<SslOptions>) -> ClientPool {
super::init();
let pool = unsafe {
@ -65,13 +69,12 @@ impl ClientPool {
}
}
/// Get a reference to this pool's Uri
/// Get a reference to this pool's Uri.
pub fn get_uri(&self) -> &Uri {
&self.uri
}
/// Retrieve a client from the client pool, possibly blocking until one is available.
/// See: http://api.mongodb.org/c/current/mongoc_client_pool_pop.html
pub fn pop(&self) -> Client {
assert!(!self.inner.is_null());
let client = unsafe { bindings::mongoc_client_pool_pop(self.inner) };
@ -82,7 +85,6 @@ impl ClientPool {
}
/// Return a client back to the client pool, called from drop of client.
/// See: http://api.mongodb.org/c/current/mongoc_client_pool_push.html
unsafe fn push(&self, mongo_client: *mut bindings::mongoc_client_t) {
assert!(!self.inner.is_null());
assert!(!mongo_client.is_null());
@ -111,6 +113,7 @@ impl Drop for ClientPool {
}
}
/// Optional SSL configuration for a `ClientPool`.
pub struct SslOptions {
inner: bindings::mongoc_ssl_opt_t,
// We need to store everything so both memory sticks around
@ -129,6 +132,8 @@ pub struct SslOptions {
}
impl SslOptions {
/// Create a new ssl options instance that can be used to configured
/// a `ClientPool`.
pub fn new(
pem_file: Option<PathBuf>,
pem_password: Option<String>,
@ -219,6 +224,11 @@ impl Clone for SslOptions {
}
}
/// Client that provides access to a MongoDB MongoDB node, replica-set, or sharded-cluster.
///
/// It maintains management of underlying sockets and routing to individual nodes based on
/// `ReadPrefs` or `WriteConcern`. Clients cannot be shared between threads, pop a new one from
/// a `ClientPool` in every thread that needs a connection instead.
pub struct Client<'a> {
client_pool: &'a ClientPool,
inner: *mut bindings::mongoc_client_t
@ -273,9 +283,7 @@ impl<'a> Client<'a> {
)
}
/// Queries the server for the current server status.
///
/// See: http://api.mongodb.org/c/current/mongoc_client_get_server_status.html
/// Queries the server for the current server status, returns a document with this information.
pub fn get_server_status(&self, read_prefs: Option<ReadPrefs>) -> Result<Document> {
assert!(!self.inner.is_null());
@ -315,3 +323,81 @@ impl<'a> Drop for Client<'a> {
}
}
}
/// Abstraction on top of MongoDB connection URI format.
pub struct Uri {
inner: *mut bindings::mongoc_uri_t
}
impl Uri {
/// Parses a string containing a MongoDB style URI connection string.
///
/// Returns None if the uri is not in the correct format, there is no
/// further information available if this is not the case.
pub fn new<T: Into<Vec<u8>>>(uri_string: T) -> Option<Uri> {
let uri_cstring = CString::new(uri_string).unwrap();
let uri = unsafe { bindings::mongoc_uri_new(uri_cstring.as_ptr()) };
if uri.is_null() {
None
} else {
Some(Uri { inner: uri })
}
}
unsafe fn inner(&self) -> *const bindings::mongoc_uri_t {
assert!(!self.inner.is_null());
self.inner
}
pub fn as_str<'a>(&'a self) -> Cow<'a, str> {
assert!(!self.inner.is_null());
unsafe {
let cstr = CStr::from_ptr(
bindings::mongoc_uri_get_string(self.inner)
);
String::from_utf8_lossy(cstr.to_bytes())
}
}
pub fn get_database<'a>(&'a self) -> Option<Cow<'a, str>> {
assert!(!self.inner.is_null());
unsafe {
let ptr = bindings::mongoc_uri_get_database(self.inner);
if ptr.is_null() {
None
} else {
let cstr = CStr::from_ptr(ptr);
Some(String::from_utf8_lossy(cstr.to_bytes()))
}
}
}
// TODO add various methods that are available on uri
}
impl PartialEq for Uri {
fn eq(&self, other: &Uri) -> bool {
self.as_str() == other.as_str()
}
}
impl fmt::Debug for Uri {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Clone for Uri {
fn clone(&self) -> Uri {
Uri::new(self.as_str().into_owned()).unwrap()
}
}
impl Drop for Uri {
fn drop(&mut self) {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_uri_destroy(self.inner);
}
}
}

@ -1,3 +1,7 @@
//! Access to a MongoDB collection.
//!
//! `Collection` is the main type used when accessing collections.
use std::ptr;
use std::ffi::CStr;
use std::borrow::Cow;
@ -12,7 +16,6 @@ use super::Result;
use super::CommandAndFindOptions;
use super::{BsoncError,InvalidParamsError};
use super::bsonc::Bsonc;
use super::bulk_operation::BulkOperation;
use super::client::Client;
use super::cursor;
use super::cursor::{Cursor,TailingCursor};
@ -21,6 +24,7 @@ use super::flags::{Flags,FlagsValue,InsertFlag,QueryFlag,RemoveFlag,UpdateFlag};
use super::write_concern::WriteConcern;
use super::read_prefs::ReadPrefs;
#[doc(hidden)]
pub enum CreatedBy<'a> {
BorrowedClient(&'a Client<'a>),
OwnedClient(Client<'a>),
@ -28,32 +32,46 @@ pub enum CreatedBy<'a> {
OwnedDatabase(Database<'a>)
}
/// Provides access to a collection for most CRUD operations, I.e. insert, update, delete, find, etc.
///
/// A collection instance can be created by calling `get_collection` or `take_database` on a `Client` or `Database`
/// instance.
pub struct Collection<'a> {
_created_by: CreatedBy<'a>,
inner: *mut bindings::mongoc_collection_t
}
/// Options to configure a bulk operation.
pub struct BulkOperationOptions {
/// If the operations must be performed in order
pub ordered: bool,
/// `WriteConcern` to use
pub write_concern: WriteConcern
}
impl BulkOperationOptions {
/// Default options that are used if no options are specified
/// when creating a `BulkOperation`.
pub fn default() -> BulkOperationOptions {
BulkOperationOptions {
ordered: false,
write_concern: WriteConcern::new()
write_concern: WriteConcern::default()
}
}
}
/// Options to configure a find and modify operation.
pub struct FindAndModifyOptions {
/// Sort order for the query
pub sort: Option<Document>,
/// If the new version of the document should be returned
pub new: bool,
/// The fields to return
pub fields: Option<Document>
}
impl FindAndModifyOptions {
/// Default options used if none are provided.
pub fn default() -> FindAndModifyOptions {
FindAndModifyOptions {
sort: None,
@ -70,21 +88,32 @@ impl FindAndModifyOptions {
}
}
/// Possible find and modify operations.
pub enum FindAndModifyOperation<'a> {
/// Update the matching documents
Update(&'a Document),
/// Upsert the matching documents
Upsert(&'a Document),
/// Remove the matching documents
Remove
}
/// Options to configure a count operation.
pub struct CountOptions {
/// The query flags to use
pub query_flags: Flags<QueryFlag>,
/// Number of results to skip, zero to ignore
pub skip: u32,
/// Limit to the number of results, zero to ignore
pub limit: u32,
/// Optional extra keys to add to the count
pub opts: Option<Document>,
/// Read prefs to use
pub read_prefs: Option<ReadPrefs>
}
impl CountOptions {
/// Default options used if none are provided.
pub fn default() -> CountOptions {
CountOptions {
query_flags: Flags::new(),
@ -96,54 +125,70 @@ impl CountOptions {
}
}
/// Options to configure an insert operation.
pub struct InsertOptions {
/// Flags to use
pub insert_flags: Flags<InsertFlag>,
/// Write concern to use
pub write_concern: WriteConcern
}
impl InsertOptions {
/// Default options used if none are provided.
pub fn default() -> InsertOptions {
InsertOptions {
insert_flags: Flags::new(),
write_concern: WriteConcern::new()
write_concern: WriteConcern::default()
}
}
}
/// Options to configure a remove operation.
pub struct RemoveOptions {
/// Flags to use
pub remove_flags: Flags<RemoveFlag>,
/// Write concern to use
pub write_concern: WriteConcern
}
impl RemoveOptions {
/// Default options used if none are provided.
pub fn default() -> RemoveOptions {
RemoveOptions {
remove_flags: Flags::new(),
write_concern: WriteConcern::new()
write_concern: WriteConcern::default()
}
}
}
/// Options to configure an update operation.
pub struct UpdateOptions {
/// Flags to use
pub update_flags: Flags<UpdateFlag>,
/// Write concern to use
pub write_concern: WriteConcern
}
impl UpdateOptions {
/// Default options used if none are provided.
pub fn default() -> UpdateOptions {
UpdateOptions {
update_flags: Flags::new(),
write_concern: WriteConcern::new()
write_concern: WriteConcern::default()
}
}
}
/// Options to configure a tailing query.
pub struct TailOptions {
/// Duration to wait before checking for new results
pub wait_duration: Duration,
/// Maximum number of retries if there is an error
pub max_retries: u32
}
impl TailOptions {
/// Default options used if none are provided.
pub fn default() -> TailOptions {
TailOptions {
wait_duration: Duration::from_millis(500),
@ -153,6 +198,7 @@ impl TailOptions {
}
impl<'a> Collection<'a> {
#[doc(hidden)]
pub fn new(
created_by: CreatedBy<'a>,
inner: *mut bindings::mongoc_collection_t
@ -164,9 +210,8 @@ impl<'a> Collection<'a> {
}
}
/// Execute a command on the collection
///
/// See: http://api.mongodb.org/c/current/mongoc_collection_command.html
/// Execute a command on the collection.
/// This is performed lazily and therefore requires calling `next` on the resulting cursor.
pub fn command(
&'a self,
command: Document,
@ -208,19 +253,14 @@ impl<'a> Collection<'a> {
))
}
/// Simplified version of command that returns the first document
///
/// See: http://api.mongodb.org/c/current/mongoc_database_command_simple.html
/// Simplified version of `command` that returns the first document immediately.
pub fn command_simple(
&'a self,
command: Document,
options: Option<&CommandAndFindOptions>
read_prefs: Option<&ReadPrefs>
) -> Result<Document> {
assert!(!self.inner.is_null());
let default_options = CommandAndFindOptions::default();
let options = options.unwrap_or(&default_options);
// Bsonc to store the reply
let mut reply = Bsonc::new();
// Empty error that might be filled
@ -230,7 +270,7 @@ impl<'a> Collection<'a> {
bindings::mongoc_collection_command_simple(
self.inner,
try!(Bsonc::from_document(&command)).inner(),
match options.read_prefs {
match read_prefs {
Some(ref prefs) => prefs.inner(),
None => ptr::null()
},
@ -249,6 +289,10 @@ impl<'a> Collection<'a> {
}
}
/// Execute a count query on the underlying collection.
/// The `query` bson is not validated, simply passed along to the server. As such, compatibility and errors should be validated in the appropriate server documentation.
///
/// For more information, see the [query reference](https://docs.mongodb.org/manual/reference/operator/query/) at the MongoDB website.
pub fn count(
&self,
query: &Document,
@ -290,6 +334,9 @@ impl<'a> Collection<'a> {
}
}
/// Create a bulk operation. After creating call various functions such as `update`,
/// `insert` and others. When calling `execute` these operations will be executed in
/// batches.
pub fn create_bulk_operation(
&'a self,
options: Option<&BulkOperationOptions>
@ -310,6 +357,7 @@ impl<'a> Collection<'a> {
BulkOperation::new(self, inner)
}
/// Request that a collection be dropped, including all indexes associated with the collection.
pub fn drop(&mut self) -> Result<()> {
assert!(!self.inner.is_null());
let mut error = BsoncError::empty();
@ -326,6 +374,10 @@ impl<'a> Collection<'a> {
Ok(())
}
/// Execute a query on the underlying collection.
/// If no options are necessary, query can simply contain a query such as `{a:1}`.
/// If you would like to specify options such as a sort order, the query must be placed inside of `{"$query": {}}`
/// as specified by the server documentation. See the example below for how to properly specify additional options to query.
pub fn find(
&'a self,
query: &Document,
@ -367,10 +419,9 @@ impl<'a> Collection<'a> {
))
}
// Update and return an object.
//
// This is a thin wrapper around the findAndModify command. Pass in
// an operation that either updates, upserts or removes.
/// Update and return an object.
/// This is a thin wrapper around the findAndModify command. Pass in
/// an operation that either updates, upserts or removes.
pub fn find_and_modify(
&'a self,
query: &Document,
@ -443,6 +494,7 @@ impl<'a> Collection<'a> {
}
}
/// Get the name of the collection.
pub fn get_name(&self) -> Cow<str> {
let cstr = unsafe {
CStr::from_ptr(bindings::mongoc_collection_get_name(self.inner))
@ -450,6 +502,9 @@ impl<'a> Collection<'a> {
String::from_utf8_lossy(cstr.to_bytes())
}
/// Insert document into collection.
/// If no `_id` element is found in document, then an id will be generated locally and added to the document.
// TODO: You can retrieve a generated _id from mongoc_collection_get_last_error().
pub fn insert(
&'a self,
document: &Document,
@ -478,6 +533,9 @@ impl<'a> Collection<'a> {
}
}
/// Remove documents in the given collection that match selector.
/// The bson `selector` is not validated, simply passed along as appropriate to the server. As such, compatibility and errors should be validated in the appropriate server documentation.
/// If you want to limit deletes to a single document, add the `SingleRemove` flag.
pub fn remove(
&self,
selector: &Document,
@ -506,6 +564,8 @@ impl<'a> Collection<'a> {
}
}
/// Save a document into the collection. If the document has an `_id` field it will be updated.
/// Otherwise it will be inserted.
pub fn save(
&self,
document: &Document,
@ -513,7 +573,7 @@ impl<'a> Collection<'a> {
) -> Result<()> {
assert!(!self.inner.is_null());
let default_write_concern = WriteConcern::new();
let default_write_concern = WriteConcern::default();
let write_concern = write_concern.unwrap_or(&default_write_concern);
let mut error = BsoncError::empty();
@ -533,9 +593,8 @@ impl<'a> Collection<'a> {
}
}
/// This function shall update documents in collection that match selector.
///
/// See: http://api.mongodb.org/c/current/mongoc_collection_update.html
/// This function updates documents in collection that match selector.
/// By default, updates only a single document. Add `MultiUpdate` flag to update multiple documents.
pub fn update(
&self,
selector: &Document,
@ -607,3 +666,183 @@ impl<'a> Drop for Collection<'a> {
}
}
}
/// Provides an abstraction for submitting multiple write operations as a single batch.
///
/// Create a `BulkOperation` by calling `create_bulk_operation` on a `Collection`. After adding all of
/// the write operations using the functions on this struct, `execute` to execute the operation on
/// the server in batches. After executing the bulk operation is consumed and cannot be used anymore.
pub struct BulkOperation<'a> {
_collection: &'a Collection<'a>,
inner: *mut bindings::mongoc_bulk_operation_t
}
impl<'a>BulkOperation<'a> {
/// Create a new bulk operation, only for internal usage.
fn new(
collection: &'a Collection<'a>,
inner: *mut bindings::mongoc_bulk_operation_t
) -> BulkOperation<'a> {
assert!(!inner.is_null());
BulkOperation {
_collection: collection,
inner: inner
}
}
/// Queue an insert of a single document into a bulk operation.
/// The insert is not performed until `execute` is called.
pub fn insert(
&self,
document: &Document
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_insert(
self.inner,
try!(Bsonc::from_document(&document)).inner()
)
}
Ok(())
}
/// Queue removal of all documents matching the provided selector into a bulk operation.
/// The removal is not performed until `execute` is called.
pub fn remove(
&self,
selector: &Document
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_remove(
self.inner,
try!(Bsonc::from_document(&selector)).inner()
)
}
Ok(())
}
/// Queue removal of a single document into a bulk operation.
/// The removal is not performed until `execute` is called.
pub fn remove_one(
&self,
selector: &Document
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_remove_one(
self.inner,
try!(Bsonc::from_document(&selector)).inner()
)
}
Ok(())
}
/// Queue replacement of a single document into a bulk operation.
/// The replacement is not performed until `execute` is called.
pub fn replace_one(
&self,
selector: &Document,
document: &Document,
upsert: bool
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_replace_one(
self.inner,
try!(Bsonc::from_document(&selector)).inner(),
try!(Bsonc::from_document(&document)).inner(),
upsert as u8
)
}
Ok(())
}
/// Queue update of a single documents into a bulk operation.
/// The update is not performed until `execute` is called.
///
/// TODO: document must only contain fields whose key starts
/// with $, these is no error handling for this.
pub fn update_one(
&self,
selector: &Document,
document: &Document,
upsert: bool
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_update_one(
self.inner,
try!(Bsonc::from_document(&selector)).inner(),
try!(Bsonc::from_document(&document)).inner(),
upsert as u8
)
}
Ok(())
}
/// Queue update of multiple documents into a bulk operation.
/// The update is not performed until `execute` is called.
///
/// TODO: document must only contain fields whose key starts
/// with $, these is no error handling for this.
pub fn update(
&self,
selector: &Document,
document: &Document,
upsert: bool
) -> Result<()> {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_update(
self.inner,
try!(Bsonc::from_document(&selector)).inner(),
try!(Bsonc::from_document(&document)).inner(),
upsert as u8
)
}
Ok(())
}
/// This function executes all operations queued into this bulk operation.
/// If ordered was set true, forward progress will be stopped upon the first error.
///
/// This function takes ownership because it is not possible to execute a bulk operation
/// multiple times.
///
/// Returns a document with an overview of the bulk operation if successfull.
pub fn execute(self) -> Result<Document> {
// Bsonc to store the reply
let mut reply = Bsonc::new();
// Empty error that might be filled
let mut error = BsoncError::empty();
// Execute the operation. This returns a non-zero hint of the peer node on
// success, otherwise 0 and error is set.
let return_value = unsafe {
bindings::mongoc_bulk_operation_execute(
self.inner,
reply.mut_inner(),
error.mut_inner()
)
};
if return_value != 0 {
match reply.as_document() {
Ok(document) => return Ok(document),
Err(error) => return Err(error.into())
}
} else {
Err(error.into())
}
}
}
impl<'a> Drop for BulkOperation<'a> {
fn drop(&mut self) {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_bulk_operation_destroy(self.inner);
}
}
}

@ -1,3 +1,5 @@
//! Access to a MongoDB query cursor.
use std::iter::Iterator;
use std::ptr;
use std::thread;
@ -16,12 +18,22 @@ use super::CommandAndFindOptions;
use super::Result;
#[doc(hidden)]
pub enum CreatedBy<'a> {
Client(&'a Client<'a>),
Database(&'a Database<'a>),
Collection(&'a Collection<'a>)
}
/// Provides access to a MongoDB cursor for a normal operation.
///
/// It wraps up the wire protocol negotiation required to initiate a query and
/// retrieve an unknown number of documents. Cursors are lazy, meaning that no network
/// traffic occurs until the first call to `next`. At this point various functions to get
/// information about the state of the cursor are available.
///
/// `Cursor` implements the `Iterator` trait, so you can use with all normal Rust means
/// of iteration and looping.
pub struct Cursor<'a> {
_created_by: CreatedBy<'a>,
inner: *mut bindings::mongoc_cursor_t,
@ -33,6 +45,7 @@ pub struct Cursor<'a> {
}
impl<'a> Cursor<'a> {
#[doc(hidden)]
pub fn new(
created_by: CreatedBy<'a>,
inner: *mut bindings::mongoc_cursor_t,
@ -140,6 +153,10 @@ impl<'a> Drop for Cursor<'a> {
/// Cursor that will reconnect and resume tailing a collection
/// at the right point if the connection fails.
///
/// This cursor will wait for new results when there are none, so calling `next`
/// is a blocking operation. If an error occurs the iterator will retry, if errors
/// keep occuring it will eventually return an error result.
pub struct TailingCursor<'a> {
collection: &'a Collection<'a>,
query: Document,
@ -151,6 +168,7 @@ pub struct TailingCursor<'a> {
}
impl<'a> TailingCursor<'a> {
#[doc(hidden)]
pub fn new(
collection: &'a Collection<'a>,
query: Document,

@ -1,3 +1,5 @@
//! Access to a MongoDB database.
use std::ffi::{CString,CStr};
use std::borrow::Cow;
use std::ptr;
@ -14,19 +16,25 @@ use super::collection;
use super::collection::Collection;
use super::cursor;
use super::cursor::Cursor;
use super::read_prefs::ReadPrefs;
use flags::FlagsValue;
#[doc(hidden)]
pub enum CreatedBy<'a> {
BorrowedClient(&'a Client<'a>),
OwnedClient(Client<'a>)
}
/// Provides access to a MongoDB database.
///
/// A database instance can be created by calling `get_database` or `take_database` on a `Client` instance.
pub struct Database<'a> {
_created_by: CreatedBy<'a>,
inner: *mut bindings::mongoc_database_t
}
impl<'a> Database<'a> {
#[doc(ignore)]
pub fn new(
created_by: CreatedBy<'a>,
inner: *mut bindings::mongoc_database_t
@ -38,9 +46,8 @@ impl<'a> Database<'a> {
}
}
/// Execute a command on the database
///
/// See: http://api.mongodb.org/c/current/mongoc_database_command.html
/// Execute a command on the database.
/// This is performed lazily and therefore requires calling `next` on the resulting cursor.
pub fn command(
&'a self,
command: Document,
@ -82,19 +89,14 @@ impl<'a> Database<'a> {
))
}
/// Simplified version of command that returns the first document
///
/// See: http://api.mongodb.org/c/current/mongoc_database_command_simple.html
/// Simplified version of `command` that returns the first document immediately.
pub fn command_simple(
&'a self,
command: Document,
options: Option<&CommandAndFindOptions>
read_prefs: Option<&ReadPrefs>
) -> Result<Document> {
assert!(!self.inner.is_null());
let default_options = CommandAndFindOptions::default();
let options = options.unwrap_or(&default_options);
// Bsonc to store the reply
let mut reply = Bsonc::new();
// Empty error that might be filled
@ -104,7 +106,7 @@ impl<'a> Database<'a> {
bindings::mongoc_database_command_simple(
self.inner,
try!(Bsonc::from_document(&command)).inner(),
match options.read_prefs {
match read_prefs {
Some(ref prefs) => prefs.inner(),
None => ptr::null()
},
@ -123,6 +125,7 @@ impl<'a> Database<'a> {
}
}
/// Create a new collection in this database.
pub fn create_collection<S: Into<Vec<u8>>>(
&self,
name: S,
@ -179,6 +182,7 @@ impl<'a> Database<'a> {
)
}
/// Get the name of this database.
pub fn get_name(&self) -> Cow<str> {
let cstr = unsafe {
CStr::from_ptr(bindings::mongoc_database_get_name(self.inner))

@ -1,23 +1,29 @@
//! Flags to configure various MongoDB operations.
use mongoc::bindings;
use std::collections::BTreeSet;
/// Structure to hold flags for various flag types
pub struct Flags<T> {
flags: BTreeSet<T>
}
impl <T> Flags<T> where T: Ord {
/// Creare a new empty flags instance
pub fn new() -> Flags<T> {
Flags {
flags: BTreeSet::new()
}
}
/// Add a flag to this instance
pub fn add(&mut self, flag: T) {
self.flags.insert(flag);
}
}
/// To provide the combined value of all flags.
pub trait FlagsValue {
fn flags(&self) -> u32;
}

@ -1,3 +1,27 @@
//! This driver is a thin wrapper around the production-ready [Mongo C driver](https://github.com/mongodb/mongo-c-driver).
//!
//! It aims to provide a safe and ergonomic Rust interface which handles all the gnarly usage details of
//! the C driver for you. We use Rust's type system to make sure that we can only use the
//! underlying C driver in the recommended way specified in it's [documentation](http://api.mongodb.org/c/current/).
//!
//! To get started create a client pool wrapped in an `Arc` so we can share it between threads. Then pop a client from it
//! you can use to perform operations.
//!
//! # Example
//!
//! ```
//! use std::sync::Arc;
//! use mongo_driver::client::{ClientPool,Uri};
//!
//! let uri = Uri::new("mongodb://localhost:27017/").unwrap();
//! let pool = Arc::new(ClientPool::new(uri.clone(), None));
//! let client = pool.pop();
//! client.get_server_status(None).unwrap();
//! ```
//!
//! See the documentation for the available modules to find out how you can use the driver beyond
//! this.
extern crate libc;
extern crate mongoc_sys as mongoc;
@ -14,14 +38,12 @@ use std::sync::{Once,ONCE_INIT};
use mongoc::bindings;
pub mod bulk_operation;
pub mod client;
pub mod collection;
pub mod cursor;
pub mod database;
pub mod flags;
pub mod read_prefs;
pub mod uri;
pub mod write_concern;
mod bsonc;
@ -72,16 +94,24 @@ unsafe extern "C" fn mongoc_log_handler(
}
}
/// Options to configure both command and find operations.
pub struct CommandAndFindOptions {
/// Flags to use
pub query_flags: flags::Flags<flags::QueryFlag>,
/// Number of documents to skip, zero to ignore
pub skip: u32,
/// Max number of documents to return, zero to ignore
pub limit: u32,
/// Number of documents in each batch, zero to ignore (default is 100)
pub batch_size: u32,
/// Fields to return, not all commands support this option
pub fields: Option<bson::Document>,
/// Read prefs to use
pub read_prefs: Option<read_prefs::ReadPrefs>
}
impl CommandAndFindOptions {
/// Default options used if none are provided.
pub fn default() -> CommandAndFindOptions {
CommandAndFindOptions {
query_flags: flags::Flags::new(),

@ -1,10 +1,18 @@
//! Abstraction on top of the MongoDB connection read prefences.
use mongoc::bindings;
/// Describes how reads should be dispatched.
pub enum ReadMode {
/// Default mode. All operations read from the current replica set primary.
Primary,
/// All operations read from among the nearest secondary members of the replica set.
Secondary,
/// In most situations, operations read from the primary but if it is unavailable, operations read from secondary members.
PrimaryPreferred,
/// In most situations, operations read from among the nearest secondary members, but if no secondaries are available, operations read from the primary.
SecondaryPreferred,
/// Operations read from among the nearest members of the replica set, irrespective of the members type.
Nearest
}
@ -18,11 +26,16 @@ fn read_mode_value(read_mode: &ReadMode) -> bindings::mongoc_read_mode_t {
}
}
/// Provides an abstraction on top of the MongoDB connection read prefences.
///
/// It allows for hinting to the driver which nodes in a replica set should be accessed first.
/// Generally, it makes the most sense to stick with the global default, `Primary`. All of the other modes come with caveats that won't be covered in great detail here.
pub struct ReadPrefs {
inner: *mut bindings::mongoc_read_prefs_t
}
impl ReadPrefs {
/// Create a new empty read prefs.
pub fn new(read_mode: &ReadMode) -> ReadPrefs {
let read_mode_value = read_mode_value(read_mode);
let inner = unsafe { bindings::mongoc_read_prefs_new(read_mode_value) };
@ -30,15 +43,18 @@ impl ReadPrefs {
ReadPrefs { inner: inner }
}
/// Get a new instance of the default read pref.
pub fn default() -> ReadPrefs{
ReadPrefs::new(&ReadMode::Primary)
}
#[doc(hidden)]
pub fn inner(&self) -> *const bindings::mongoc_read_prefs_t {
assert!(!self.inner.is_null());
self.inner
}
#[doc(hidden)]
pub fn mut_inner(&self) -> *mut bindings::mongoc_read_prefs_t {
assert!(!self.inner.is_null());
self.inner as *mut bindings::mongoc_read_prefs_t

@ -1,87 +0,0 @@
use std::borrow::Cow;
use std::ffi::{CStr,CString};
use std::fmt;
use mongoc::bindings;
/// Abstraction on top of MongoDB connection URI format.
/// See: http://api.mongodb.org/c/current/mongoc_uri_t.html
pub struct Uri {
inner: *mut bindings::mongoc_uri_t
}
impl Uri {
/// Parses a string containing a MongoDB style URI connection string.
///
/// Returns None if the uri is not in the correct format, there is no
/// further information available if this is not the case.
///
/// See: http://api.mongodb.org/c/current/mongoc_uri_new.html
pub fn new<T: Into<Vec<u8>>>(uri_string: T) -> Option<Uri> {
let uri_cstring = CString::new(uri_string).unwrap();
let uri = unsafe { bindings::mongoc_uri_new(uri_cstring.as_ptr()) };
if uri.is_null() {
None
} else {
Some(Uri { inner: uri })
}
}
pub unsafe fn inner(&self) -> *const bindings::mongoc_uri_t {
assert!(!self.inner.is_null());
self.inner
}
pub fn as_str<'a>(&'a self) -> Cow<'a, str> {
assert!(!self.inner.is_null());
unsafe {
let cstr = CStr::from_ptr(
bindings::mongoc_uri_get_string(self.inner)
);
String::from_utf8_lossy(cstr.to_bytes())
}
}
pub fn get_database<'a>(&'a self) -> Option<Cow<'a, str>> {
assert!(!self.inner.is_null());
unsafe {
let ptr = bindings::mongoc_uri_get_database(self.inner);
if ptr.is_null() {
None
} else {
let cstr = CStr::from_ptr(ptr);
Some(String::from_utf8_lossy(cstr.to_bytes()))
}
}
}
// TODO add various methods that are available on uri
}
impl PartialEq for Uri {
fn eq(&self, other: &Uri) -> bool {
self.as_str() == other.as_str()
}
}
impl fmt::Debug for Uri {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Clone for Uri {
fn clone(&self) -> Uri {
Uri::new(self.as_str().into_owned()).unwrap()
}
}
impl Drop for Uri {
fn drop(&mut self) {
assert!(!self.inner.is_null());
unsafe {
bindings::mongoc_uri_destroy(self.inner);
}
}
}

@ -1,16 +1,44 @@
//! Abstraction on top of the MongoDB connection write concern.
use mongoc::bindings;
/// Possible write concern levels, only default is supported at the moment.
pub enum WriteConcernLevel {
/// By default, writes block awaiting acknowledgment from MongoDB. Acknowledged write concern allows clients to catch network, duplicate key, and other errors.
Default,
// We'd like to support the following write concerns too at some point, pull request welcome:
// With this write concern, MongoDB does not acknowledge the receipt of write operation. Unacknowledged is similar to errors ignored; however, mongoc attempts to receive and handle network errors when possible.
// WriteUnacknowledged,
// Block until a write has been propagated to a majority of the nodes in the replica set.
// Majority,
// Block until a write has been propagated to at least n nodes in the replica set.
// AtLeastNumberOfNodes(u32),
// Block until the node receiving the write has committed the journal.
// Journal
}
/// This tells the driver what level of acknowledgment to await from the server.
/// The default, `Default`, is right for the great majority of applications.
pub struct WriteConcern {
inner: *mut bindings::mongoc_write_concern_t
}
impl WriteConcern {
pub fn new() -> WriteConcern {
/// Get the default write concern
pub fn default() -> WriteConcern {
Self::new(WriteConcernLevel::Default)
}
/// Create a new write concern
pub fn new(_: WriteConcernLevel) -> WriteConcern {
let inner = unsafe { bindings::mongoc_write_concern_new() };
assert!(!inner.is_null());
WriteConcern { inner: inner }
}
#[doc(hidden)]
pub fn inner(&self) -> *const bindings::mongoc_write_concern_t {
assert!(!self.inner.is_null());
self.inner

@ -1,7 +1,6 @@
use chrono::*;
use mongo_driver::uri::Uri;
use mongo_driver::client::ClientPool;
use mongo_driver::client::{ClientPool,Uri};
use bson::oid::ObjectId;
use bson::spec::BinarySubtype;

@ -2,8 +2,7 @@ use std::env;
use bson;
use mongo_driver::uri::Uri;
use mongo_driver::client::ClientPool;
use mongo_driver::client::{ClientPool,Uri};
#[test]
fn test_execute_error() {

@ -3,8 +3,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use std::thread;
use mongo_driver::uri::Uri;
use mongo_driver::client::{ClientPool,SslOptions};
use mongo_driver::client::{ClientPool,SslOptions,Uri};
#[test]
fn test_new_pool_pop_client_and_borrow_collection() {

@ -2,8 +2,7 @@ use bson;
use mongo_driver::CommandAndFindOptions;
use mongo_driver::collection::{CountOptions,FindAndModifyOperation};
use mongo_driver::uri::Uri;
use mongo_driver::client::ClientPool;
use mongo_driver::client::{ClientPool,Uri};
use mongo_driver::flags;
#[test]

@ -4,8 +4,7 @@ use std::time::Duration;
use bson;
use mongo_driver::uri::Uri;
use mongo_driver::client::ClientPool;
use mongo_driver::client::{ClientPool,Uri};
use mongo_driver::Result;
#[test]

@ -1,5 +1,4 @@
use mongo_driver::uri::Uri;
use mongo_driver::client::ClientPool;
use mongo_driver::client::{ClientPool,Uri};
#[test]
fn test_command() {

@ -1,4 +1,4 @@
use mongo_driver::uri::Uri;
use mongo_driver::client::Uri;
#[test]
fn test_new_uri() {

@ -1,7 +1,7 @@
use mongo_driver::write_concern::WriteConcern;
#[test]
fn test_write_concern() {
let write_concern = WriteConcern::new();
fn test_default_write_concern() {
let write_concern = WriteConcern::default();
assert!(!write_concern.inner().is_null());
}

Loading…
Cancel
Save