Skip to content

Commit

Permalink
Merge pull request #103 from mcasper/fix_foreign_key_inference
Browse files Browse the repository at this point in the history
Fix foreign key and module inference for multi word structs
  • Loading branch information
mcasper committed Jan 18, 2016
2 parents 519ba3d + d3665cc commit d4c472e
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 29 deletions.
14 changes: 13 additions & 1 deletion diesel_codegen/src/associations/belongs_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct BelongsToAssociationBuilder {
impl BelongsToAssociationBuilder {
fn parent_struct_name(&self) -> ast::Ident {
let association_name = self.options.name.name.as_str();
let struct_name = association_name[..1].to_uppercase() + &association_name[1..];
let struct_name = capitalize_from_association_name(association_name.to_string());
str_to_ident(&struct_name)
}

Expand Down Expand Up @@ -95,6 +95,18 @@ impl BelongsToAssociationBuilder {
}
}

fn capitalize_from_association_name(name: String) -> String {
let mut result = String::with_capacity(name.len());
let words = name.split("_");

for word in words {
result.push_str(&word[..1].to_uppercase());
result.push_str(&word[1..]);
}

result
}

impl ::std::ops::Deref for BelongsToAssociationBuilder {
type Target = aster::AstBuilder;

Expand Down
10 changes: 8 additions & 2 deletions diesel_codegen/src/associations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::parse::token::str_to_ident;

use model::Model;
use model::{infer_association_name, Model};

mod has_many;
mod belongs_to;
Expand Down Expand Up @@ -67,6 +67,12 @@ fn build_association_options(
}

fn to_foreign_key(model_name: &str) -> ast::Ident {
let lower_cased = model_name.to_lowercase();
let lower_cased = infer_association_name(model_name);
str_to_ident(&format!("{}_id", &lower_cased))
}

#[test]
fn to_foreign_key_properly_handles_underscores() {
assert_eq!("foo_bar_id", &to_foreign_key("FooBar"));
assert_eq!("foo_bar_baz_id", &to_foreign_key("FooBarBaz"));
}
7 changes: 6 additions & 1 deletion diesel_codegen/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl Model {
}
}

fn infer_table_name(name: &str) -> String {
pub fn infer_association_name(name: &str) -> String {
let mut result = String::with_capacity(name.len());
result.push_str(&name[..1].to_lowercase());
for character in name[1..].chars() {
Expand All @@ -69,6 +69,11 @@ fn infer_table_name(name: &str) -> String {
result.push(character);
}
}
result
}

fn infer_table_name(name: &str) -> String {
let mut result = infer_association_name(name);
result.push('s');
result
}
Expand Down
88 changes: 88 additions & 0 deletions diesel_tests/tests/annotations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use diesel::*;
use schema::*;

#[test]
fn association_where_struct_name_doesnt_match_table_name() {
#[derive(PartialEq, Eq, Debug, Clone, Queryable)]
#[belongs_to(post)]
#[table_name="comments"]
struct OtherComment {
id: i32,
post_id: i32
}

let connection = connection_with_sean_and_tess_in_users_table();

let sean = find_user_by_name("Sean", &connection);
let post: Post = insert(&sean.new_post("Hello", None)).into(posts::table)
.get_result(&connection).unwrap();
insert(&NewComment(post.id, "comment")).into(comments::table)
.execute(&connection).unwrap();

let comment_text = OtherComment::belonging_to(&post).select(comments::text)
.first::<String>(&connection);
assert_eq!(Ok("comment".into()), comment_text);
}


#[test]
fn association_where_parent_and_child_have_underscores() {
#[derive(PartialEq, Eq, Debug, Clone, Queryable)]
#[has_many(special_comments)]
#[belongs_to(user)]
struct SpecialPost {
id: i32,
user_id: i32,
title: String
}

#[insertable_into(special_posts)]
struct NewSpecialPost {
user_id: i32,
title: String
}

impl SpecialPost {
fn new(user_id: i32, title: &str) -> NewSpecialPost {
NewSpecialPost {
user_id: user_id,
title: title.to_owned()
}
}
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable)]
#[belongs_to(special_post)]
struct SpecialComment {
id: i32,
special_post_id: i32,
}

impl SpecialComment {
fn new(special_post_id: i32) -> NewSpecialComment {
NewSpecialComment {
special_post_id: special_post_id
}
}
}

#[insertable_into(special_comments)]
struct NewSpecialComment {
special_post_id: i32
}

let connection = connection_with_sean_and_tess_in_users_table();

let sean = find_user_by_name("Sean", &connection);
let new_post = SpecialPost::new(sean.id, "title");
let special_post: SpecialPost = insert(&new_post).into(special_posts::table)
.get_result(&connection).unwrap();
let new_comment = SpecialComment::new(special_post.id);
insert(&new_comment).into(special_comments::table)
.execute(&connection).unwrap();

let comment: SpecialComment = SpecialComment::belonging_to(&special_post)
.first(&connection).unwrap();

assert_eq!(special_post.id, comment.special_post_id);
}
15 changes: 0 additions & 15 deletions diesel_tests/tests/associations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,3 @@ fn one_to_many_returns_query_source_for_association() {
let found_posts: Vec<_> = Post::belonging_to(&tess).load(&connection).unwrap().collect();
assert_eq!(tess_posts, found_posts);
}

#[test]
fn association_where_struct_name_doesnt_match_table_name() {
let connection = connection_with_sean_and_tess_in_users_table();

let sean = find_user_by_name("Sean", &connection);
let post: Post = insert(&sean.new_post("Hello", None)).into(posts::table)
.get_result(&connection).unwrap();
insert(&NewComment(post.id, "comment")).into(comments::table)
.execute(&connection).unwrap();

let comment_text = SpecialComment::belonging_to(&post).select(comments::text)
.first::<String>(&connection);
assert_eq!(Ok("comment".into()), comment_text);
}
5 changes: 3 additions & 2 deletions diesel_tests/tests/lib.in.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod schema;
mod insert;
mod annotations;
mod deserialization;
mod insert;
mod schema;
mod update;
8 changes: 0 additions & 8 deletions diesel_tests/tests/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,6 @@ pub struct Comment {
text: String,
}

#[derive(PartialEq, Eq, Debug, Clone, Queryable)]
#[belongs_to(post)]
#[table_name="comments"]
pub struct SpecialComment {
id: i32,
post_id: i32,
}

infer_schema!(dotenv!("DATABASE_URL"));
numeric_expr!(users::id);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DROP TABLE special_posts;
DROP TABLE special_comments;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE TABLE special_posts (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
title VARCHAR NOT NULL
);

CREATE TABLE special_comments (
id SERIAL PRIMARY KEY,
special_post_id INTEGER NOT NULL
);

0 comments on commit d4c472e

Please sign in to comment.