Skip to content

Commit 2cd6c79

Browse files
committed
Change associations to a Macros 1.1 compatible API
This does not re-implement associations to use Macros 1.1, but does include the API change that will be required for them eventually. Macros 1.1 *only* supports custom derive. We can do something crazy and dumb to make bang macros work, but we cannot represent non-derive annotations. `#[as_changeset]` and `#[insertable_into]` can both be represented nicely as derives, but associations cannot individually be represented that way. So as a workaround we'll just leave the annotations separate and require `#[derive(Associations)]` to kick things off. I have made this change for both syntex and nightly even though only nightly requires it, as I want to keep those APIs in sync and deprecate syntex once Macros 1.1 is on a path to stabilization. The actual implementation is pretty straightforward, as we're just looping through the attributes and calling out to what the macro system would have called out to previously.
1 parent b7d499b commit 2cd6c79

11 files changed

Lines changed: 55 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
2121

2222
[bash completion]: https://github.com/diesel-rs/diesel/blob/b1a0d9901f0f2a8c8d530ccba8173b57f332b891/diesel_cli/README.md#bash-completion
2323

24+
### Changed
25+
26+
* Structs annotated with `#[has_many]` or `#[belongs_to]` now require
27+
`#[derive(Associations)]`. This is to allow them to work with Macros 1.1.
28+
2429
### Fixed
2530

2631
* `diesel migrations run` will now respect migration directories overridden by

diesel/src/associations/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
//! `#[belongs_to]`.
1515
//!
1616
//! ```ignore
17-
//! #[derive(Identifiable, Queryable)]
17+
//! #[derive(Identifiable, Queryable, Associations)]
1818
//! #[has_many(posts)]
1919
//! pub struct User {
2020
//! id: i32,
2121
//! name: String,
2222
//! }
2323
//!
24-
//! #[derive(Identifiable, Queryable)]
24+
//! #[derive(Identifiable, Queryable, Associations)]
2525
//! #[belongs_to(User)]
2626
//! pub struct Post {
2727
//! id: i32,
@@ -30,6 +30,9 @@
3030
//! }
3131
//! ```
3232
//!
33+
//! Note that in addition to the `#[has_many]` and `#[belongs_to]` annotations, we also need to
34+
//! `#[derive(Associations)]`
35+
//!
3336
//! `#[has_many]` should be passed the name of the table that the children will be loaded from,
3437
//! while `#[belongs_to]` is given the name of the struct that represents the parent. Both types
3538
//! must implement the [`Identifiable`][identifiable] trait.

diesel_codegen/src/lib.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ use diesel_codegen_syntex::*;
1010
pub fn register(reg: &mut rustc_plugin::Registry) {
1111
use syntax::parse::token::intern;
1212
use syntax::ext::base::MultiDecorator;
13+
reg.register_syntax_extension(
14+
intern("derive_Associations"),
15+
MultiDecorator(Box::new(associations::expand_derive_associations)),
16+
);
1317
reg.register_syntax_extension(
1418
intern("derive_Queryable"),
1519
MultiDecorator(Box::new(queryable::expand_derive_queryable))
@@ -26,14 +30,6 @@ pub fn register(reg: &mut rustc_plugin::Registry) {
2630
intern("changeset_for"),
2731
MultiDecorator(Box::new(update::expand_changeset_for)),
2832
);
29-
reg.register_syntax_extension(
30-
intern("has_many"),
31-
MultiDecorator(Box::new(associations::expand_has_many))
32-
);
33-
reg.register_syntax_extension(
34-
intern("belongs_to"),
35-
MultiDecorator(Box::new(associations::expand_belongs_to))
36-
);
3733
reg.register_macro("embed_migrations", migrations::expand_embed_migrations);
3834
reg.register_macro("infer_table_from_schema", schema_inference::expand_load_table);
3935
reg.register_macro("infer_schema", schema_inference::expand_infer_schema);

diesel_codegen_syntex/src/associations/mod.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,26 @@ use model::{infer_association_name, Model};
99
mod has_many;
1010
mod belongs_to;
1111

12-
pub use self::has_many::expand_has_many;
13-
pub use self::belongs_to::expand_belongs_to;
12+
use self::has_many::expand_has_many;
13+
use self::belongs_to::expand_belongs_to;
14+
15+
pub fn expand_derive_associations(
16+
cx: &mut ExtCtxt,
17+
span: Span,
18+
_: &MetaItem,
19+
annotatable: &Annotatable,
20+
push: &mut FnMut(Annotatable)
21+
) {
22+
for attr in annotatable.attrs() {
23+
if attr.check_name("has_many") {
24+
expand_has_many(cx, span, &attr.node.value, annotatable, push);
25+
}
26+
27+
if attr.check_name("belongs_to") {
28+
expand_belongs_to(cx, span, &attr.node.value, annotatable, push);
29+
}
30+
}
31+
}
1432

1533
fn parse_association_options(
1634
association_kind: &str,

diesel_codegen_syntex/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@ pub fn register(reg: &mut syntex::Registry) {
3030

3131
reg.add_decorator("derive_Queryable", queryable::expand_derive_queryable);
3232
reg.add_decorator("derive_Identifiable", identifiable::expand_derive_identifiable);
33+
reg.add_decorator("derive_Associations", associations::expand_derive_associations);
3334
reg.add_decorator("insertable_into", insertable::expand_insert);
3435
reg.add_decorator("changeset_for", update::expand_changeset_for);
35-
reg.add_decorator("has_many", associations::expand_has_many);
36-
reg.add_decorator("belongs_to", associations::expand_belongs_to);
3736
reg.add_macro("embed_migrations", migrations::expand_embed_migrations);
3837
reg.add_macro("infer_table_from_schema", schema_inference::expand_load_table);
3938
reg.add_macro("infer_schema", schema_inference::expand_infer_schema);

diesel_codegen_syntex/src/util.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ pub fn ident_value_of_attr_with_name(
6767
.and_then(|a| single_arg_value_of_attr(cx, &a, name))
6868
}
6969

70+
#[cfg(feature = "with-syntex")]
71+
const KNOWN_ATTRIBUTES: &'static [&'static str] = &[
72+
"table_name",
73+
"column_name",
74+
"has_many",
75+
"belongs_to",
76+
];
77+
7078
#[cfg(feature = "with-syntex")]
7179
pub fn strip_attributes(krate: ast::Crate) -> ast::Crate {
7280
use syntax::fold;
@@ -75,7 +83,7 @@ pub fn strip_attributes(krate: ast::Crate) -> ast::Crate {
7583

7684
impl fold::Folder for StripAttributeFolder {
7785
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
78-
if attr.check_name("table_name") || attr.check_name("column_name") {
86+
if KNOWN_ATTRIBUTES.iter().any(|name| attr.check_name(name)) {
7987
None
8088
} else {
8189
Some(attr)

diesel_tests/tests/annotations.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use schema::*;
66
// impls
77
// #[test]
88
// fn association_where_struct_name_doesnt_match_table_name() {
9-
// #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable)]
9+
// #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
1010
// #[belongs_to(Post)]
1111
// #[table_name(comments)]
1212
// struct OtherComment {
@@ -29,7 +29,7 @@ use schema::*;
2929

3030
#[test]
3131
fn association_where_parent_and_child_have_underscores() {
32-
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable)]
32+
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
3333
#[has_many(special_comments)]
3434
#[belongs_to(User)]
3535
pub struct SpecialPost {
@@ -53,7 +53,7 @@ fn association_where_parent_and_child_have_underscores() {
5353
}
5454
}
5555

56-
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable)]
56+
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
5757
#[belongs_to(SpecialPost)]
5858
struct SpecialComment {
5959
id: i32,
@@ -107,13 +107,13 @@ mod associations_can_have_nullable_foreign_keys {
107107
}
108108
// This test has no assertions, as it is for compilation purposes only.
109109
#[has_many(bars)]
110-
#[derive(Identifiable)]
110+
#[derive(Identifiable, Associations)]
111111
pub struct Foo {
112112
id: i32,
113113
}
114114

115115
#[belongs_to(Foo)]
116-
#[derive(Identifiable)]
116+
#[derive(Identifiable, Associations)]
117117
pub struct Bar {
118118
id: i32,
119119
foo_id: Option<i32>,
@@ -151,7 +151,7 @@ mod custom_foreign_keys_are_respected_on_belongs_to {
151151

152152
table! { special_posts { id -> Integer, author_id -> Integer, } }
153153

154-
#[derive(Identifiable)]
154+
#[derive(Identifiable, Associations)]
155155
#[belongs_to(User, foreign_key = "author_id")]
156156
pub struct SpecialPost {
157157
id: i32,

diesel_tests/tests/associations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ mod eager_loading_with_string_keys {
4747
id: String,
4848
}
4949

50-
#[derive(Queryable, Identifiable, Debug, PartialEq, Clone)]
50+
#[derive(Queryable, Identifiable, Debug, PartialEq, Clone, Associations)]
5151
#[belongs_to(User)]
5252
pub struct Post {
5353
id: String,

diesel_tests/tests/postgres_specific_schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{User, posts, comments};
22

3-
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable)]
3+
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
44
#[has_many(comments)]
55
#[belongs_to(User)]
66
pub struct Post {

diesel_tests/tests/schema.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use diesel::*;
22

33
infer_schema!(dotenv!("DATABASE_URL"));
44

5-
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable)]
5+
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
66
#[changeset_for(users)]
77
#[insertable_into(users)]
88
#[has_many(posts)]
@@ -30,7 +30,7 @@ impl User {
3030
}
3131
}
3232

33-
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable)]
33+
#[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
3434
#[belongs_to(Post)]
3535
pub struct Comment {
3636
id: i32,

0 commit comments

Comments
 (0)