Diesel: Diesel does not produce `belonging_to()` for structs annotated with `belongs_to`

Created on 26 Sep 2017  路  5Comments  路  Source: diesel-rs/diesel

Setup

Versions

  • Rust: rustc 1.22.0-nightly (1ed7d41d8 2017-09-24)
  • Diesel: 0.16.0
  • Database: postgresql 9.6.2
  • Operating System macos sierra 10.12.6

Feature Flags

  • diesel: postgres, chrono
  • diesel_codegen: postgres

Problem Description

#[derive(Queryable, Serialize, Identifiable)]
#[has_many(categories)]
pub struct User {
    pub id: i32,
    pub username: String,
}

#[derive(Queryable, Serialize, Identifiable, Associations)]
#[table_name = "categories"]
#[belongs_to(User, foreign_key = "username")]
pub struct Category {
    pub id: i32,
    pub username: String,
}

[... later in main.rs ...]

        let user: User = users.find(1).first(connection).expect("Error loading user");
        let cats = Category::belonging_to(&user).load(connection).expect("Error loading cats");

gives

error[E0599]: no function or associated item named `belonging_to` found for type `models::Category` in the current scope
   --> src/main.rs:157:20
    |
157 |         let cats = Category::belonging_to(&user).load(connection).expect(
    |                     ^^^^^^^^^^^^^^^^^^^^^^

What are you trying to accomplish?

Link two tables using the belonging_to()

What is the expected output?

Should compile at least.

What is the actual output?

Regardless of whether these tables have a foreign key relation on DB or not, there's no belonging_to() function to call.

Are you seeing any additional errors?

No. Warnings:

warning: unused attribute
 --> src/models.rs:8:1
  |
8 | #[has_many(categories)]
  | ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_attributes)] on by default

Steps to reproduce

models.rs as above.

schema.rs (from diesel print-schema):

table! {
    users (id) {
        id -> Int4,
        username -> Varchar,
    }
}

table! {
    categories (id) {
        id -> Int4,
        username -> Varchar,
    }
}

Checklist

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

Most helpful comment

I reduced your repro case to this minimal case:

#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;

use diesel::prelude::*;

table! {
    users {
        id -> Int4,
        username -> Varchar,
    }
}

table! {
    categories {
        id -> Int4,
        username -> Varchar,
    }
}

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

#[derive(Identifiable, Associations)]
#[table_name = "categories"]
#[belongs_to(User, foreign_key = "username")]
pub struct Category {
    pub id: i32,
    pub username: String,
}

fn main() {
    let user = User { id: 1, username: "".into() };
    let cats = Category::belonging_to(&user);
}

by switching to UFCS (<Category as BelongingToDsl<&User>>::belonging_to(&user)) we get a much clearer error message:

error[E0277]: the trait bound `diesel::query_builder::SelectStatement<categories::table>: diesel::FilterDsl<diesel::expression::operators::Eq<categories::columns::username, &i32>>` is not satisfied
  --> src/main.rs:36:16
   |
36 |     let cats = <Category as BelongingToDsl<&User>>::belonging_to(&user);
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::FilterDsl<diesel::expression::operators::Eq<categories::columns::username, &i32>>` is not implemented for `diesel::query_builder::SelectStatement<categories::table>`
   |
   = help: the following implementations were found:
             <diesel::query_builder::SelectStatement<F, S, D, W, O, L, Of, G> as diesel::FilterDsl<Predicate>>
   = note: required because of the requirements on the impl of `diesel::FilterDsl<diesel::expression::operators::Eq<categories::columns::username, &i32>>` for `categories::table`

error[E0277]: the trait bound `i32: diesel::Expression` is not satisfied
  --> src/main.rs:36:16
   |
36 |     let cats = <Category as BelongingToDsl<&User>>::belonging_to(&user);
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `i32`
   |
   = note: required because of the requirements on the impl of `diesel::Expression` for `&i32`
   = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::types::Text>` for `&i32`
   = note: required because of the requirements on the impl of `diesel::BelongingToDsl<&User>` for `Category`

You are attempting to use the field username as the foreign key, but the primary key of user is id which has the type Integer. You cannot compare an integer and text column.

All 5 comments

Please provide your full compiler output

I will send you full project repo in a bit.

Here's the repo: https://github.com/berkus/diesel-belongs-to-bug/blob/master/README.md

steps to reproduce:

  1. git clone https://github.com/berkus/diesel-belongs-to-bug
  2. cd diesel-belongs-to-bug
  3. cargo run

(i'm using nightly jfyi)

I reduced your repro case to this minimal case:

#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;

use diesel::prelude::*;

table! {
    users {
        id -> Int4,
        username -> Varchar,
    }
}

table! {
    categories {
        id -> Int4,
        username -> Varchar,
    }
}

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

#[derive(Identifiable, Associations)]
#[table_name = "categories"]
#[belongs_to(User, foreign_key = "username")]
pub struct Category {
    pub id: i32,
    pub username: String,
}

fn main() {
    let user = User { id: 1, username: "".into() };
    let cats = Category::belonging_to(&user);
}

by switching to UFCS (<Category as BelongingToDsl<&User>>::belonging_to(&user)) we get a much clearer error message:

error[E0277]: the trait bound `diesel::query_builder::SelectStatement<categories::table>: diesel::FilterDsl<diesel::expression::operators::Eq<categories::columns::username, &i32>>` is not satisfied
  --> src/main.rs:36:16
   |
36 |     let cats = <Category as BelongingToDsl<&User>>::belonging_to(&user);
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::FilterDsl<diesel::expression::operators::Eq<categories::columns::username, &i32>>` is not implemented for `diesel::query_builder::SelectStatement<categories::table>`
   |
   = help: the following implementations were found:
             <diesel::query_builder::SelectStatement<F, S, D, W, O, L, Of, G> as diesel::FilterDsl<Predicate>>
   = note: required because of the requirements on the impl of `diesel::FilterDsl<diesel::expression::operators::Eq<categories::columns::username, &i32>>` for `categories::table`

error[E0277]: the trait bound `i32: diesel::Expression` is not satisfied
  --> src/main.rs:36:16
   |
36 |     let cats = <Category as BelongingToDsl<&User>>::belonging_to(&user);
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `i32`
   |
   = note: required because of the requirements on the impl of `diesel::Expression` for `&i32`
   = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::types::Text>` for `&i32`
   = note: required because of the requirements on the impl of `diesel::BelongingToDsl<&User>` for `Category`

You are attempting to use the field username as the foreign key, but the primary key of user is id which has the type Integer. You cannot compare an integer and text column.

Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

raintears picture raintears  路  4Comments

orionz picture orionz  路  3Comments

jimmycuadra picture jimmycuadra  路  3Comments

kanekv picture kanekv  路  3Comments

Fuckoffee picture Fuckoffee  路  3Comments