Sqlx lifetimes when the pool is generic member in a struct

I have a design where storage can use different backends. I'd like to fit sqlx in that, for which I'd need to have the connection object of sqlx be a member of a struct (which will implement the storage traits later). Even though I succeeded in doing a simple query, I'm having trouble with a query that I can parse to a result. Here's a minimal example:

Both my success and failure can be seen here (unfortunately playground doesn't have sqlx, so it won't compile in there, but it compiles otherwise)

You only need these two dependencies:

sqlx = { version = "0.7", features = [ "runtime-tokio", "macros", "sqlite", "postgres" ] }
tokio = { version = "1.30", features = ["full"] }

You will see in main() a minimal example (without parametrization) that works fine. But I can't seem to parametrize the struct to do the same thing.

Here's the error once you uncomment the code in there (that I'd like to get working):

error: implementation of `FromRow` is not general enough
  --> src/main.rs:50:28
   |
50 |         let rows: (i64,) = sqlx::query_as::<_, _>("SELECT COUNT(*) as count_pet FROM misc;")
   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FromRow` is not general enough
   |
   = note: `(i64,)` must implement `FromRow<'0, <D as sqlx::Database>::Row>`, for any lifetime `'0`...
   = note: ...but it actually implements `FromRow<'1, <D as sqlx::Database>::Row>`, for some specific lifetime `'1`

error: implementation of `FromRow` is not general enough
  --> src/main.rs:50:28
   |
50 |           let rows: (i64,) = sqlx::query_as::<_, _>("SELECT COUNT(*) as count_pet FROM misc;")
   |  ____________________________^
51 | |             .fetch_one(&self.db_pool)
   | |_____________________________________^ implementation of `FromRow` is not general enough
   |
   = note: `(i64,)` must implement `FromRow<'0, <D as sqlx::Database>::Row>`, for any lifetime `'0`...
   = note: ...but it actually implements `FromRow<'1, <D as sqlx::Database>::Row>`, for some specific lifetime `'1`

error: lifetime may not live long enough
  --> src/main.rs:50:28
   |
41 |     pub async fn is_initialized<'e, O>(&'e self) -> Result<bool, Error>
   |                                 -- lifetime `'e` defined here
...
50 |         let rows: (i64,) = sqlx::query_as::<_, _>("SELECT COUNT(*) as count_pet FROM misc;")
   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`

error: could not compile `sqlx_generics` (bin "sqlx_generics") due to 3 previous errors

What I don't understand is: Why does sqlx care about the lifetime of the raw &str I pass there... I tried all kinds of games but nothing works. I would really appreciate assistance in getting this to compile.

Also if you have hints on how to do better with sqlx I do welcome your suggestions. I feel like I'm trying hard, not smart.

That's not the problematic lifetime (it is 'static after all), 'e, the lifetime of the reference to self with the database pool is the problem. I've changed your where clause a little bit to make your bounds not dependent on the concrete lifetime of &self, but instead use HRTBs to express that these bounds should be applicable to any lifetime 'e and not the concrete lifetime of &self. Makes it compile on the Rustexplorer[1].


  1. Where you can import and use sqlx, but only till version 0.6. ↩ī¸Ž

2 Likes

This is awesome. Thank you very much! Even though I've been doing rust for years, I still have to learn more and more on how to do lifetimes properly. Cheers!

1 Like