diff --git a/src/client.rs b/src/client.rs index 3f2b682..c828b00 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,8 +3,9 @@ use std::ffi::CString; use mongo_c_driver_wrapper::bindings; +use super::collection::{Collection,CreatedBy}; +use super::database::Database; use super::uri::Uri; -use super::collection::Collection; // TODO: We're using a sort of poor man's Arc here // with this root bool, there must be a better way. @@ -91,18 +92,28 @@ pub struct Client<'a> { impl<'a> Client<'a> { pub fn get_collection>>(&'a self, db: S, collection: S) -> Collection<'a> { assert!(!self.inner.is_null()); - let mut coll; - unsafe { + let coll = unsafe { let db_cstring = CString::new(db).unwrap(); let collection_cstring = CString::new(collection).unwrap(); - - coll = bindings::mongoc_client_get_collection( + bindings::mongoc_client_get_collection( self.inner, db_cstring.as_ptr(), collection_cstring.as_ptr() - ); - } - Collection::new(self, coll) + ) + }; + Collection::new(CreatedBy::Client(self), coll) + } + + pub fn get_database>>(&'a self, db: S) -> Database<'a> { + assert!(!self.inner.is_null()); + let coll = unsafe { + let db_cstring = CString::new(db).unwrap(); + bindings::mongoc_client_get_database( + self.inner, + db_cstring.as_ptr() + ) + }; + Database::new(self, coll) } } @@ -128,13 +139,15 @@ mod tests { let uri = Uri::new("mongodb://localhost:27017/"); let pool = ClientPool::new(uri); - // Pop a client and insert a couple of times - for _ in 0..10 { - let client = pool.pop(); - pool.pop(); - let collection = client.get_collection("rust_test", "items"); - assert_eq!("items", collection.get_name().to_mut()); - } + // Pop a client and get a database and collection + let client = pool.pop(); + pool.pop(); + + let database = client.get_database("rust_test"); + assert_eq!("rust_test", database.get_name().to_mut()); + + let collection = client.get_collection("rust_test", "items"); + assert_eq!("items", collection.get_name().to_mut()); } #[test] diff --git a/src/collection.rs b/src/collection.rs index 66f75c8..de56b6a 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -12,12 +12,14 @@ use super::bsonc::Bsonc; use super::client::Client; use super::cursor; use super::cursor::Cursor; +use super::database::Database; use super::flags::{Flags,FlagsValue,InsertFlag,QueryFlag,RemoveFlag}; use super::write_concern::WriteConcern; use super::read_prefs::ReadPrefs; pub enum CreatedBy<'a> { - Client(&'a Client<'a>) + Client(&'a Client<'a>), + Database(&'a Database<'a>) } pub struct Collection<'a> { @@ -27,12 +29,12 @@ pub struct Collection<'a> { impl<'a> Collection<'a> { pub fn new( - client: &'a Client<'a>, - inner: *mut bindings::mongoc_collection_t + created_by: CreatedBy<'a>, + inner: *mut bindings::mongoc_collection_t ) -> Collection<'a> { assert!(!inner.is_null()); Collection { - _created_by: CreatedBy::Client(client), + _created_by: created_by, inner: inner } } diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..fbfa8df --- /dev/null +++ b/src/database.rs @@ -0,0 +1,123 @@ +use std::ffi::{CString,CStr}; +use std::borrow::Cow; +use std::ptr; + +use mongo_c_driver_wrapper::bindings; +use bson::Document; + +use super::Result; +use super::bsonc::Bsonc; +use super::client::Client; +use super::collection::{Collection,CreatedBy}; +use error::BsoncError; + +pub struct Database<'a> { + _client: &'a Client<'a>, + inner: *mut bindings::mongoc_database_t +} + +impl<'a> Database<'a> { + pub fn new( + client: &'a Client<'a>, + inner: *mut bindings::mongoc_database_t + ) -> Database<'a> { + assert!(!inner.is_null()); + Database { + _client: client, + inner: inner + } + } + + pub fn create_collection>>( + &self, + name: S, + options: Option<&Document> + ) -> Result { + assert!(!self.inner.is_null()); + + let mut error = BsoncError::empty(); + let name_cstring = CString::new(name).unwrap(); + let coll = unsafe { + bindings::mongoc_database_create_collection( + self.inner, + name_cstring.as_ptr(), + match options { + Some(o) => try!(Bsonc::from_document(o)).inner(), + None => ptr::null() + }, + error.mut_inner() + ) + }; + + if error.is_empty() { + Ok(Collection::new(CreatedBy::Database(self), coll)) + } else { + Err(error.into()) + } + } + + pub fn get_collection>>(&self, collection: S) -> Collection { + assert!(!self.inner.is_null()); + let coll = unsafe { + let collection_cstring = CString::new(collection).unwrap(); + bindings::mongoc_database_get_collection( + self.inner, + collection_cstring.as_ptr() + ) + }; + Collection::new(CreatedBy::Database(self), coll) + } + + pub fn get_name(&self) -> Cow { + let cstr = unsafe { + CStr::from_ptr(bindings::mongoc_database_get_name(self.inner)) + }; + String::from_utf8_lossy(cstr.to_bytes()) + } +} + +impl<'a> Drop for Database<'a> { + fn drop(&mut self) { + assert!(!self.inner.is_null()); + unsafe { + bindings::mongoc_database_destroy(self.inner); + } + } +} + +#[cfg(test)] +mod tests { + use bson; + use super::super::uri::Uri; + use super::super::client::ClientPool; + use super::super::flags::{Flags}; + + #[test] + fn test_get_collection_and_name() { + let uri = Uri::new("mongodb://localhost:27017/"); + let pool = ClientPool::new(uri); + let client = pool.pop(); + let database = client.get_database("rust_test"); + + assert_eq!("rust_test", database.get_name().to_mut()); + + let collection = database.get_collection("items"); + assert_eq!("items", collection.get_name().to_mut()); + } + + #[test] + fn test_create_collection() { + let uri = Uri::new("mongodb://localhost:27017/"); + let pool = ClientPool::new(uri); + let client = pool.pop(); + let database = client.get_database("rust_test"); + database.get_collection("created_collection").drop().unwrap_or(()); + + let collection = database.create_collection( + "created_collection", + None + ).unwrap(); + + assert_eq!("created_collection", collection.get_name().to_mut()); + } +} diff --git a/src/lib.rs b/src/lib.rs index e27fc28..1b5c172 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod bsonc; pub mod client; pub mod collection; pub mod cursor; +pub mod database; pub mod error; pub mod flags; pub mod read_prefs;