#sqlx #insert #proc-macro #postgresql #sqlite #statement #generate

sqlx_insert

Proc macro for generating insert statements for sqlx

2 releases

0.1.1 Mar 12, 2024
0.1.0 Mar 4, 2024

#1278 in Database interfaces

Download history 132/week @ 2024-03-03 133/week @ 2024-03-10 11/week @ 2024-03-17 73/week @ 2024-03-24 30/week @ 2024-03-31 2/week @ 2024-04-07

107 downloads per month

Apache-2.0

6KB

sqlx-insert

This crate provides a proc macro that generates code for inserting structs into the database using sqlx to save you from excessive typing, and not inserted columns.

Example

use sqlx::Postgres;
use sqlx::Sqlite;
use sqlx_insert::SQLInsert;

#[derive(SQLInsert, Clone, Debug, PartialEq)]
#[sqlx_insert(database(Postgres, Sqlite))]
pub struct Thing {
    id: String,
    name: String,
    amount: i32,
    pear: String,
}

Then you can simply use it as:

use sqlx_insert::SQLInsert;
//...
let mut connection = pool.acquire().await.unwrap();

let thing = Thing {
    // Create a thing...
};

thing.sql_insert(cnn.as_mut()).await.unwrap();

The SQLInsert macro will generate the following insert query:

let _ = sqlx::query(
        "INSERT INTO thing (id, name, amount, pear) VALUES ($1, $2, $3, $4)",
    )
    .bind(thing.id.clone())
    .bind(thing.name.clone())
    .bind(thing.amount.clone())
    .bind(thing.pear.clone())
    .execute(connection)
    .await?;

Attributes

SQLInsert macro supports the following struct attributes:

  • database - list of types implementing sqlx::Database for which insert query is implemented.
  • table - the name of the table to which generated query inserts.

And field level attributes:

  • ignore - ignore field in generated insert query.
  • rename - column name for which the field should be inserted.

Example struct using those:

#[derive(SQLInsert, Clone, Debug, PartialEq)]
#[sqlx_insert(table = "thingy")]
#[sqlx_insert(database(Postgres))]
pub struct Thing {
    id: String,
    name: String,
    amount: i32,
    pear: String,
    #[sqlx_insert(ignore)]
    ignore_me: Option<String>,
    #[sqlx_insert(rename = "param_extra")]
    param: String,
    #[sqlx_insert(ignore)]
    complex_type: ComplexType,
}

For detailed examples, see tests.

Motivation

I created this macro some time ago for use in personal projects, and it proved itself very useful. sqlx is a great library giving users a lot of control over the shape of queries, however, it requires them to write insert queries for all types "by hand".

As the types grow in size and change over time I often find it tedious to maintain, with this macro I only add a filed to a type and do not need to update insert queries. If more sophisticated insert logic is required, I can always switch back to hand written query.

The drawback of this approach is that we do not leverage compile-time query verification, however, I personally rarely used it anyway due to additional dependencies during development.


lib.rs:

SQLInsert trait and derive macro for sqlx.

Dependencies

~10MB
~212K SLoC