0

I'm trying to use Rust and sqlx (v0.6.2) to retrieve from DB structs with nested structs.

I tried using the below code but I found out that there is a limit of 9 fields in tuple that I can use with FromRow.

Note: As you can see I'm using a Box<T> for struct fields.

use sqlx::{postgres::PgRow, FromRow, QueryBuilder, Row};

#[derive(Debug, Default, sqlx::FromRow)]
pub struct PgCoach { //PgCoach has ONLY scalar values
    pub team_id: String,
    pub id: String,
    pub created_at: Time::OffsetDateTime,
    pub updated_at: Option<Time::OffsetDateTime>,
    pub firstname: Option<String>,
    pub lastname: Option<String>,
    pub motto: Option<String>,
    pub first_case: Option<String>,
    pub second_case: Option<String>,
    pub third_case: Option<String>,
    pub birth_date: Option<Time::OffsetDateTime>,
    pub sex: Option<i64>,
    pub phone: Option<String>,
    pub email_address: Option<String>,
    pub address: Option<String>,
    pub picture: Option<String>,
    pub notes: Option<String>,
}

#[derive(Debug, Default)]
pub struct PgPlayer {
    pub team_id: String,
    pub id: String,
    pub created_at: Time::OffsetDateTime,
    pub updated_at: Option<Time::OffsetDateTime>,
    pub score: i64,
    pub birth_date: Time::OffsetDateTime,
    pub code: String,
    pub payed: bool,
    pub coach_id: String,
    pub coach: Option<Box<PgCoach>>,
    pub skills: Option<Vec<PgSkill>>,
}

impl FromRow<'_, PgRow> for PgPlayer {
    fn from_row(row: &PgRow) -> sqlx::Result<Self> {
        let mut res = Self {
            team_id: row.get("team_id"),
            id: row.get("id"),
            created_at: row.get("created_at"),
            updated_at: row.get("updated_at"),
            score: row.get("score"),
            birth_date: row.get("birth_date"),
            code: row.get("code"),
            payed: row.get("payed"),
            coach_id: row.get("coach_id"),
            ..Default::default()
        };

        if row.try_get_raw("coach").is_ok() {
            res.coach = Some(Box::new(PgCoach {
                id: row.try_get::<PgCoach, &str>("coach")?.1,
                firstname: row.try_get::<PgCoach, &str>("coach")?.4,
                lastname: row.try_get::<PgCoach, &str>("coach")?.5,
                ..Default::default()
            }));
        }

        Ok(res)
    }
}

The error is:

error[E0277]: the trait bound `pg::PgCoach: sqlx::Decode<'_, sqlx::Postgres>` is not satisfied
   --> src\crates\project\pg.rs:656:21
    |
656 |                 id: row.try_get::<PgCoach, &str>("coach")?.id,
    |                     ^^^ ------- required by a bound introduced by this call
    |                     |
    |                     the trait `sqlx::Decode<'_, sqlx::Postgres>` is not implemented for `pg::PgCoach`
    |
    = help: the following other types implement trait `sqlx::Decode<'r, DB>`:
              <&'r [u8] as sqlx::Decode<'r, sqlx::Postgres>>
              <&'r [u8] as sqlx::Decode<'r, sqlx_core::any::database::Any>>
              <&'r sqlx::types::JsonRawValue as sqlx::Decode<'r, DB>>
              <&'r str as sqlx::Decode<'r, sqlx::Postgres>>
              <&'r str as sqlx::Decode<'r, sqlx_core::any::database::Any>>
              <() as sqlx::Decode<'r, sqlx::Postgres>>
              <(T1, T2) as sqlx::Decode<'r, sqlx::Postgres>>
              <(T1, T2, T3) as sqlx::Decode<'r, sqlx::Postgres>>
            and 43 others
note: required by a bound in `sqlx::Row::try_get`
   --> C:\Users\Fred\.cargo\registry\src\github.com-1ecc6299db9ec823\sqlx-core-0.6.2\src\row.rs:114:12
    |
114 |         T: Decode<'r, Self::Database> + Type<Self::Database>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `sqlx::Row::try_get`

I can use whatever SQL query the method needs.

I can return tuple from DB or single columns, I don't care. I only need a way to query with sqlx structs with nested Box<Struct> and I cannot understand how.

How can I retrieve these structs?

Fred Hors
  • 3,258
  • 3
  • 25
  • 71

0 Answers0