如何在Rust中使用sqlx构建安全的动态查询?

5

sqlx有一个查询生成器。文档可以在这里查看。

我发现它支持动态构建以下形式的查询:

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

但我对构建更复杂的查询很感兴趣,例如:

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

其中任何一个where子句都是可选的。因此,以下内容也应该是动态构建的。

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

我似乎找不到除了手动拼接where字符串之外,使用sqlx完成这个操作的方法。


你目前尝试了什么? - matiaslauriti
手动连接 where 字符串。 - Finlay Weber
1
你现有的“手动连接”代码是什么样的?它使用pushpush_bind吗?还是你在手动处理字符串? - PitaJ
我认为pushpush_bind不能用于构建形如“where field :condition value”的查询,特别是当谓词可以是可选的时候。 - Finlay Weber
1
相反,我所看到的一切都非常通用。当然,某些示例更具体,但它们并不是关于pushpush_bind的。即使是这样,这些只是一个常见用例的示例。请尝试一下。 - PitaJ
显示剩余4条评论
1个回答

12

我在本地使以下内容正常工作。当然,我没有你的数据库,但构建的 SQL 看起来是正确的。我只是选择了 postgres,因为你没有指定你实际使用的数据库。

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"
}

我没有将id参数设为可选的,但我相信如果没有提供参数,你可以想办法省略where


1
谢谢。我的困惑源于调用.sql时打印出来的SQL查询语句。我能看到绑定变量,但是没有包括值的部分。显然这是内置的。 - Finlay Weber
“我该如何将数组绑定到VALUES()子句?我该如何进行批量插入?”官方FAQ中的内容也可能作为替代方法非常有用 https://github.com/launchbadge/sqlx/blob/main/FAQ.md#how-can-i-bind-an-array-to-a-values-clause-how-can-i-do-bulk-inserts - BinaryButterfly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接