有没有办法在“sqlx::query!()”中使用动态查询

Inc*_*ete 8 rust rust-sqlx

上下文:rust、sqlx 库

问题:如何在不丢失类型检查的情况下从较小的部分组成类似的查询?

macro_rules! select {
  () => {"select col from tab"}
}

macro_rules! guard1 {
  () => {"where col > 1"}
}

macro_rules! guard2 {
  () => {"where col > 2"}
}

let mut conn = get_pg_connection_from_somewhere();

if some_condition() {
  sqlx::query!(select!() + guard1!()).fetch_all(&mut conn).await?;
} else {
  sqlx::query!(select!() + guard2!()).fetch_all(&mut conn).await?;
}
Run Code Online (Sandbox Code Playgroud)

文档说:

查询必须是字符串文字,或使用 + 连接字符串文字(对于宏生成的查询很有用),否则它无法进行内省(因此不能是动态的或另一个宏的结果)。

你可以看到它说“对于宏生成的查询有用”(尽管后来“不能是另一个宏的结果”)

我想解决的问题是,根据条件,我想运行不同但相似的(例如它们都具有相同的列)查询,并且我想从较小的可重用部分组成查询[

小智 2

您可以使用如下宏来完成此操作

macro_rules! fetch_all_todos_with_predicate {
    ($executor:ident, $predicate:tt) => {
        sqlx::query!(
            "SELECT id, title, completed_at FROM todos " + $predicate
        ).fetch_all($executor).await
    }
}
Run Code Online (Sandbox Code Playgroud)

并根据某些条件提供谓词

let kind = QueryKind::Complete;
let mut conn = get_pg_connection_from_somewhere();

let result = match kind {
    QueryKind::Complete => fetch_all_todos_with_predicate!(conn, "WHERE completed_at IS NOT NULL"),
    QueryKind::Incomplete => fetch_all_todos_with_predicate!(conn, "WHERE completed_at IS NULL"),
    QueryKind::All => fetch_all_todos_with_predicate!(conn, ""),
};
Run Code Online (Sandbox Code Playgroud)