Search code examples
postgresqlrustormrust-diesel

More generic CRUD. RUST, Diesel


is it possible to create more generic queries using diesel? I know how to create update or delete for every properties. But my point is create generic update for many structures. My models:

#[derive(Associations, Identifiable, Queryable, PartialEq, Debug)]
#[diesel(belongs_to(User))]
#[diesel(table_name = books)]
pub struct Book {
    pub id: i32,
    pub user_id: i32,
    pub title: String,
    pub body: String,
    pub book_description: String,
    pub book_image: Option<String>,
    pub publish_day: chrono::NaiveDateTime,
}

#[derive(Associations, Identifiable, Queryable, PartialEq, Debug)]
#[diesel(belongs_to(Book))]
#[diesel(table_name = book_comments)]
pub struct BookComment {
    pub id: i32,
    pub book_id: i32,
    pub body: String,    
    pub publish_day: chrono::NaiveDateTime,
} 

My schema:

diesel::table! {
    books (id) {
        id -> Int4,
        user_id -> Int4,
        title -> Varchar,
        body -> Text,
        book_description -> Varchar,
        book_image -> Nullable<Varchar>,
        publish_day -> Timestamp,
    }
}

diesel::table! {
    book_comments (id) {
        id -> Int4,
        book_id -> Int4,
        body -> Varchar,
        publish_day -> Timestamp,
    }
}


Working wersion:

pub fn upate<T>(&mut self, book_id: &i32, title: &str) -> Book {
        let result = diesel::update(books::table)
            .filter(book::id.eq(&book_id))
            .set(book::title.eq(title))
            .get_result::<Book>(&mut self.connection)
            .expect("Failed to update book");

        result
    }
   

I'm trying something like this:

 pub fn upate<T, U, P: Table, S>(&mut self, find_by: &T, change: U, target_table: Table,change_param: &S) -> Book {
        let result = diesel::update(target_table)
            .filter(find_by.eq(&book_id))
            .set(S.eq(change))
            .get_result::<U>(&mut self.connection)
            .expect("Failed to update book");

        result

But of course doesn't work. Is this possible?

Little help with solution.


Solution

  • I did this using macro, this is a snippet from the code I used

    #[macro_export]
    macro_rules! get_by_id {
        ($table:ident,$m:ident,$pool:ident,$id:ident) => {
             {
                let conn = $pool.get()?;
                let res = $table::table
                    .filter($table::columns::id.eq($id))
                    .get_result::<$m>(&conn)?;
                Ok(res) as Result<$m, Error>
            }
        };
    }
    

    Edit: can be used like this:

    let user = get_by_id!(schema::users, User, pool, user_id)?;