From d2e0fbc109f0a12e5618ff83ed334543a81c8904 Mon Sep 17 00:00:00 2001 From: Thijs Cadier Date: Wed, 19 Aug 2015 21:59:30 +0200 Subject: [PATCH] Add command on collection and database --- src/collection.rs | 88 ++++++++++++++++++++++++++++++++--------------- src/cursor.rs | 13 ++++--- src/database.rs | 69 ++++++++++++++++++++++++++++++++++--- src/lib.rs | 22 ++++++++++++ 4 files changed, 156 insertions(+), 36 deletions(-) diff --git a/src/collection.rs b/src/collection.rs index f9b2d06..4f0983c 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -7,6 +7,7 @@ use mongo_c_driver_wrapper::bindings; use bson::{Bson,Document}; use super::Result; +use super::CommandAndFindOptions; use super::{BsoncError,InvalidParamsError}; use super::bsonc::Bsonc; use super::bulk_operation::BulkOperation; @@ -62,28 +63,6 @@ impl CountOptions { } } -pub struct FindOptions { - pub query_flags: Flags, - pub skip: u32, - pub limit: u32, - pub batch_size: u32, - pub fields: Option, - pub read_prefs: Option -} - -impl FindOptions { - pub fn default() -> FindOptions { - FindOptions { - query_flags: Flags::new(), - skip: 0, - limit: 0, - batch_size: 0, - fields: None, - read_prefs: None - } - } -} - pub struct InsertOptions { pub insert_flags: Flags, pub write_concern: WriteConcern @@ -138,6 +117,47 @@ impl<'a> Collection<'a> { } } + /// Execute a command on the collection + /// + /// See: http://api.mongodb.org/c/current/mongoc_collection_command.html + pub fn command( + &'a self, + command: Document, + options: Option<&CommandAndFindOptions> + ) -> Result> { + assert!(!self.inner.is_null()); + + let default_options = CommandAndFindOptions::default(); + let options = options.unwrap_or(&default_options); + + let inner = unsafe { + bindings::mongoc_collection_command( + self.inner, + options.query_flags.flags(), + options.skip, + options.limit, + options.batch_size, + try!(Bsonc::from_document(&command)).inner(), + match options.fields { + Some(ref f) => { + try!(Bsonc::from_document(f)).inner() + }, + None => ptr::null() + }, + match options.read_prefs { + Some(ref prefs) => prefs.inner(), + None => ptr::null() + } + ) + }; + + if inner.is_null() { + return Err(InvalidParamsError.into()) + } + + Ok(Cursor::new(cursor::CreatedBy::Collection(self), inner)) + } + pub fn count( &self, query: &Document, @@ -214,11 +234,11 @@ impl<'a> Collection<'a> { pub fn find( &'a self, query: &Document, - options: Option<&FindOptions> + options: Option<&CommandAndFindOptions> ) -> Result> { assert!(!self.inner.is_null()); - let default_options = FindOptions::default(); + let default_options = CommandAndFindOptions::default(); let options = options.unwrap_or(&default_options); let inner = unsafe { @@ -355,7 +375,7 @@ impl<'a> Collection<'a> { pub fn tail( &'a self, query: Document, - find_options: Option, + find_options: Option, tail_options: Option ) -> TailingCursor<'a> { let mut query_with_options = Document::new(); @@ -368,7 +388,7 @@ impl<'a> Collection<'a> { TailingCursor::new( self, query_with_options, - find_options.unwrap_or(FindOptions::default()), + find_options.unwrap_or(CommandAndFindOptions::default()), tail_options.unwrap_or(TailOptions::default()) ) } @@ -390,6 +410,20 @@ mod tests { use super::super::client::ClientPool; use super::super::flags; + #[test] + fn test_command() { + let uri = Uri::new("mongodb://localhost:27017/"); + let pool = ClientPool::new(uri); + let client = pool.pop(); + let collection = client.get_collection("rust_driver_test", "items"); + + let mut command = bson::Document::new(); + command.insert("ping".to_string(), bson::Bson::I32(1)); + + let result = collection.command(command, None).unwrap().next().unwrap().unwrap(); + assert!(result.contains_key("ok")); + } + #[test] fn test_mutation_and_finding() { let uri = Uri::new("mongodb://localhost:27017/"); @@ -454,7 +488,7 @@ mod tests { { let mut fields = bson::Document::new(); fields.insert("key_1".to_string(), bson::Bson::Boolean(true)); - let options = super::FindOptions { + let options = super::super::CommandAndFindOptions { query_flags: flags::Flags::new(), skip: 0, limit: 0, diff --git a/src/cursor.rs b/src/cursor.rs index 43bb06c..e80d0a3 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -8,14 +8,17 @@ use bson::{Bson,Document,oid}; use super::BsoncError; use super::bsonc; use super::client::Client; +use super::database::Database; use super::flags::QueryFlag; -use super::collection::{Collection,FindOptions,TailOptions}; +use super::collection::{Collection,TailOptions}; +use super::CommandAndFindOptions; use super::Result; pub enum CreatedBy<'a> { - Collection(&'a Collection<'a>), - Client(&'a Client<'a>) + Client(&'a Client<'a>), + Database(&'a Database<'a>), + Collection(&'a Collection<'a>) } pub struct Cursor<'a> { @@ -134,7 +137,7 @@ impl<'a> Drop for Cursor<'a> { pub struct TailingCursor<'a> { collection: &'a Collection<'a>, query: Document, - find_options: FindOptions, + find_options: CommandAndFindOptions, tail_options: TailOptions, cursor: Option>, last_seen_id: Option, @@ -145,7 +148,7 @@ impl<'a> TailingCursor<'a> { pub fn new( collection: &'a Collection<'a>, query: Document, - find_options: FindOptions, + find_options: CommandAndFindOptions, tail_options: TailOptions ) -> TailingCursor<'a> { // Add flags to make query tailable diff --git a/src/database.rs b/src/database.rs index a7e63f3..37ddf08 100644 --- a/src/database.rs +++ b/src/database.rs @@ -6,10 +6,15 @@ use mongo_c_driver_wrapper::bindings; use bson::Document; use super::Result; +use super::CommandAndFindOptions; +use super::{BsoncError,InvalidParamsError}; use super::bsonc::Bsonc; use super::client::Client; -use super::collection::{Collection,CreatedBy}; -use error::BsoncError; +use super::collection; +use super::collection::Collection; +use super::cursor; +use super::cursor::Cursor; +use flags::FlagsValue; pub struct Database<'a> { _client: &'a Client<'a>, @@ -28,6 +33,47 @@ impl<'a> Database<'a> { } } + /// Execute a command on the database + /// + /// See: http://api.mongodb.org/c/current/mongoc_database_command.html + pub fn command( + &'a self, + command: Document, + options: Option<&CommandAndFindOptions> + ) -> Result> { + assert!(!self.inner.is_null()); + + let default_options = CommandAndFindOptions::default(); + let options = options.unwrap_or(&default_options); + + let inner = unsafe { + bindings::mongoc_database_command( + self.inner, + options.query_flags.flags(), + options.skip, + options.limit, + options.batch_size, + try!(Bsonc::from_document(&command)).inner(), + match options.fields { + Some(ref f) => { + try!(Bsonc::from_document(f)).inner() + }, + None => ptr::null() + }, + match options.read_prefs { + Some(ref prefs) => prefs.inner(), + None => ptr::null() + } + ) + }; + + if inner.is_null() { + return Err(InvalidParamsError.into()) + } + + Ok(Cursor::new(cursor::CreatedBy::Database(self), inner)) + } + pub fn create_collection>>( &self, name: S, @@ -50,7 +96,7 @@ impl<'a> Database<'a> { }; if error.is_empty() { - Ok(Collection::new(CreatedBy::Database(self), coll)) + Ok(Collection::new(collection::CreatedBy::Database(self), coll)) } else { Err(error.into()) } @@ -65,7 +111,7 @@ impl<'a> Database<'a> { collection_cstring.as_ptr() ) }; - Collection::new(CreatedBy::Database(self), coll) + Collection::new(collection::CreatedBy::Database(self), coll) } pub fn get_name(&self) -> Cow { @@ -87,9 +133,24 @@ impl<'a> Drop for Database<'a> { #[cfg(test)] mod tests { + use bson; use super::super::uri::Uri; use super::super::client::ClientPool; + #[test] + fn test_command() { + let uri = Uri::new("mongodb://localhost:27017/"); + let pool = ClientPool::new(uri); + let client = pool.pop(); + let database = client.get_database("rust_test"); + + let mut command = bson::Document::new(); + command.insert("ping".to_string(), bson::Bson::I32(1)); + + let result = database.command(command, None).unwrap().next().unwrap().unwrap(); + assert!(result.contains_key("ok")); + } + #[test] fn test_get_collection_and_name() { let uri = Uri::new("mongodb://localhost:27017/"); diff --git a/src/lib.rs b/src/lib.rs index f5b1c1d..500a12e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,28 @@ fn init() { }); } +pub struct CommandAndFindOptions { + pub query_flags: flags::Flags, + pub skip: u32, + pub limit: u32, + pub batch_size: u32, + pub fields: Option, + pub read_prefs: Option +} + +impl CommandAndFindOptions { + pub fn default() -> CommandAndFindOptions { + CommandAndFindOptions { + query_flags: flags::Flags::new(), + skip: 0, + limit: 0, + batch_size: 0, + fields: None, + read_prefs: None + } + } +} + #[cfg(test)] mod tests { #[test]