Skip to content

Commit

Permalink
Add :joins to an array and let AR handle making them unique
Browse files Browse the repository at this point in the history
  • Loading branch information
binarylogic committed Jun 13, 2009
1 parent 74ea432 commit b418206
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 9 deletions.
13 changes: 6 additions & 7 deletions lib/searchlogic/named_scopes/associations.rb
Expand Up @@ -88,7 +88,7 @@ def association_condition_options(association_name, association_condition, args)
# The underlying condition doesn't require any parameters, so let's just create a simple # The underlying condition doesn't require any parameters, so let's just create a simple
# named scope that is based on a hash. # named scope that is based on a hash.
options = scope.proxy_options options = scope.proxy_options
add_left_outer_join(options, association) add_left_outer_joins(options, association)
options options
else else
# The underlying condition requires parameters, let's match the parameters it requires # The underlying condition requires parameters, let's match the parameters it requires
Expand All @@ -110,7 +110,7 @@ def association_condition_options(association_name, association_condition, args)
eval <<-"end_eval" eval <<-"end_eval"
searchlogic_lambda(:#{scope_options.searchlogic_arg_type}) { |#{proc_args.join(",")}| searchlogic_lambda(:#{scope_options.searchlogic_arg_type}) { |#{proc_args.join(",")}|
options = association.klass.named_scope_options(association_condition).call(#{proc_args.join(",")}) options = association.klass.named_scope_options(association_condition).call(#{proc_args.join(",")})
add_left_outer_join(options, association) add_left_outer_joins(options, association)
options options
} }
end_eval end_eval
Expand All @@ -130,11 +130,10 @@ def association_condition_options(association_name, association_condition, args)
# JoinDependency which creates a LEFT OUTER JOIN, which is what we want. # JoinDependency which creates a LEFT OUTER JOIN, which is what we want.
# #
# The code below was extracted out of AR's add_joins! method and then modified. # The code below was extracted out of AR's add_joins! method and then modified.
def add_left_outer_join(options, association) def add_left_outer_joins(options, association)
join = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, association.name, nil).join_associations.collect { |assoc| assoc.association_join }.join join = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, association.name, nil).join_associations.collect { |assoc| assoc.association_join }.join.strip
options[:joins] ||= "" options[:joins] ||= []
next if options[:joins].include?(join) options[:joins].unshift(join)
options[:joins] = join.strip + (options[:joins].blank? ? "" : " #{options[:joins]}")
end end
end end
end end
Expand Down
2 changes: 2 additions & 0 deletions lib/searchlogic/search.rb
Expand Up @@ -89,6 +89,8 @@ def type_cast(value, type)
when Array when Array
value.collect { |v| type_cast(v, type) } value.collect { |v| type_cast(v, type) }
else else
# Let's leverage ActiveRecord's type casting, so that casting is consistent
# with the other models.
column_for_type_cast = ActiveRecord::ConnectionAdapters::Column.new("", nil) column_for_type_cast = ActiveRecord::ConnectionAdapters::Column.new("", nil)
column_for_type_cast.instance_variable_set(:@type, type) column_for_type_cast.instance_variable_set(:@type, type)
column_for_type_cast.type_cast(value) column_for_type_cast.type_cast(value)
Expand Down
26 changes: 24 additions & 2 deletions spec/named_scopes/associations_spec.rb
Expand Up @@ -2,8 +2,8 @@


describe "Associations" do describe "Associations" do
before(:each) do before(:each) do
@users_join_sql = "LEFT OUTER JOIN \"users\" ON users.company_id = companies.id" @users_join_sql = ["LEFT OUTER JOIN \"users\" ON users.company_id = companies.id"]
@orders_join_sql = "LEFT OUTER JOIN \"users\" ON users.company_id = companies.id LEFT OUTER JOIN \"orders\" ON orders.user_id = users.id" @orders_join_sql = ["LEFT OUTER JOIN \"users\" ON users.company_id = companies.id", "LEFT OUTER JOIN \"orders\" ON orders.user_id = users.id"]
end end


it "should create a named scope" do it "should create a named scope" do
Expand Down Expand Up @@ -86,6 +86,14 @@
Company.users_orders_total_gt(10).users_orders_taxes_lt(5).ascend_by_users_orders_total.all.should == Company.all Company.users_orders_total_gt(10).users_orders_taxes_lt(5).ascend_by_users_orders_total.all.should == Company.all
end end


it "should not create the same join twice when traveling through the duplicate join" do
Company.users_username_like("bjohnson").users_orders_total_gt(100).all.should == Company.all
end

it "should not create the same join twice when traveling through the duplicate join 2" do
Company.users_orders_total_gt(100).users_orders_line_items_price_gt(20).all.should == Company.all
end

it "should allow the use of :include when a join was created" do it "should allow the use of :include when a join was created" do
company = Company.create company = Company.create
user = company.users.create user = company.users.create
Expand All @@ -99,4 +107,18 @@
order = user.orders.create(:total => 20, :taxes => 3) order = user.orders.create(:total => 20, :taxes => 3)
Company.users_orders_total_gt(10).users_orders_taxes_lt(5).ascend_by_users_orders_total.all(:include => {:users => :orders}).should == Company.all Company.users_orders_total_gt(10).users_orders_taxes_lt(5).ascend_by_users_orders_total.all(:include => {:users => :orders}).should == Company.all
end end

it "should allow the use of :include when traveling through the duplicate join" do
company = Company.create
user = company.users.create(:username => "bjohnson")
order = user.orders.create(:total => 20, :taxes => 3)
Company.users_username_like("bjohnson").users_orders_taxes_lt(5).ascend_by_users_orders_total.all(:include => :users).should == Company.all
end

it "should allow the use of deep :include when traveling through the duplicate join" do
company = Company.create
user = company.users.create(:username => "bjohnson")
order = user.orders.create(:total => 20, :taxes => 3)
Company.ascend_by_users_orders_total.users_orders_taxes_lt(50).all(:include => {:users => :orders}).should == Company.all
end
end end
14 changes: 14 additions & 0 deletions spec/spec_helper.rb
Expand Up @@ -29,6 +29,13 @@
t.float :taxes t.float :taxes
t.float :total t.float :total
end end

create_table :line_items do |t|
t.datetime :created_at
t.datetime :updated_at
t.integer :order_id
t.float :price
end
end end


$LOAD_PATH.unshift(File.dirname(__FILE__)) $LOAD_PATH.unshift(File.dirname(__FILE__))
Expand All @@ -48,16 +55,23 @@ class User < ActiveRecord::Base


class Order < ActiveRecord::Base class Order < ActiveRecord::Base
belongs_to :user belongs_to :user
has_many :line_items, :dependent => :destroy
end

class LineItem < ActiveRecord::Base
belongs_to :order
end end


Company.destroy_all Company.destroy_all
User.destroy_all User.destroy_all
Order.destroy_all Order.destroy_all
LineItem.destroy_all
end end


config.after(:each) do config.after(:each) do
Object.send(:remove_const, :Company) Object.send(:remove_const, :Company)
Object.send(:remove_const, :User) Object.send(:remove_const, :User)
Object.send(:remove_const, :Order) Object.send(:remove_const, :Order)
Object.send(:remove_const, :LineItem)
end end
end end

0 comments on commit b418206

Please sign in to comment.