Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build safe dynamic query with sqlx in rust?

Tags:

rust

rust-sqlx

sqlx has a query builder. Documentation can be seen here

I see it supports dynamically buidling queries of the form:

SELECT * FROM users WHERE (id, username) IN ((1, "test_user_1"), (2, "test_user_2"))

But I am interested in building more complex queries likle

SELECT * from users where id = "id" AND username = "username" AND age > "10" AND age < "70" AND last_visited < 12324235435 AND last_visited > 214324324234234

Where any of the where clause is optional. So following should also be dynamically built

SELECT * from users where id = "id" AND age > "10" AND last_visited < 12324235435

I can't seem to find a way to do this with sqlx except from having to manually concatenate the where string myself

like image 462
Finlay Weber Avatar asked Dec 23 '25 00:12

Finlay Weber


1 Answers

I got the following to work locally. Of course, I don't have your database, but the constructed SQL looks correct. I just picked postgres because you didn't specify what database you're actually using.

use sqlx::{query_builder::QueryBuilder, Execute};

struct Search {
    id: i64,
    username: Option<String>,
    min_age: Option<i8>,
    max_age: Option<i8>,
}

fn search_query(search: Search) -> String {
    let mut query = QueryBuilder::new("SELECT * from users where id = ");
    query.push_bind(search.id);

    if let Some(username) = search.username {
        query.push(" AND username = ");
        query.push_bind(username);
    }

    if let Some(min_age) = search.min_age {
        query.push(" AND age > ");
        query.push_bind(min_age);
    }

    if let Some(max_age) = search.max_age {
        query.push(" AND age < ");
        query.push_bind(max_age);
    }

    query.build().sql().into()
}

fn main() {
    dbg!(search_query(Search {
        id: 12,
        username: None,
        min_age: None,
        max_age: None,
    })); // "SELECT * from users where id = $1"
    dbg!(search_query(Search {
        id: 12,
        username: Some("Bob".into()),
        min_age: None,
        max_age: None,
    })); // "SELECT * from users where id = $1 AND username = $2"
    dbg!(search_query(Search {
        id: 12,
        username: Some("Bob".into()),
        min_age: Some(10),
        max_age: Some(70),
    })); // "SELECT * from users where id = $1 AND username = $2 AND age > $3 AND age < $4"
}

I didn't make the id optional but I'm sure you can figure out how to omit the where entirely if no parameters are provided.

like image 166
PitaJ Avatar answered Dec 27 '25 11:12

PitaJ



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!