@ELD Would it be simple to add support to mongodb via https://github.com/mongodb-labs/mongo-rust-driver-prototype and https://gitlab.com/petoknm/r2d2-mongodb?
@SergioBenitez So, spiking a bit on this this morning and remembering why we didn't ship with MongoDB was because the r2d2 driver didn't accept a URI. Instead, it required we parse out the URI and feed it in separately. I'm more than happy to revisit adding support for it, though. I assume they're still compatible with one another (the Rust MongoDB driver has a couple recent updates).
I can continue working on this, if we'd like to make this a priority for rocket_contrib.
@ELD Yes, we should add support for mongodb; it's at least as popular as the other databases we support.
Aside from parsing the connection URL itself (user:pass@host:port/db into user, host, db, etc) we can submit a PR to the r2d2 crate and add support for this kind of URL. My feeling is that submitting a PR is the better approach; this seems like something that crate should support anyway. Should they refuse, we can implement the parsing here.
@SergioBenitez Sounds good. I can cook up a PR for r2d2-mongodb to handle the parsing. I agree that it should be handled there since the original adapter has a method to accept a connection from a URI.
Worst case, yes, we can implement the parsing within rocket_contrib, but having it upstream would be better.
Use r2d2 and r2d2-mongodb. I am using it works fine, but it is a little slow.
pub struct Conn(pub PooledConnection<MongodbConnectionManager>);
/*
create a connection pool of mongodb connections to allow a lot of users to modify db at same time.
*/
pub fn init_pool() -> Pool<MongodbConnectionManager> {
dotenv().ok();
let mongo_addr = env::var("MONGO_ADDR").expect("MONGO_ADDR must be set");
let mongo_port = env::var("MONGO_PORT").expect("MONGO_PORT must be set");
let db_name = env::var("DB_NAME").expect("DB_NAME env var must be set");
let manager = MongodbConnectionManager::new(
ConnectionOptionsBuilder::new()
.with_host(&mongo_addr)
.with_port(mongo_port.parse::<u16>().unwrap())
.with_db(&db_name)
.build(),
);
match Pool::builder().max_size(64).build(manager) {
Ok(pool) => pool,
Err(e) => panic!("Error: failed to create mongodb pool {}", e),
}
}
/*
When Conn is dereferencd, return the mongo connection.
*/
impl Deref for Conn {
type Target = <r2d2_mongodb::MongodbConnectionManager as ManageConnection>::Connection;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/*
Create a implementation of FromRequest so Conn can be provided at every api endpoint
*/
impl<'a, 'r> FromRequest<'a, 'r> for Conn {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Conn, ()> {
let pool = request.guard::<State<Pool<MongodbConnectionManager>>>()?;
match pool.get() {
Ok(db) => Outcome::Success(Conn(db)),
Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())),
}
}
}
#[get("/hello")]
pub fn helloworld(
conn: Conn,
) -> Json<Value> {
let db = &conn; // need to deref to get a mongo connection
db.collections("hello").insert_one(doc!{ "name": "John" }, None).unwrap();
Json(json!({ "status": "ok"}))
}
fn main() {
// launch the app and mount all the api endpoints.
rocket::ignite()
.manage(init_pool())
.mount("/", routes![helloworld)
.launch();
}
I think this has been resolved now that #838 is merged.
Most helpful comment
Use r2d2 and r2d2-mongodb. I am using it works fine, but it is a little slow.