Skip to content

Synthesize INSERT statements for structs #3071

@borchero

Description

@borchero

Is your feature request related to a problem? Please describe.

sqlx is an amazing crate and I love the ability to write compile-time-checked queries. The only thing that bothers me whenever I'm using the library is that INSERT statements are very verbose. As tables get wider, queries feel ever more repetitive, and as schemas evolve, updates are required in a bunch of places. I always thought that there should be a "write-equivalent" to the "read-only" interface query_as! that allows me to automatically map Rust types to the underlying tables for INSERT statements.

Describe the solution you'd like

The most natural way to handle this would, in my opinion, be the implementation of a trait (let's call it sqlx::Insert) on structs that can be inserted into a database. The trait implementation can easily be synthesized via a macro. For example, the user could implement

#[derive(sqlx::Insert)]
#[sqlx(table_name = "users")]
struct User {
    email: String,
    name: String,
    age: u8,
}

which then synthesizes a method sqlx_insert which executes

sqlx::query!("INSERT INTO users (email, name, age) VALUES ($1, $2, $3)", self.email, self.name, self.age)

and which is compile-time-checked!

The real power of sqlx can be leveraged by synthesizing ON CONFLICT ... UPDATE queries by querying a table's primary key during compilation. Assuming email is a primary key, we can synthesize (again, compile-time-checked) queries like this:

sqlx::query!(r#"
    INSERT INTO users (email, name, age) VALUES ($1, $2, $3)
    ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name, age = EXCLUDED.age
"#, self.email, self.name, self.age)

The user would not be required to do anything but define the struct above.

Describe alternatives you've considered

n/a

Additional context

The main purpose of this issue is to gauge whether the proposal (or something along these lines) would be in scope for sqlx. If so, I would be happy to contribute, @delsner and I already implemented this as a third-party crate (which is, unfortunately, not yet published). Besides our shared love for open-source, a major driver for the desire to contribute is that synthesizing the ON CONFLICT ... UPDATE queries requires storing the primary key information for offline compilation which currently requires us to duplicate much of the logic in sqlx-cli.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions