launchbadge / sqlx

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
Apache License 2.0
13.17k stars 1.24k forks source link

Optionally select fields #1830

Open nanokeshtw opened 2 years ago

nanokeshtw commented 2 years ago

Question

I understand that in order to get data from a table I need to define a struct with the data I expect, and for specific queries I can specify specific structs with the specific data I am querying, but what if I may or may not query data. How do I query to the db where one time I might want the fields id, name, and age, and the next time I just want id and name?

Example

Currently, if I use this code (and user_input is false), I get an runtime error that tells me that age needs to be included in the select query. I want to be able to sometimes query for, in this case, the age column, but without having to define another struct, leave out the age column in the next query. Is this possible?

let user_input: bool = /* ... */

let mut age = String::from("");
if user_input {
    age = " age"
}

// How to make age possibly queried?
// Option doesn't work as it just makes
// age act as nullable in the mysql table definition
#[derive(sqlx::FromRow)]
struct Person { id: i64, name: String, age: Option<u8> }

// Sometimes we query fields id, name, age and other times just id and name
let query = format!("SELECT id, name,{} FROM person", age); 

let mut rows = sqlx::query_as::<_, Person>(query)
    .fetch(&mut conn);
pythoneer commented 2 years ago

There where some ideas cooking here but it has not lead to any concrete implementations.

I think in your case you would get something like

query_as!(Person, "SELECT p.id, p.name, ...", skip: ["age"])

But this is not even close to being worked on as far as i know. I think in the current state you have to either make two structs or have two different queries with one returning null for the age that is being converted to an Option