Replies: 1 comment 1 reply
-
The way I would do this is via an enum Database {
Postgres(MyPgDb),
MySqliteDb(MySqliteDb)
} You can then implement impl Fairing for Database {
#[rocket::async_trait]
fn info(&self) -> Info {
name: "Database Muxer",
kind: Kind::Ignite,
}
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
let rocket = match rocket.config().db_backend {
Backend::Sqlite => rocket.attach(Sqlite::fairing()),
Backend::Postgres => rocket.attach(Postgres::fairing()),
};
}
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Database {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
// We could store something in managed state in `on_ignite()` above
// that tells us which database we should be fetching to avoid calling
// `from_request()` for each type.
if let Success(db) = req.guard::<MyPgDb>().await {
return Success(Database::Postgres(db));
}
if let Success(db) = req.guard::<MySqliteDb>().await {
return Success(Database::Postgres(db));
}
Failure(todo!())
}
}
impl Sentinel for Database {
fn abort(rocket: &Rocket<Ignite>) -> bool {
MyPgDb::abort(rocket) && MySqliteDb::abort(rocket)
}
}
impl Database {
async fn run_migrations<P: Phase>(rocket: &Rocket<P>) -> _ {
if let Some(db) = MyPgDb::pool(rocket) {
todo!()
}
if let Some(db) = MySqliteDb::pool(rocket) {
todo!()
}
Err(todo!())
}
async fn count_cols(&self) -> _ {
match self {
Postgres(conn) => conn.run(...).await,
MySqliteDb(conn) => conn.run(...).await,
}
}
} Then you can just use it as normal: pub async fn status(
_api_version: &str,
db: Database
) -> Result<Json<StatusResponse>, Json<ApiError>> {
match db.count_cols().await {
Ok(n) => Ok(Json(StatusResponse {
status: "ok".to_string(),
num_entries: n
})),
Err(e) => Err(Json(ApiError::new(&e.to_string(), 0))),
}
} I hope this makes sense. |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I'm writing an app that supports both SQLite and Postgres. I had a question about how to handle the database fairings in a generic way. Today, I define two database structures:
At runtime, based on the config, I choose which fairing to attach and run migrations:
Then, I have a macro for each route implementation that I run for each backend:
Then, at runtime, I pass back the list of routes to mount (based on the config):
Is there a more straightforward or obvious way to do this? My solution feels clunky and non-idiomatic.
Thanks so much for your time!
Beta Was this translation helpful? Give feedback.
All reactions