Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upAssociations: what should they look like? #89
Comments
sgrif
added
enhancement
discussion desired
labels
Jan 12, 2016
sgrif
added this to the 0.5 milestone
Jan 12, 2016
This comment has been minimized.
|
@mfpiccolo @mikeastock @samphippen @mcasper Would like to get some discussion going on this. |
sgrif
referenced this issue
Jan 12, 2016
Merged
Allow structs to be annotated with `#[table_name="foo"]` #87
This comment has been minimized.
|
Thanks for putting this together @sgrif. One to many: Currently we have: What you have here makes sense to me as well: |
This comment has been minimized.
|
I'm moving this to 0.6, as SQLite support is more immediately actionable. |
sgrif
modified the milestones:
0.6,
0.5
Jan 23, 2016
chasinglogic
referenced this issue
Apr 15, 2016
Closed
There is currently no documentation on defining relationships. #270
This comment has been minimized.
|
The first pass was released in 0.7, but I'm leaving this open as I think there's still more work to be done. |
sgrif
removed this from the 0.7 milestone
Aug 11, 2016
Eijebong
referenced this issue
Feb 4, 2017
Closed
Multiple foreign keys with #[belongs_to], conflicting implementations of trait #616
This comment has been minimized.
beefsack
commented
Apr 20, 2017
|
Have been using the current iteration of associations and has been working really well in my testing. One case I'm not sure the current implementation covers is as below; having multiple #[derive(Debug, PartialEq, Clone, Queryable, Identifiable, Associations)]
#[belongs_to(User, foreign_key="source_user_id")]
#[belongs_to(User, foreign_key="target_user_id")]
pub struct Friend {
pub id: Uuid,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub source_user_id: Uuid,
pub target_user_id: Uuid,
pub has_accepted: Option<bool>,
}The error is:
I'm not seeing these sorts of relationships defined in the issue description so thought I would bring it up. |
This was referenced Jun 3, 2017
sgrif
closed this
in
#933
Jun 5, 2017
This comment has been minimized.
sbstp
commented
Mar 19, 2018
|
I don't think that what @beefsack pointed out has been fixed. Here's what I'm trying to do and the error I get #[macro_use]
extern crate diesel;
use diesel::prelude::*;
mod schema {
table! {
humans {
id -> Integer,
name -> VarChar,
father_id -> Integer,
mother_id -> Integer,
}
}
}
use schema::*;
#[derive(PartialEq, Debug, Associations, Identifiable, Queryable)]
#[belongs_to(Human, foreign_key = "father_id")]
#[belongs_to(Human, foreign_key = "mother_id")]
struct Human {
id: i32,
name: String,
father_id: i32,
mother_id: i32,
}
|
This comment has been minimized.
Raytlty
commented
Oct 13, 2018
|
@sbstp I wonder if there are any solutions for this problem. THANKS. |
This comment has been minimized.
sbstp
commented
Oct 13, 2018
|
@Raytlty I think there is. Just newtype the Human struct as two different strucs like so: |
This comment has been minimized.
Raytlty
commented
Oct 15, 2018
|
@sbstp Thanks, I just test it and it work! |
sgrif commentedJan 12, 2016
Let's talk about associations. First what's in the public API today, what's in the private API today, and what they actually need to do. We can use those things to drive what the API should look like.
Public API today
Right now
Tablehasinner_joinandleft_outer_joinwhich can take any other table which implementsJoinTo. This is limited to exactly one table today, due to some limitations that I think will be resolved by specialization. There also needs to be some boilerplate implementations ofSelectableExpressionfor all the various types of query sources, which will go away when specialization (or rust-lang/rust#29864) lands and replaced with:This will also basically allow us to implement the join methods on the various join sources as well, though we might need to do some tuple hackery.
Private API today
The annotations
#[has_many]and#[belongs_to]are part of the internal API today. Both implementJoinToautomatically.belongs_toadditionally implementsBelongingToDsl<Parent>for the child. I wrote up some thoughts on where that is today at #86 (comment).What do Associations actually need to do?
Ultimately we're either eager loading the children for a collection of parents, or we're loading the children for a single parent. I believe that
BelongingTosufficiently handles the latter, but it'll effectively be handled by the former.One To Many
I'm pretty reasonably confident that associations should be non invasive (user doesn't know it has many posts). That means that the type of a user and all of its posts is
(User, Vec<Post>). This can get tricky when dealing with multiple levels of nesting here. For example, the type of a user, all the posts they've written, and all the comments written by that user is(User, Vec<Post>, Vec<Comment>). By contrast, the type of a user, all of the posts they've written, and all of the comments left on each of those posts would be(User, Vec<(Post, Vec<Comment>)>).I'd imagine the way to specify that you want to load the comments for the posts and not for the users is by writing
users.left_outer_join(posts.left_outer_join(comments))as opposed tousers.left_outer_join(posts).left_outer_join(comments).The case of a user and all of its posts would be written today as:
The case involving comments is effectively impossible today.
We do not need to have specific code to handle loading the children for a single record, as
Post::belonging_to(&user)is sufficient.It should also be noted that I don't want to restrict what you're able to work with. We should be able to get a user, and the title of all of their posts by doing
users.left_outer_joins(posts::table).select((users.all_columns(), posts::title)).One To One
The type of a one to one relationship is either
(A, B)or(A, Option<B>). Technically only abelongs_tocan be mandatory, but you can still end up with the first signature with an inner join. Regardless of if we're going child to parent or parent to child, the way this is written today is simply:users.inner_join(profile)And loading a single record is handled by
Post::belonging_to(&user). I do not believe we need any additional code to handle this case, but we could potentially rename the join methods to have parity with whatever we come up with for one to many.Composition
Associations should be composable. If we want to get all of the comments that have been written for any posts written by a user, we should be able to re-use our existing logic, without having to actually load the posts.