rustrust-sqlx

Dynamic SQL queries in sqlx


Using the sqlx library in Rust and PostgreSQL, I would like to perform some dynamic queries, i.e. the tables and columns and WHERE clauses will not be known until runtime.

When I use .execute, I get back a PgQueryResult and when I use .fetch_all I get back a Vec<PgRow>. But neither seems to offer a way to iterate over rows returned and then identify the columns from the response metadata and obtain the field values individually.

    // Returns PgQueryResult
    let result  = sqlx::query("select * from category")
    .execute(&pool)
    .await.unwrap();

    // Returns Vec<PgRow>
    let results = sqlx::query("select * from category")
    .fetch_all(&pool)
    .await.unwrap();

There is an example pointed to in the README from this issue: https://github.com/launchbadge/sqlx/issues/333#issuecomment-632610467 which seems to come close:

// provides `try_next`
use futures::TryStreamExt;

let mut rows = sqlx::query("SELECT * FROM users WHERE email = ?")
    .bind(email)
    .fetch(&mut conn);

while let Some(row) = rows.try_next().await? {
    // map the row into a user-defined domain type
    let email: &str = row.try_get("email")?;
}

But this does not work for me. (There is no try_get function even after using futures::TryStreamExt.

But even this suggests that I need, at compile time, to know what the data looks like in order to map it.

Perhaps there is an example I have not seen of how to do this completely dynamically, i.e. obtain a list from the column, then obtain each field individually using that for each row.


Solution

  • When I use .execute, I get back a PgQueryResult and when I use .fetch_all I get back a Vec<PgRow>. But neither seems to offer a way to iterate over rows returned and then identify the columns from the response metadata and obtain the field values individually.

    I might be missing what you mean but as far as I can tell PgRow implements Row which does in fact provide a way to identify the columns.

    You can also prepare the query and retrieve the expected columns from that before running the query.

    Although if you are executing dynamically constructed query I would also expect you could know the columns up front from the preparation, so you have no reason to ask for them? Surely you don't full send random crap into your database?