Skip to content

Commit 092b226

Browse files
authored
Merge pull request diesel-rs#948 from diesel-rs/sg-rm-has-many
Remove `#[has_many]`, it has become useless
2 parents f956c6d + 6374b36 commit 092b226

26 files changed

Lines changed: 126 additions & 209 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
3434
* Trait bounds along the lines of `T: LoadDsl<Conn>, U: Queryable<T::SqlType,
3535
Conn::Backend>` should be changed to `T: LoadQuery<Conn, U>`.
3636

37+
### Removed
38+
39+
* `#[has_many]` has been removed. Its functionality is now provided by
40+
`#[belongs_to]` on the child struct. If there is no child struct to
41+
put `#[belongs_to]` on, you can invoke `joinable!` directly instead.
42+
3743
## [0.13.0] - 2017-05-15
3844

3945
### Added

diesel/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ ipnetwork = { version = "0.12.2", optional = true }
2828

2929
[dev-dependencies]
3030
cfg-if = "0.1.0"
31-
diesel_codegen = "0.12.0"
31+
diesel_codegen = "0.13.0"
3232
dotenv = ">=0.8, <0.11"
3333
quickcheck = "0.3.1"
3434
tempdir = "^0.3.4"

diesel/src/associations/mod.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! `#[macro_use] extern crate diesel_codegen;` at the root of your crate.
1313
//!
1414
//! Associations in Diesel are bidirectional, but primarily focus on the child-to-parent
15-
//! relationship. You can declare an association between two records with `#[has_many]` and
15+
//! relationship. You can declare an association between two records with
1616
//! `#[belongs_to]`.
1717
//!
1818
//! ```rust
@@ -23,8 +23,7 @@
2323
//! # include!("src/doctest_setup.rs");
2424
//! use schema::{posts, users};
2525
//!
26-
//! #[derive(Identifiable, Queryable, Associations)]
27-
//! #[has_many(posts)]
26+
//! #[derive(Identifiable, Queryable)]
2827
//! pub struct User {
2928
//! id: i32,
3029
//! name: String,
@@ -47,24 +46,19 @@
4746
//! # }
4847
//! ```
4948
//!
50-
//! Note that in addition to the `#[has_many]` and `#[belongs_to]` annotations, we also need to
49+
//! Note that in addition to the `#[belongs_to]` annotation, we also need to
5150
//! `#[derive(Associations)]`
5251
//!
53-
//! `#[has_many]` should be passed the name of the table that the children will be loaded from,
54-
//! while `#[belongs_to]` is given the name of the struct that represents the parent. Both types
52+
//! `#[belongs_to]` is given the name of the struct that represents the parent. Both types
5553
//! must implement the [`Identifiable`][identifiable] trait. The struct or table referenced in your
5654
//! association has to be in scope, so you'll need `use schema::posts` or similar to bring the
5755
//! table into scope, and `use some_module::User` if `User` were in a different module.
5856
//!
5957
//! [Identifiable]: trait.Identifiable.html
6058
//!
6159
//! If the name of your foreign key doesn't follow the convention `tablename_id`, you can specify a
62-
//! custom one to `#[has_many]` and `#[belongs_to]` by adding a `foreign_key` argument to the
63-
//! attribute like so `#[has_many, foreign_key="mykey"]`.
64-
//!
65-
//! `#[has_many]` actually has no behavior on its own. It only enables joining between the two
66-
//! tables. If you are only writing `children.inner_join(parents)` or
67-
//! `Child::belonging_to(&parents)`, you only need to define the `#[belongs_to]` side.
60+
//! custom one to `#[belongs_to]` by adding a `foreign_key` argument to the
61+
//! attribute like so `#[belongs_to(Foo, foreign_key="mykey")]`.
6862
//!
6963
//! Once the associations are defined, you can join between the two tables using the
7064
//! [`inner_join`][inner-join] or [`left_outer_join`][left-outer-join].

diesel/src/macros/associations/belongs_to.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,14 @@ macro_rules! BelongsTo {
235235
primary_key_ty = <<$parent_struct as $crate::associations::HasTable>::Table as $crate::Table>::PrimaryKey,
236236
primary_key_expr = $crate::Table::primary_key(&<$parent_struct as $crate::associations::HasTable>::table()),
237237
);
238+
joinable_inner!(
239+
left_table_ty = $child_table_name::table,
240+
right_table_ty = $crate::query_source::joins::PleaseGenerateInverseJoinImpls<<$parent_struct as $crate::associations::HasTable>::Table>,
241+
right_table_expr = <$parent_struct as $crate::associations::HasTable>::table(),
242+
foreign_key = $child_table_name::$foreign_key_name,
243+
primary_key_ty = <<$parent_struct as $crate::associations::HasTable>::Table as $crate::Table>::PrimaryKey,
244+
primary_key_expr = $crate::Table::primary_key(&<$parent_struct as $crate::associations::HasTable>::table()),
245+
);
238246
});
239247
};
240248

diesel/src/macros/associations/has_many.rs

Lines changed: 0 additions & 122 deletions
This file was deleted.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
#[macro_use] mod belongs_to;
2-
#[macro_use] mod has_many;

diesel/src/macros/mod.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,13 @@ macro_rules! table_body {
325325
use $crate::{
326326
QuerySource,
327327
Table,
328+
JoinTo,
328329
};
329330
use $crate::associations::HasTable;
330331
use $crate::query_builder::*;
331332
use $crate::query_builder::nodes::Identifier;
332-
use $crate::query_source::{AppearsInFromClause, Once};
333+
use $crate::query_source::{AppearsInFromClause, Once, Never};
334+
use $crate::query_source::joins::PleaseGenerateInverseJoinImpls;
333335
$(use $($import)::+;)+
334336
pub use self::columns::*;
335337

@@ -413,6 +415,22 @@ macro_rules! table_body {
413415
type Count = Once;
414416
}
415417

418+
impl<T> AppearsInFromClause<T> for table where
419+
T: Table + JoinTo<table>,
420+
{
421+
type Count = Never;
422+
}
423+
424+
impl<T> JoinTo<T> for table where
425+
T: JoinTo<table> + JoinTo<PleaseGenerateInverseJoinImpls<table>>,
426+
{
427+
type JoinOnClause = <T as JoinTo<table>>::JoinOnClause;
428+
429+
fn join_on_clause() -> Self::JoinOnClause {
430+
<T as JoinTo<table>>::join_on_clause()
431+
}
432+
}
433+
416434
impl_query_id!(table);
417435

418436
/// Contains all of the columns of this table
@@ -560,9 +578,6 @@ macro_rules! joinable_inner {
560578
primary_key_ty = $primary_key_ty:ty,
561579
primary_key_expr = $primary_key_expr:expr,
562580
) => {
563-
impl $crate::query_source::AppearsInFromClause<$right_table_ty> for $left_table_ty {
564-
type Count = $crate::query_source::Never;
565-
}
566581
impl $crate::JoinTo<$right_table_ty> for $left_table_ty {
567582
type JoinOnClause = $crate::expression::helper_types::Eq<
568583
$crate::expression::nullable::Nullable<$foreign_key>,

diesel/src/query_source/joins.rs

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -225,36 +225,6 @@ impl<DB: Backend> QueryFragment<DB> for LeftOuter {
225225
}
226226
}
227227

228-
impl<T, From> JoinTo<SelectStatement<From>> for T where
229-
T: Table + JoinTo<From>,
230-
{
231-
type JoinOnClause = T::JoinOnClause;
232-
233-
fn join_on_clause() -> Self::JoinOnClause {
234-
T::join_on_clause()
235-
}
236-
}
237-
238-
impl<T, Join, On> JoinTo<JoinOn<Join, On>> for T where
239-
T: Table + JoinTo<Join>,
240-
{
241-
type JoinOnClause = T::JoinOnClause;
242-
243-
fn join_on_clause() -> Self::JoinOnClause {
244-
T::join_on_clause()
245-
}
246-
}
247-
248-
impl<Left, Mid, Right, Kind> JoinTo<Join<Mid, Right, Kind>> for Left where
249-
Left: Table + JoinTo<Mid>,
250-
{
251-
type JoinOnClause = Left::JoinOnClause;
252-
253-
fn join_on_clause() -> Self::JoinOnClause {
254-
Left::join_on_clause()
255-
}
256-
}
257-
258228
impl<Left, Mid, Right, Kind> JoinTo<Right> for Join<Left, Mid, Kind> where
259229
Left: JoinTo<Right>,
260230
{
@@ -275,7 +245,6 @@ impl<Join, On, Right> JoinTo<Right> for JoinOn<Join, On> where
275245
}
276246
}
277247

278-
279248
use super::{Succ, Never, AppearsInFromClause};
280249

281250
impl<T, Left, Right, Kind> AppearsInFromClause<T> for Join<Left, Right, Kind> where
@@ -292,6 +261,22 @@ impl<T, Join, On> AppearsInFromClause<T> for JoinOn<Join, On> where
292261
type Count = Join::Count;
293262
}
294263

264+
#[allow(missing_debug_implementations, missing_copy_implementations)]
265+
#[doc(hidden)]
266+
/// A hack to allow bidirectional joins to be generated from `#[belongs_to]`
267+
///
268+
/// This type needs to exist because it is illegal in Rust today to write
269+
/// `impl JoinTo<posts> for <User as HasTable>::Table`, even though the type
270+
/// is fully monomorphic and projects to a local type. If this restriction
271+
/// were ever lifted in the future, this type could be removed.
272+
///
273+
/// Instead, after generating `impl JoinTo<<User as HasTable>::Table> for
274+
/// posts`, we *also* generate `impl JoinTo<PleaseGenerateInverseJoinImpls<<User
275+
/// as HasTable>::table> for posts`, and rely on the fact that `users::table`
276+
/// will have a blanket impl on itself for anything that joins to
277+
/// `PleaseGenerateInverseJoinImpls`.
278+
pub struct PleaseGenerateInverseJoinImpls<T>(T);
279+
295280
pub trait Plus<T> {
296281
type Output;
297282
}

diesel_codegen/src/associations.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ pub fn derive_associations(input: syn::MacroInput) -> quote::Tokens {
99
let model = t!(Model::from_item(&input, "Associations"));
1010

1111
for attr in input.attrs.as_slice() {
12-
if attr.name() == "has_many" {
13-
let options = t!(build_association_options(attr, "has_many"));
14-
derived_associations.push(expand_has_many(&model, options))
15-
}
16-
1712
if attr.name() == "belongs_to" {
1813
let options = t!(build_association_options(attr, "belongs_to"));
1914
derived_associations.push(expand_belongs_to(&model, options))
@@ -43,23 +38,6 @@ fn expand_belongs_to(model: &Model, options: AssociationOptions) -> quote::Token
4338
})
4439
}
4540

46-
fn expand_has_many(model: &Model, options: AssociationOptions) -> quote::Tokens {
47-
let parent_table_name = model.table_name();
48-
let child_table_name = options.name;
49-
let foreign_key_name = options.foreign_key_name.unwrap_or_else(||
50-
to_foreign_key(model.name.as_ref()));
51-
let fields = model.attrs.as_slice();
52-
53-
quote!(HasMany! {
54-
(
55-
parent_table_name = #parent_table_name,
56-
child_table = #child_table_name::table,
57-
foreign_key = #child_table_name::#foreign_key_name,
58-
),
59-
fields = [#(#fields)*],
60-
})
61-
}
62-
6341
struct AssociationOptions {
6442
name: syn::Ident,
6543
foreign_key_name: Option<syn::Ident>,

diesel_codegen/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ pub fn derive_as_changeset(input: TokenStream) -> TokenStream {
7171
expand_derive(input, as_changeset::derive_as_changeset)
7272
}
7373

74-
#[proc_macro_derive(Associations, attributes(table_name, has_many, belongs_to))]
74+
#[proc_macro_derive(Associations, attributes(table_name, belongs_to))]
7575
pub fn derive_associations(input: TokenStream) -> TokenStream {
7676
expand_derive(input, associations::derive_associations)
7777
}

0 commit comments

Comments
 (0)