5

上下文: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?;
}

文档说:

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

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

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

4

1 回答 1

1

您可以使用如下宏来执行此操作

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

并根据某些条件提供谓词

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, ""),
};
于 2021-04-04T15:39:51.113 回答