在 Diesel 中执行正确的连接
Performing a Right Join in Diesel
我有一个函数,它接受两个可选的过滤参数,如果提供了这些参数,它会过滤 table 中的数据。为此,我创建了一个盒装查询。我想用这个盒装查询创建一个右连接。 Diesel 目前的文档没有提到 right join,但它似乎更喜欢 belonging_to
方法。我已将我的代码缩减为一个示例:
#[macro_use] extern crate diesel;
use diesel::prelude::*;
table! {
groups (id) {
id -> Int4,
name -> Text,
}
}
table! {
user_groups (id) {
id -> Int4,
user_id -> Int4,
group_id -> Int4,
}
}
allow_tables_to_appear_in_same_query!(groups, user_groups);
#[derive(Debug, Queryable)]
struct Group {
id: i32,
name: String,
}
#[derive(Debug, Queryable, Associations)]
#[belongs_to(Group)]
struct UserGroup {
id: i32,
user_id: i32,
group_id: i32,
}
fn filter(
name: Option<&str>,
user_id: Option<i32>,
conn: &diesel::PgConnection,
) -> Result<Vec<(Group, Vec<UserGroup>)>, Box<dyn std::error::Error>> {
let mut query = groups::table
.right_join(user_groups::table.on(groups::id.eq(user_groups::group_id))) // this method does not exist
.into_boxed();
if let Some(name) = name {
query = query.filter(groups::name.eq(name));
}
if let Some(user_id) = user_id {
query = query.filter(user_groups::user_id.contains(user_id)); // so this is just a guess
}
Ok(query.get_results(conn)?)
}
fn main() {
let url = "postgres://question_usr:question_pwd:localhost:5432/question_db";
let conn = diesel::PgConnection::establish(url).unwrap();
let _ = filter(Some("groupname"), Some(4), &conn).unwrap();
}
目的是,如果指定参数 user_id
,则仅返回 Groups
行,其中至少有一个 UserGroup
满足 user_group.user_id == user_id
。我如何运行这个查询?我需要以某种方式使用 belonging_to
函数吗?
右连接在任何情况下都等同于具有倒置 table 顺序的左连接。 (参见 here for example). Therefore Diesel only provides functions to construct a LEFT JOIN
。
你的例子看起来像这样:
fn filter(
name: Option<&str>,
user_id: Option<i32>,
conn: &diesel::PgConnection,
) -> Result<Vec<(UserGroup, Option<Group>)>, Box<dyn std::error::Error>> {
let mut query = user_groups::table
.left_join(groups::table.on(groups::id.eq(user_groups::group_id))) /
.into_boxed();
if let Some(name) = name {
query = query.filter(groups::name.eq(name));
}
if let Some(user_id) = user_id {
query = query.filter(user_groups::user_id.eq(user_id));
}
Ok(query.get_results(conn)?)
}
请注意,此 returns 默认为 Vec<(UserGroup, Option<Group>)>
。如果您想要不同的东西,您需要编写一个自定义 select 子句来指定所需的结果形状。
我有一个函数,它接受两个可选的过滤参数,如果提供了这些参数,它会过滤 table 中的数据。为此,我创建了一个盒装查询。我想用这个盒装查询创建一个右连接。 Diesel 目前的文档没有提到 right join,但它似乎更喜欢 belonging_to
方法。我已将我的代码缩减为一个示例:
#[macro_use] extern crate diesel;
use diesel::prelude::*;
table! {
groups (id) {
id -> Int4,
name -> Text,
}
}
table! {
user_groups (id) {
id -> Int4,
user_id -> Int4,
group_id -> Int4,
}
}
allow_tables_to_appear_in_same_query!(groups, user_groups);
#[derive(Debug, Queryable)]
struct Group {
id: i32,
name: String,
}
#[derive(Debug, Queryable, Associations)]
#[belongs_to(Group)]
struct UserGroup {
id: i32,
user_id: i32,
group_id: i32,
}
fn filter(
name: Option<&str>,
user_id: Option<i32>,
conn: &diesel::PgConnection,
) -> Result<Vec<(Group, Vec<UserGroup>)>, Box<dyn std::error::Error>> {
let mut query = groups::table
.right_join(user_groups::table.on(groups::id.eq(user_groups::group_id))) // this method does not exist
.into_boxed();
if let Some(name) = name {
query = query.filter(groups::name.eq(name));
}
if let Some(user_id) = user_id {
query = query.filter(user_groups::user_id.contains(user_id)); // so this is just a guess
}
Ok(query.get_results(conn)?)
}
fn main() {
let url = "postgres://question_usr:question_pwd:localhost:5432/question_db";
let conn = diesel::PgConnection::establish(url).unwrap();
let _ = filter(Some("groupname"), Some(4), &conn).unwrap();
}
目的是,如果指定参数 user_id
,则仅返回 Groups
行,其中至少有一个 UserGroup
满足 user_group.user_id == user_id
。我如何运行这个查询?我需要以某种方式使用 belonging_to
函数吗?
右连接在任何情况下都等同于具有倒置 table 顺序的左连接。 (参见 here for example). Therefore Diesel only provides functions to construct a LEFT JOIN
。
你的例子看起来像这样:
fn filter(
name: Option<&str>,
user_id: Option<i32>,
conn: &diesel::PgConnection,
) -> Result<Vec<(UserGroup, Option<Group>)>, Box<dyn std::error::Error>> {
let mut query = user_groups::table
.left_join(groups::table.on(groups::id.eq(user_groups::group_id))) /
.into_boxed();
if let Some(name) = name {
query = query.filter(groups::name.eq(name));
}
if let Some(user_id) = user_id {
query = query.filter(user_groups::user_id.eq(user_id));
}
Ok(query.get_results(conn)?)
}
请注意,此 returns 默认为 Vec<(UserGroup, Option<Group>)>
。如果您想要不同的东西,您需要编写一个自定义 select 子句来指定所需的结果形状。