Nested postgres custom composite types
Consider following types:
#[derive(sqlx::Type)]
struct Foo {
one: String,
two: String,
}
#[derive(sqlx::Type)]
struct Bar {
foo: Foo,
three: String,
}
This fails to compile on 1.46 with:
error: implementation of `sqlx::Decode` is not general enough
--> src/main.rs:7:10
|
7 | #[derive(sqlx::Type)]
| ^^^^^^^^^^ implementation of `sqlx::Decode` is not general enough
|
::: /Users/fey/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-core-0.4.0-beta.1/src/decode.rs:60:1
|
60 | / pub trait Decode<'r, DB: Database>: Sized {
61 | | /// Decode a new value of this type using a raw value from the database.
62 | | fn decode(value: <DB as HasValueRef<'r>>::ValueRef) -> Result<Self, BoxDynError>;
63 | | }
| |_- trait `sqlx::Decode` defined here
|
= note: `Foo` must implement `sqlx::Decode<'0, sqlx::Postgres>`, for any lifetime `'0`...
= note: ...but `Foo` actually implements `sqlx::Decode<'1, sqlx::Postgres>`, for some specific lifetime `'1`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
I used cargo-expand to see what the derive macro expands to and Decode impl is like this:
impl<'r> sqlx::decode::Decode<'r, sqlx::Postgres> for Bar
where
String: sqlx::decode::Decode<'r, sqlx::Postgres>,
String: sqlx::types::Type<sqlx::Postgres>,
Foo: sqlx::decode::Decode<'r, sqlx::Postgres>,
Foo: sqlx::types::Type<sqlx::Postgres>,
{
fn decode(
value: sqlx::postgres::PgValueRef<'r>,
) -> std::result::Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
let mut decoder = sqlx::postgres::types::PgRecordDecoder::new(value)?;
let three = decoder.try_decode::<String>()?;
let foo = decoder.try_decode::<Foo>()?;
Ok(Bar { three, foo })
}
}
If I change Foo: sqlx::decode::Decode<'r, sqlx::Postgres>, to Foo: for<'q> sqlx::decode::Decode<'q, sqlx::Postgres>, then it compiles well. Could this be a bug in the sqlx::Type macro?
I'm having the same issue with:
#[derive(sqlx::Type)]
struct Contract {
id: i32,
user_id: i32,
order_id: i32,
tags: Vec<i32>,
}
Manually implementing decode using your strategy worked.
From what I noticed, it seems like the fact that composite types in Postgres do not have constraints means that all composite fields are automatically not null. And that means that the output type has to have all it's fields as Option<_>.
This issue is a major blocker for me :(
Hope will be resolved soon.
I can't use a workaround impl Decode since I am migrating from the 0.5.2 version to 0.6.2 and there is a lot of Option<T>.
Is this still an issue in sqlx 0.8? It seems fixed for me.
I can also confirm that it works on 0.8.