-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Rust Version
1.93.0
Diesel Version
2.3.6
Diesel Features
sqlite
Database Version
Sqlite 3.46.1
Operating System Version
Kubuntu 25.10
What happened?
When using joinable tables whose struct definitions use field types mapped using #[diesel(serialize_as)] and #[diesel(deserialize_as)] in their primary and foreign key fields, their relation is not usable with the GroupBy trait, the compiler complaining, among others, that [ChildEntity] is required to implement Sized for Vec<ChildEntity> to implement GroupBy.
While most often one uses simple types like i64, i32, or sometimes String for table keys, mapping them via separate mapping types comes in handy if one wants eg. Ulid keys serialized as raw bytes in the database (that’s actually how I first hit the problem).
Using the conversion type directly (instead of via serialize_as / deserialize_as attributes) in the struct works around this limitation.
What did you expect to happen?
I expected either:
- the
grouped_byfunction to work in this case, - or the limitation (if it is intended eg. to avoid issues with different behaviour of
HashandEq/PartialEqon the two types) to be documented and the error message clearer.
I lost a few hours trying to figure out why this doesn’t want to work and why it requires an unsized array to implement sized.
Additional details
I checked that this issue can be reproduced without a third party crate as it’s true – for brevity I pulled derive_more in the minimal reproducer though.
Steps to reproduce
A full reproducible example using these dependencies:
derive_more = { version = "2.1.1", features = ["from", "into"] }
diesel = { version = "2.3.6", features = ["sqlite"] }is here:
main.rs
use derive_more::{From, Into};
use diesel::{
backend::Backend,
deserialize::{FromSql, FromSqlRow},
expression::AsExpression,
prelude::*,
serialize::{IsNull, ToSql},
sql_types,
sqlite::Sqlite,
};
mod schema {
diesel::table! {
posts (id) {
id -> Text,
content -> Text,
}
}
diesel::table! {
tags_to_posts (name, post_id) {
name -> Text,
post_id -> Text,
}
}
diesel::allow_tables_to_appear_in_same_query!(posts, tags_to_posts,);
}
#[derive(Debug, PartialEq, Eq, Hash, Selectable, Queryable, Identifiable, Insertable)]
#[diesel(table_name = schema::posts)]
struct Post {
#[diesel(deserialize_as = IntAsString, serialize_as = IntAsString)]
id: i32,
content: String,
}
#[derive(
Debug, PartialEq, Eq, Hash, Selectable, Queryable, Identifiable, Insertable, Associations,
)]
#[diesel(table_name = schema::tags_to_posts)]
#[diesel(primary_key(name, post_id))]
#[diesel(belongs_to(Post))]
struct TagToPost {
name: String,
#[diesel(deserialize_as = IntAsString, serialize_as = IntAsString)]
post_id: i32,
}
#[derive(Debug, PartialEq, Eq, Hash, From, Into, AsExpression, FromSqlRow)]
#[diesel(sql_type = sql_types::Text)]
struct IntAsString(i32);
impl FromSql<sql_types::Text, Sqlite> for IntAsString {
fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
let string = <String as FromSql<sql_types::Text, _>>::from_sql(bytes)?;
let i = string.parse().map_err(Box::new)?;
Ok(IntAsString(i))
}
}
impl ToSql<sql_types::Text, Sqlite> for IntAsString {
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
) -> diesel::serialize::Result {
let string = self.0.to_string();
out.set_value(string);
Ok(IsNull::No)
}
}
fn main() {
let mut db = diesel::SqliteConnection::establish("test.db").unwrap();
let posts = schema::posts::table
.select(Post::as_select())
.load::<Post>(&mut db)
.unwrap();
let tags = schema::tags_to_posts::table
.select(TagToPost::as_select())
.load::<TagToPost>(&mut db)
.unwrap();
let _grouped = tags
.grouped_by(&posts)
.into_iter()
.zip(posts)
.collect::<Vec<_>>();
}Compile time error
error[E0599]: the method `grouped_by` exists for struct `Vec<TagToPost>`, but its trait bounds were not satisfied
--> src/main.rs:85:10
|
84 | let _grouped = tags
| ____________________-
85 | | .grouped_by(&posts)
| | -^^^^^^^^^^ method cannot be called on `Vec<TagToPost>` due to unsatisfied trait bounds
| |_________|
|
|
= note: the following trait bounds were not satisfied:
`<[TagToPost] as IntoIterator>::Item = _`
which is required by `[TagToPost]: diesel::GroupedBy<'_, _>`
`[TagToPost]: Sized`
which is required by `[TagToPost]: diesel::GroupedBy<'_, _>`
`[TagToPost]: IntoIterator`
which is required by `[TagToPost]: diesel::GroupedBy<'_, _>`
For more information about this error, try `rustc --explain E0599`.
error: could not compile `diesel-associations` (bin "diesel-associations") due to 1 previous error
Checklist
-
I have already looked over the issue tracker and the discussion forum for similar possible closed issues.
-
This issue can be reproduced on Rust's stable channel. (Please submit the issue in the Rust issue tracker instead if that's not the case)
-
This issue can be reproduced without requiring a third party crate