require File.join(File.dirname(__FILE__), 'spec_helper') describe 'implicit joins' do before do TestModel.extended_models.each { |model| model.last_find = {} } end describe 'on belongs_to' do describe 'with single condition inline' do before do Post.filter do having(:blog).with :name, 'Test Name' end.inspect end it 'should add correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "blogs" AS posts__blog ON "posts".blog_id = posts__blog.id)] end it 'should query against condition on join table' do Post.last_find[:conditions].should == ['posts__blog.name = ?', 'Test Name'] end end shared_examples_for 'multiple conditions on single join' do it 'should add join once' do Post.last_find[:joins].should == [%q(INNER JOIN "blogs" AS posts__blog ON "posts".blog_id = posts__blog.id)] end it 'should query against conditions on join table' do Post.last_find[:conditions].should == [%q((posts__blog.name = ?) AND (posts__blog.published = ?)), 'Test Name', true] end end describe 'with multiple conditions on single join inline' do before do Post.filter do having(:blog).with :name, 'Test Name' having(:blog).with :published, true end.inspect end it_should_behave_like 'multiple conditions on single join' end describe 'with multiple conditions on a single join in a block' do before do Post.filter do having :blog do with :name, 'Test Name' with :published, true end end.inspect end it_should_behave_like 'multiple conditions on single join' end end describe 'on has_many' do before do Blog.filter do having(:posts).with :permalink, 'test-post' end.inspect end it 'should add correct join' do Blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id)] end it 'should query against condition on join table' do Blog.last_find[:conditions].should == [%q(blogs__posts.permalink = ?), 'test-post'] end end describe 'with multiple joins' do before do Blog.filter do having(:posts) do with :permalink, 'test-post' having(:comments).with :offensive, true end end.inspect end it 'should add both joins' do Blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id), %q(INNER JOIN "comments" AS blogs__posts__comments ON blogs__posts.id = blogs__posts__comments.post_id)] end it 'should query against both conditions' do Blog.last_find[:conditions].should == [%q((blogs__posts.permalink = ?) AND (blogs__posts__comments.offensive = ?)), 'test-post', true] end end describe 'with one having statement expressing multiple joins' do before do Blog.filter do having(:posts => :comments) do with :offensive, true end end.inspect end it 'should add both joins' do Blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id), %q(INNER JOIN "comments" AS blogs__posts__comments ON blogs__posts.id = blogs__posts__comments.post_id)] end it 'should query against both conditions' do Blog.last_find[:conditions].should == [%q(blogs__posts__comments.offensive = ?), true] end end describe 'on has_one' do before do Post.filter do having(:photo).with :format, 'jpg' end.inspect end it 'should add correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "photos" AS posts__photo ON "posts".id = posts__photo.post_id)] end it 'should query against condition on join table' do Post.last_find[:conditions].should == ['posts__photo.format = ?', 'jpg'] end end describe 'with nested joins' do before do Blog.filter do having(:posts).having(:photo).with :format, 'png' end.inspect end it 'should add correct join' do Blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id), %q(INNER JOIN "photos" AS blogs__posts__photo ON blogs__posts.id = blogs__posts__photo.post_id)] end it 'should query against condition on join table' do Blog.last_find[:conditions].should == ['blogs__posts__photo.format = ?', 'png'] end end describe 'with has and belongs to many joins' do before do Post.filter do having(:tags).with :name, 'activerecord' end.inspect end it 'should add correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "posts_tags" AS __posts__tags ON "posts".id = __posts__tags.post_id), %q(INNER JOIN "tags" AS posts__tags ON __posts__tags.tag_id = posts__tags.id)] end end describe 'with negative conditions' do before do Comment.filter do with :offensive, false end.inspect end it 'should create the correct condition' do Comment.last_find[:conditions].should == [%q("comments".offensive = ?), false] end end describe 'with nil conditions' do before do Comment.filter do with :contents, nil with :offensive, true end.inspect end it 'should create the correct IS NULL condition' do Comment.last_find[:conditions].should == [%q(("comments".contents IS NULL) AND ("comments".offensive = ?)), true] end end describe 'with negated conditions' do before do Comment.filter do with(:offensive).not(false) end.inspect end it 'should create the correct condition' do Comment.last_find[:conditions].should == [%q("comments".offensive <> ?), false] end end describe 'with negated nil conditions' do before do Comment.filter do with(:contents).not(nil) with :offensive, true end.inspect end it 'should create the correct IS NOT NULL condition' do Comment.last_find[:conditions].should == [%q(("comments".contents IS NOT NULL) AND ("comments".offensive = ?)), true] end end describe 'with negated nil conditions using is_null' do before do Comment.filter do with(:contents).not.is_null with :offensive, true end.inspect end it 'should create the correct IS NOT NULL condition' do Comment.last_find[:conditions].should == [%q(("comments".contents IS NOT NULL) AND ("comments".offensive = ?)), true] end end describe 'passing the join type to having' do before do Blog.filter do having(:posts, :join_type => :left) do with(:permalink, 'ack') end end.inspect end it 'should create the correct condition' do Blog.last_find[:conditions].should == [%q(blogs__posts.permalink = ?), 'ack'] end it 'should create the correct join' do Blog.last_find[:joins].should == [%q(LEFT OUTER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id)] end end describe 'passing the join type to having with multiple joins' do before do Blog.filter do having({ :posts => :comments }, :join_type => :left) do with(:offensive, true) end end.inspect end it 'should create the correct condition' do Blog.last_find[:conditions].should == [%q(blogs__posts__comments.offensive = ?), true] end it 'should create the correct join' do Blog.last_find[:joins].should == [%q(LEFT OUTER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id), %q(LEFT OUTER JOIN "comments" AS blogs__posts__comments ON blogs__posts.id = blogs__posts__comments.post_id)] end end it 'should allow strings to be passed as the join type' do Blog.filter do having({ :posts => :comments }, :join_type => 'left') do with(:offensive, true) end end.inspect end describe 'on polymorphic associations' do before do PublicPost.filter do having(:reviews) do with(:stars_count, 3) end end.inspect end it 'should create the correct condition' do PublicPost.last_find[:conditions].should == [%q(posts__reviews.stars_count = ?), 3] end it 'should create the correct join' do PublicPost.last_find[:joins].should == [%q(INNER JOIN "reviews" AS posts__reviews ON "posts".id = posts__reviews.reviewable_id AND (posts__reviews.reviewable_type = 'Post'))] end end describe 'on has_many_through associations' do before do Blog.filter do having(:comments) do with(:offensive, true) end end.inspect end it 'should create the correct condition' do Blog.last_find[:conditions].should == [%q(blogs__posts__comments.offensive = ?), true] end it 'should create the correct join' do Blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id), %q(INNER JOIN "comments" AS blogs__posts__comments ON blogs__posts.id = blogs__posts__comments.post_id)] end end describe 'adding joins automatically on ordering' do it 'should infer the join' do Post.filter do order(:comments => :created_at) end.inspect Post.last_find.should == {:order => 'posts__comments.created_at ASC', :joins => [%q(INNER JOIN "comments" AS posts__comments ON "posts".id = posts__comments.post_id)], :readonly => false} end end describe 'on has_one_through associations' do before do Post.filter do having(:user) do with(:first_name, 'Joe') end end.inspect end it 'should create the correct condition' do Post.last_find[:conditions].should == [%q(posts__author__user.first_name = ?), 'Joe'] end it 'should create the correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "authors" AS posts__author ON "posts".id = posts__author.post_id), %q(INNER JOIN "users" AS posts__author__user ON posts__author.user_id = posts__author__user.id)] end end describe 'passing strings instead of symbols' do before do Post.filter do having('comments') do with('offensive', true) end with('id').gte(12) end.inspect end it 'should create the correct condition' do Post.last_find[:conditions].should == [%q((posts__comments.offensive = ?) AND ("posts".id >= ?)), true, 12] end it 'should create the correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "comments" AS posts__comments ON "posts".id = posts__comments.post_id)] end end describe 'using a table alias' do before do Post.filter do having(:comments, :alias => 'arghs') do with(:offensive, true) end end.inspect end it 'should create the correct condition' do Post.last_find[:conditions].should == [%q(arghs.offensive = ?), true] end it 'should create the correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "comments" AS arghs ON "posts".id = arghs.post_id)] end end describe 'using a table alias to do multiple joins on the same association' do before do Post.filter do having(:comments, :alias => 'ooohs').with(:offensive, true) having(:comments, :alias => 'aaahs').with(:offensive, false) end.inspect end it 'should create the correct condition' do Post.last_find[:conditions].should == [%q((ooohs.offensive = ?) AND (aaahs.offensive = ?)), true, false] end it 'should create the correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "comments" AS ooohs ON "posts".id = ooohs.post_id), %q(INNER JOIN "comments" AS aaahs ON "posts".id = aaahs.post_id)] end end describe 'using a table alias with has_many :through associations' do before do Blog.filter do having(:comments, :alias => 'arghs') do with(:offensive, true) end end.inspect end it 'should create the correct condition' do Blog.last_find[:conditions].should == [%q(arghs.offensive = ?), true] end it 'should create the correct join' do Blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs__posts ON "blogs".id = blogs__posts.blog_id), %q(INNER JOIN "comments" AS arghs ON blogs__posts.id = arghs.post_id)] end end describe 'using a table alias' do before do Post.filter do having(:comments, :alias => 'arghs') do with(:offensive, true) end end.inspect end it 'should create the correct condition' do Post.last_find[:conditions].should == [%q(arghs.offensive = ?), true] end it 'should create the correct join' do Post.last_find[:joins].should == [%q(INNER JOIN "comments" AS arghs ON "posts".id = arghs.post_id)] end end describe 'with nonstandard primary and foreign keys' do it 'should join with the correct key on belongs_to' do Subscription.filter { having(:user).with(:first_name, 'Bob') }.inspect Subscription.last_find[:joins].should == [%q(INNER JOIN "users" AS subscriptions__user ON "subscriptions".email = subscriptions__user.email_address)] end it 'should join to the correct key on has_many' do User.filter { having(:subscriptions).with(:created_at).gt(3.weeks.ago.utc) }.inspect User.last_find[:joins].should == [%q(INNER JOIN "subscriptions" AS users__subscriptions ON "users".email_address = users__subscriptions.email)] end end end