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

Auto-generated query methods #1358

Closed
shssoichiro opened this Issue Dec 8, 2017 · 3 comments

Comments

Projects
None yet
3 participants
@shssoichiro
Contributor

shssoichiro commented Dec 8, 2017

In Diesel, I'd like the ability to auto-derive query methods onto my model. For example, if I have the following code:

#[derive(Insertable)]
pub struct NewUser<'a> {
    name: &'a str,
    email: &'a str,
    password_hash: &'a str,
}

I'd like to see the following method derived:

impl<'a> Insertable for NewUser<'a> {
    fn save(&self, conn: &Connection) -> QueryResult<User> {
        diesel::insert_into(users::table)
            .values(&self)
            .get_result(conn)
    }
}

Likewise for selects, a few examples:

#[derive(Identifiable)]
pub struct User {
    // fields omitted
}

Would generate something like this:

impl Identifiable for User {
    fn find_one(conn: &Connection, id: i32) -> QueryResult<Option<Self>> {
        users::dsl::users
            .find(id)
            .get_result(conn)
            .optional()
    }
}

The following:

#[derive(Queryable)]
pub struct User {
    // fields omitted
}

Would generate this:

impl Queryable for User {
    fn find_all(conn: &Connection) -> QueryResult<Vec<Self>> {
        users::dsl::users.get_results(conn)
    }
}

And this derive:

#[derive(AsChangeset)]
pub struct User {
    // fields omitted
}

would generate this:

impl AsChangeset for User {
    fn update(&self, conn: &Connection) -> QueryResult<Self> {
        update(self).set(self).get_result(conn)
    }
}

As a more advanced version of this feature, I'd like to be able to define queries with basic filters and sorts using auto-derive as I can in Hibernate. For example, something like this:

trait UserQueries {
    fn find_all_by_last_name_order_by_created_at_desc(conn: &Connection, last_name: &str) -> QueryResult<Vec<User>>;
}

#[derive(UserQueries)]
pub struct User { ... }

would generate standard Diesel DSL like this:

impl UserQueries for User {
    fn find_all_by_last_name_order_by_created_at_desc(conn: &Connection, last_name: &str) -> QueryResult<Vec<User>> {
        users::dsl::users
            .filter(users::dsl::last_name.eq(last_name))
            .order(users::dsl::created_at.desc())
            .get_results(conn)
    }
}

Each of these features would reduce the amount of DSL needed to be manually written (users would only need to resort to DSL for more complex queries) by deriving the most frequently used types of queries (CRUD) within a typical service, would help users to get up and running with Diesel more quickly with less upfront knowledge needed, and would reduce the amount of code needed to be maintained (and copy and pasted) by users. I'd be willing to help implement this as well, if this feature is accepted and API agreed upon.

@sgrif

This comment has been minimized.

Member

sgrif commented Dec 9, 2017

I don't think that these methods would be significantly easier to use than using the query builder directly. Generally we try to keep Diesel very clear what underlying SQL is being performed. I think this would make a great candidate for a third party library, but I don't think it makes sense for Diesel at this time.

@sgrif sgrif closed this Dec 9, 2017

@Eijebong

This comment has been minimized.

Member

Eijebong commented Dec 9, 2017

https://git.bananium.fr/enib/enibar/blob/master/application/rapi/rapi_codegen/src/model.rs#L31-56

Here's what I'm doing in a project (for now it's minimal but I intend to expand it as the migration from python to rust progresses), if there is an interest I guess I could release it as a diesel_models crate or something like that.

@shssoichiro

This comment has been minimized.

Contributor

shssoichiro commented Dec 16, 2017

@Eijebong I used what you wrote as a base for building this library: https://github.com/shssoichiro/diesel-derives-extra. It's a little rough for now but I'll clean it up and probably add more methods as feedback is generated from using it. I think the main benefit of putting this into diesel itself would be that the traits could be pulled in with diesel::prelude::* and remove the need for the extra trait imports, but I don't think that's enough to push this into diesel if the maintainers don't feel it fits with the core goals of diesel. I'm fine with keeping this as a third-party crate.

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