New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error using Identifiable struct with only id field #1013

Closed
agersant opened this Issue Jul 10, 2017 · 4 comments

Comments

Projects
None yet
3 participants
@agersant

agersant commented Jul 10, 2017

Setup

Versions

  • Rust: 1.18
  • Diesel: 0.14.0
  • Database: SQLite
  • Operating System Windows

Feature Flags

  • diesel: sqlite
  • diesel_codegen: sqlite

Problem Description

When gathering key values for a join via belonging_to, it is not possible to store the keys in a struct which holds id and no other fields.

What are you trying to accomplish?

I run a setup very similar to the posts and users example from the docs so I'll use it for illustration.

The following code works fine (it's from the docs):

let user : User = try!(users::find(1).first(&connection));
let posts = Post::belonging_to(&user).load(&connection);

Now let's imagine the User table and its corresponding struct have many more columns. We would like to only select the id column from the users table (either for performance or to avoid exposing a full fledged User struct to a module that doesn't need it).

We can define a local User struct that only has a id field and update our user query accordingly:

#[derive(Identifiable, Queryable)]
pub struct User {
    id: i32,
}

let user : User = try!(users::find(1).select((id)).first(&connection));

The query returns the actual id and not a struct containing the id so we get this error: the trait diesel::types::FromSqlRow<diesel::types::Integer, diesel::sqlite::Sqlite>is not implemented for(i32,)``.

This seems reasonable so let's change our code to:

let user : i32 = try!(users::find(1).select(id).first(&connection));
let posts = Post::belonging_to(user).load(&connection);

We now receive the following error: the trait diesel::BelongingToDslis not implemented forPost``. Also fairly reasonable, so let's update our belongs_to statement on `Post` accordingly:

#[belongs_to(i32)]
// Note: my real use case also specifies a foreign_key name here but I don't think it's relevant

We now receive: conflicting implementations of trait diesel::JoinTo<_>for typedb::schema::__diesel_infer_schema::infer_posts::posts::table:

I don't know where to go from here.

Workaround

The only workaround I found is to define a second field on the local User struct and change the user query to .select((id, other_field)). This actually lets everything compile but the Rust compiler correctly emits a warning that other_field is never used and could/should be removed.

Checklist

  • I have already looked over the issue tracker for similar issues.

@agersant agersant changed the title from Error using Identifiable struct with only one field to Error using Identifiable struct with only id field Jul 10, 2017

@killercup

This comment has been minimized.

Member

killercup commented Jul 11, 2017

If you User struct only has the id field, do you even need the .select? Or was this just as an example? IIRC we always enumerate all the columns we want to query, so it's never select *. Thus, another workaround would be to write a SlimUser struct :)

@agersant

This comment has been minimized.

agersant commented Jul 12, 2017

Sorry if I didn't explain this right.

There are two User structs in this story. One of them has many fields and matches the layout of the users table closely. That struct is not exposed to this module and does not appear in the snippets above.

The second User struct (let's call it SlimUser) only has the id field. The issue is that diesel refuses to put the result of a SELECT id FROM users […] into a SlimUser.

@sgrif

This comment has been minimized.

Member

sgrif commented Jul 12, 2017

@agersant I think you're just running into a quirky (but intentional) edge case. #[derive(Queryable)] does not special case single-field structs. If you are manually calling select, you'll need to pass it a tuple (so .select((id,)). Is this an issue that occurs without a manual call to select?

@agersant

This comment has been minimized.

agersant commented Jul 12, 2017

Oh that makes sense. I had not realized that without the trailing comma, the select argument was a lone value and not a 1-item tuple (even with the extra parenthesis around the field name). Sorry for the false bug report 🙏.

Everything does work as expected without a select call.

@agersant agersant closed this Jul 12, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment