Rocket version: 0.4
I have a repository struct in my application for CRUD operations.
rust
struct UserRepo {
connection: PgConnection
}
I also had defined the following struct:
````rust
struct DBConn(PgConnection);
and then in `main()`
rust
rocket::ignite()
.attach(DBConn::fairing())
.mount("/", routes![home])
.launch();
````
I was then trying to implement FromRequest for struct UserRepo
``rust
let connection = request.guard::<DBConn>().unwrap().0;
Outcome::Success(UserRepo {
connection: connection,
})
````
But I'm getting this error:
````rust
note: expected typediesel::PgConnection
found typediesel::r2d2::PooledConnection
````
I looked at the docs here: https://api.rocket.rs/v0.4/rocket_contrib/databases/index.html
But I couldn't find anything about wrapping the field of struct annotated with #[database]
It kind of looks like it does: database.rs:80
The #[database] attribute does indeed wrap the type, specifically as an r2d2::PooledConnection<<ConnectionType as Poolable>::Manager> but that is really an implementation detail. The request guard type implements Deref<Target = ConnectionType> which works for many cases, but doesn't allow for ownership transfer like you are trying to do here.
One possibility is to have UserRepo lose the connection member and take &PgConnection instead of &self -- similarly to what the todo example does.
Another option might be to make DbConn the type used in UserRepo. DbConn implements a function from_pool(r2d2::Pool...), which allows for construction outside of Rocket but is undocumented.
Regardless of your specific needs or solutions, I do think the examples and docs could be somewhat improved in this area.
I was trying to completely abstract from the logic functions that we are actually using a database here.
I had defined a trait IUserRepo like this:
trait IUserRepo {
fn authenticate(username: &str, password: &str) -> Result<User, AuthError>;
}
And I was trying to implement FromRequest for Box<IUserRepo>
I thought this would help me write better tests. When testing I can provide a dummy implementation of IUserRepo
Folks at Diesel's gitter channel suggested me to do the following, and this is what I am currently doing:
struct UserRepo<C: Connection<Backend=Pg>> {
connection: C
}
I later found out a problem with this approach and also my original approach.
If a route needs instances of IUserRepo and say `IPostsRepo, then two connections are grabbed from the Pool.
My goal is to make the modules more modular and testable.
Can you think of any other way to restructure this code to achieve that?
My goal is to make the modules more modular and testable.
Can you think of any other way to restructure this code to achieve that?
Another option, seen in the todo example and some other projects, is to take a connection as an argument. This is pretty unlike your approach, though.
If you want to keep your one-trait-object-per-resource approach, I think something like this might help to reduce the number of "extra" connections:
impl FromRequest<'a, 'r> for &'a $repo {
type Error = ??;
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let database = request.local_cache(|| {
let connection = request.guard::<DBConn>().unwrap().0;
let b: Box<Database<Connection>> = Box::from(Database {
connection: connection,
});
b
});
// database is &Box<Database<Connection>>
&**database as Self
}
}
It doesn't type-check or error-handle, but that's approximately what you could use. This approach uses request-local state to create only one connection, and casts the reference as the specific type being asked for.
Thanks @jebrosen. Let me try that.