sqlx icon indicating copy to clipboard operation
sqlx copied to clipboard

Flatten out struct fields on insertions

Open laralove143 opened this issue 2 years ago • 2 comments

Is your feature request related to a problem? Please describe. If we have a struct with many fields which we want to insert to the database, we need to write out every field individually, this gets inconvenient and hard to maintain (removing/adding a field and column needs changing every query they're used in)

struct ManyFields {
  assume: i64,
  theres: i64,
  many: i64,
}
async fn insert(db: &PgPool, fields: ManyFields) -> sqlx::Result<()> {
  query!(
    "INSERT INTO many_fields VALUES ($1, $2, $3)",
    fields.assume,
    fields.theres,
    fields.many
  ).exec(db).await?;
  Ok(())
}

Describe the solution you'd like

  • The struct's field names have to match the column names, similar to #[sqlx(FromRow)]
  • The query could:
    • Ignore the fields that are unused (if struct as foo, bar, baz fields and table/insertion has foo, bar columns, it'd still be allowed), which lets us avoid creating new structs or taking fields by parameters, but also makes the function require more fields than actually used (which is very common in other code actually).
    • Require an exact match between fields and columns
  • It would also ideally work with multiple structs, flattening each one's fields
struct ManyFields {
  assume: i64,
  theres: i64,
  many: i64,
}
async fn insert(db: &PgPool, fields: ManyFields) -> sqlx::Result<()> {
  query!("INSERT INTO many_fields VALUES ($1)", fields).exec(db).await?;
  Ok(())
}

Describe alternatives you've considered If required, this could be another function/macro, like how query and query_as are different

Additional context This might help with making unnest() (which is currently required for multiple-row insertions) easier

laralove143 avatar Mar 12 '23 01:03 laralove143

#328 and sqlxinsert may be of interest also.

mtbc avatar Nov 15 '23 17:11 mtbc

There is now a set of new macros in SeaQuery allowing you to write:

struct Item {
    a: i32,
    b: String,
    c: u16,
}

let values = vec![
    Item { a: 1, b: "2".to_owned(), c: 3 },
    Item { a: 4, b: "5".to_owned(), c: 6 },
];

let mut sql;
let res = sea_query::sqlx::sqlite::query!(
    sql = r#"INSERT INTO "glyph" ("aspect", "image", "font_size")
       VALUES {..(values.a, values.b, values.c),}"#
).execute(pool).await?;

Ref: https://www.sea-ql.org/blog/2025-08-15-sea-query-raw-sql/#sqlx-integration

tyt2y3 avatar Oct 24 '25 10:10 tyt2y3