Diesel : belonging_to not found with many to many

Hi again, it's me !

I am lost with diesel ORM...
I am trying to select a user, with all agencies link to him.

But I don't success to make it works...

I've tried to follow some topics, like this one, or this.

But I think I misunderstand some things...

shema.rs
table! {
    agencies (id) {
        id -> Varchar,
        label -> Varchar,
        mail -> Varchar,
        uri -> Varchar,
        logo -> Varchar,
    }
}

table! {
    users (id) {
        id -> Int4,
        mail -> Varchar,
        pass -> Bpchar,
    }
}

table! {
    users_agencies (users_id, agencies_id) {
        users_id -> Int4,
        agencies_id -> Varchar,
    }
}

joinable!(users_agencies -> agencies (agencies_id));
joinable!(users_agencies -> users (users_id));

allow_tables_to_appear_in_same_query!(
    agencies,
    users,
    users_agencies,
);
models.rs
use diesel::PgConnection;

use super::schema::*;
use crate::business::{agency::Agency, error::ApiError, user::ApiUser};

#[derive(Identifiable, Insertable, Queryable, PartialEq, Debug)]
#[table_name = "users"]
pub struct Users {
    pub id: i32,
    pub mail: String,
    pub pass: String,
}

impl Users {
    pub fn into_api_user(&self, db_connection: &PgConnection) -> Result<ApiUser, ApiError> {
        match UsersAgencies::belonging_to(self)
            .inner_join(agencies::table)
            .select(agencies::all_columns)
            .load::<Agencies>(db_connection)
        {
            Ok(agencies) => Ok(ApiUser::new(
                self.mail,
                agencies.into_iter().map(|a| a.into_agency).collect(),
            )),
            Err(e) => Err(ApiError::new(format!(
                "Error while converting db Users into ApiUser : {}",
                e
            ))),
        }
    }
}

#[derive(Insertable, Queryable, PartialEq, Debug)]
#[table_name = "agencies"]
pub struct Agencies {
    pub id: String,
    pub label: String,
    pub mail: String,
    pub uri: String,
    pub logo: String,
}

impl Agencies {
    pub fn into_agency(&self) -> Agency {
        Agency::new(self.id, self.label, self.mail, self.uri, self.logo)
    }
}

#[derive(Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Users)]
#[belongs_to(Agencies)]
#[table_name = "users_agencies"]
pub struct UsersAgencies {
    pub users_id: String,
    pub agencies_id: String,
}
implementation
#[macro_use]
extern crate diesel;
extern crate diesel_codegen;
extern crate r2d2;
extern crate r2d2_diesel;

use diesel::prelude::*;
use diesel::PgConnection;
use crate::business::{ad::Ad, error::ApiError, user::ApiUser};
use super::db_models::models::Users;
use super::db_models::schema::users::dsl::*;

    pub fn authenticate(
        &self,
        login: String,
        password: String,
        db_connection: &PgConnection,
    ) -> Result<ApiUser, ApiError> {
        let usrs = match users
            .filter(mail.eq(&login))
            .filter(pass.eq(self.hash_password(&password)))
            .load::<Users>(db_connection)
        {
            Ok(u) => u,
            Err(e) => {
                return Err(ApiError::new(format!(
                    "User '{}' unauthorized : {}",
                    login, e
                )))
            }
        };

        match usrs.get(0) {
            Some(u) => u.into_api_user(db_connection),
            None => Err(ApiError::new(format!("No user found for '{}'", login))),
        }
    }
Build error
error[E0599]: no function or associated item named `belonging_to` found for struct `UsersAgencies` in the current scope
  --> src\infrastructure\db_models\models.rs:16:30
   |
16 |         match UsersAgencies::belonging_to(self)
   |                              ^^^^^^^^^^^^ function or associated item not found in `UsersAgencies`
...
53 | pub struct UsersAgencies {
   | ------------------------ function or associated item `belonging_to` not found for this
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `belonging_to`, perhaps you need to implement it:
           candidate #1: `BelongingToDsl`

I tried to implement 'BelongingToDsl' trait on UsersAgencies, but I don't understand how to fill the function.

Does soemone can help me again please ?

Try adding Identifiable to the derive list for UsersAgencies.

This page says that it should: diesel::associations

Hi alice, thank you for your answer.

I've already tried this, but it tells me that there must be an id.
And my table does not have one, because the primary key is the bot foreign key.

  --> src\infrastructure\db_models\models.rs:28:53
   |
28 | #[derive(Queryable, Associations, PartialEq, Debug, Identifiable)]
   |                                                     ^^^^^^^^^^^^
   |
   = help: message: No field with column name id

For the moment, I success to work around the problem by doing :

fn user_into_api_user(
        &self,
        user: &Users,
        api_key: &str,
        db_connection: &PgConnection,
    ) -> Result<ApiUser, ApiError> {
        match users
            .inner_join(users_agencies::table.inner_join(agencies::table))
            .filter(id.eq(user.id))
            .select(agencies::all_columns)
            .load::<Agencies>(db_connection)
        {
            Ok(agencies) => Ok(ApiUser::new(
                user.mail.clone(),
                agencies.into_iter().map(|a| a.into_agency()).collect(),
                api_key.to_string(),
            )),
            Err(e) => Err(ApiError::new(format!(
                "Error while converting db Users into api user : {}",
                e
            ))),
        }
    }

But I can't put this code in Users impl (don't know why it do not found inner_join and other functions), so I put it in my DAO impl.

Oh, well, I think diesel requires an id in all tables?

If I have understand right, 'Identifiable' is to be linked with and id.

Because with my workaround I don't need it and it works.

To clarify that: Diesel does not require a column named id on tables, that's just the default that various derives assume. It's always possible to change that. For example the Identifiable derive allows you to specify a custom primary key via the #[primary_key()] attribute. Checkout the documentation for more details: Identifiable in diesel::associations - Rust

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.