Ross Rogers
Ross Rogers

Reputation: 24240

Can calling `get_results` on `sql_query` deserialize into a a nested struct?

I unfortunately must use sql_query(). However, I'm wondering if there is a way to serialize the database results into a nested struct. I'd like to avoid creating a flattened data type to receive the results from the data and instead use the data struct with nested struct definitions, similar to deserializing json with #[serde(flatten)]

I've attempted this with the following code:

use diesel::*;
use serde::Deserialize;
use diesel::r2d2::{ConnectionManager, PooledConnection};
type DB = diesel::pg::Pg;
type DbConn = PooledConnection<ConnectionManager<PgConnection>>;

diesel::table! {
    foo (id) {
        id -> Int4,
    }
}

diesel::table! {
    bar (id) {
        id -> Int4,
        foo_id -> Int4,
    }
}
              
#[derive(Deserialize, Queryable)]
#[diesel(table_name=foo)]
pub struct Foo {
    pub id: i32,
}

#[derive(Deserialize, Queryable, QueryableByName)]
pub struct Nested {
    #[sql_type = "Integer"]
    pub bar_id: i32,
    pub foo: Foo
}

pub fn get_nested(conn: & mut DbConn) {
    sql_query("select * from bar join foo on foo.id = bar.foo_id")
        .get_results::<Nested>(conn);
}

But it complains

error: Cannot determine the SQL type of foo
  --> src/main.rs:30:9
   |
30 |     pub foo: Foo
   |         ^^^
   |
   = help: Your struct must either be annotated with `#[diesel(table_name = foo)]` or have this field annotated with `#[diesel(sql_type = ...)]`

error[E0277]: the trait bound `Untyped: load_dsl::private::CompatibleType<Nested, Pg>` is not satisfied
    --> src/main.rs:35:32
     |
35   |         .get_results::<Nested>(conn);
     |          -----------           ^^^^ the trait `load_dsl::private::CompatibleType<Nested, Pg>` is not implemented for `Untyped`
     |          |
     |          required by a bound introduced by this call
     |
     = help: the trait `load_dsl::private::CompatibleType<U, DB>` is implemented for `Untyped`
     = note: required for `SqlQuery` to implement `LoadQuery<'_, _, Nested>`
note: required by a bound in `get_results`
    --> /home/rogers/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-2.0.3/src/query_dsl/mod.rs:1695:15
     |
1695 |         Self: LoadQuery<'query, Conn, U>,
     |               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_results`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust_test` due to 2 previous errors
[Finished running. Exit status: 101]

Is there a way to serialize the database values into a nested structs when doing raw sql queries in diesel?

Upvotes: 0

Views: 294

Answers (1)

weiznich
weiznich

Reputation: 3445

To cite from the relevant documentation:

If a field is another struct which implements QueryableByName, instead of a column, you can annotate that struct with #[diesel(embed)]. Then all fields contained by that inner struct are loaded into the embedded struct.

That means that:

  • Your struct Foo needs to derive QueryableByName as well
  • The field foo of the Nested struct needs to be annotated with #[diesel(embed)]

Upvotes: 2

Related Questions