Diesel Async Pagination Triggers Lifetime Error in async-graphql #[Object] Resolver

โš“ Rust    ๐Ÿ“… 2025-07-18    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 3      

surdeus

Hey all! Iโ€™m encountering a confusing lifetime issue in a project using diesel_async, a custom pagination trait, and async-graphql.

The error doesnโ€™t occur when I write the query inline, but does occur when I move the query into a build_query() function, even though I try to give it a 'static lifetime.

My custom pagination trait comes from this article: https://rymc.io/blog/2024/pagination-in-diesel-async/


:white_check_mark: What works (inline)

let (items, total) = users::table
    .left_join(...)
    .select(...)
    .paginate(page)
    .per_page(per_page)
    .load_and_count_pages::<MyModel>(&mut conn)
    .await?;

This works and compiles fine.


:cross_mark: What fails (via function)

fn build_query(...) -> IntoBoxed<'static, _, Pg> {
    users::table
        .left_join(...)
        .into_boxed()
}
let query = build_query(...);

let (items, total) = query
    .paginate(page)
    .per_page(per_page)
    .load_and_count_pages::<MyModel>(&mut conn)
    .await?;

This causes a lifetime error, but the error doesnโ€™t appear at the call site โ€” instead, it surfaces at the #[Object] macro from async-graphql:

error[E0477]: the type `Paginated<BoxedSelectStatement<'_, ...>>` does not fulfill the required lifetime
  --> src/http/handlers/my_handler.rs:23:1
   |
23 | #[Object]
   | ^^^^^^^^^

:magnifying_glass_tilted_left: What Iโ€™ve tried

  • Made all input arguments owned (no references)
  • Explicitly set the return type of build_query() to BoxedSelectStatement<'static, _, _, Pg, _>

:folded_hands: What Iโ€™d love help with

  1. Why does returning a boxed query from a function break .paginate().await in a #[Object] resolver?
  2. How can I structure the query builder so I can paginate it asynchronously inside #[Object]?
  3. Are there any best practices to avoid these lifetime traps when using Diesel + async + GraphQL?

Context

Rust version:

rustc 1.85.1 (4eb161250 2025-03-15)

Dependencies:

axum = { version = "0.8.1", features = ["multipart"] }
deadpool-diesel = { version = "0.6.1", features = ["postgres", "tracing"] }
diesel = { version = "2.2.8", features = ["chrono", "postgres", "serde_json"] }
diesel-async = { version = "0.5.2", features = ["deadpool", "postgres"] }
...

Any suggestions โ€” even hacky workarounds โ€” would be greatly appreciated! :folded_hands:
Sorry if this is a noob question โ€” Iโ€™m still new to Rust and still wrapping my head around lifetimes :sweat_smile:
I truly appreciate any pointers or explanations, even if they seem basic!

1 post - 1 participant

Read full topic

๐Ÿท๏ธ rust_feed