Permalink
Browse files

Merge [5435] from trunk.

git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5651 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent d6c28bf commit 87ef365a49ec1f7370cf388db4c9ce8d017a07b6 @jeremy jeremy committed Nov 29, 2006
Showing with 53 additions and 33 deletions.
  1. +6 −0 activerecord/CHANGELOG
  2. +33 −31 activerecord/lib/active_record/base.rb
  3. +14 −2 activerecord/test/finder_test.rb
View
@@ -1,3 +1,9 @@
+*1.15.0 RC2*
+
+* Support nil and Array in :conditions => { attr => value } hashes. #6548 [Assaf, Jeremy Kemper]
+ find(:all, :conditions => { :topic_id => [1, 2, 3], :last_read => nil }
+
+
*1.15.0 RC1* (November 22nd, 2006)
* Quote ActiveSupport::Multibyte::Chars. #6653 [Julian Tarkhanov]
@@ -987,7 +987,7 @@ def find_initial(options)
options.update(:limit => 1) unless options[:include]
find_every(options).first
end
-
+
def find_every(options)
records = scoped?(:find, :include) || options[:include] ?
find_with_associations(options) :
@@ -997,11 +997,11 @@ def find_every(options)
records
end
-
+
def find_from_ids(ids, options)
- expects_array = ids.first.kind_of?(Array)
+ expects_array = ids.first.kind_of?(Array)
return ids.first if expects_array && ids.first.empty?
-
+
ids = ids.flatten.compact.uniq
case ids.size
@@ -1195,16 +1195,16 @@ def method_missing(method_id, *arguments)
attribute_names = extract_attribute_names_from_match(match)
super unless all_attributes_exists?(attribute_names)
- conditions = construct_conditions_from_arguments(attribute_names, arguments)
+ attributes = construct_attributes_from_arguments(attribute_names, arguments)
case extra_options = arguments[attribute_names.size]
when nil
- options = { :conditions => conditions }
+ options = { :conditions => attributes }
set_readonly_option!(options)
ActiveSupport::Deprecation.silence { send(finder, options) }
when Hash
- finder_options = extra_options.merge(:conditions => conditions)
+ finder_options = extra_options.merge(:conditions => attributes)
validate_find_options(finder_options)
set_readonly_option!(finder_options)
@@ -1218,17 +1218,19 @@ def method_missing(method_id, *arguments)
else
ActiveSupport::Deprecation.silence do
- send(deprecated_finder, conditions, *arguments[attribute_names.length..-1])
+ send(deprecated_finder, sanitize_sql(attributes), *arguments[attribute_names.length..-1])
end
end
elsif match = /find_or_(initialize|create)_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
instantiator = determine_instantiator(match)
attribute_names = extract_attribute_names_from_match(match)
super unless all_attributes_exists?(attribute_names)
- options = { :conditions => construct_conditions_from_arguments(attribute_names, arguments) }
+ attributes = construct_attributes_from_arguments(attribute_names, arguments)
+ options = { :conditions => attributes }
set_readonly_option!(options)
- find_initial(options) || send(instantiator, construct_attributes_from_arguments(attribute_names, arguments))
+
+ find_initial(options) || send(instantiator, attributes)
else
super
end
@@ -1250,12 +1252,6 @@ def extract_attribute_names_from_match(match)
match.captures.last.split('_and_')
end
- def construct_conditions_from_arguments(attribute_names, arguments)
- conditions = []
- attribute_names.each_with_index { |name, idx| conditions << "#{table_name}.#{connection.quote_column_name(name)} #{attribute_condition(arguments[idx])} " }
- [ conditions.join(" AND "), *arguments[0...attribute_names.length] ]
- end
-
def construct_attributes_from_arguments(attribute_names, arguments)
attributes = {}
attribute_names.each_with_index { |name, idx| attributes[name] = arguments[idx] }
@@ -1278,7 +1274,7 @@ def attribute_condition(argument)
def expand_id_conditions(id_or_conditions)
case id_or_conditions
when Array, Hash then id_or_conditions
- else construct_conditions_from_arguments([primary_key], [id_or_conditions])
+ else sanitize_sql(primary_key => id_or_conditions)
end
end
@@ -1380,26 +1376,32 @@ def class_name_of_active_record_descendant(klass) #:nodoc:
klass.base_class.name
end
- #Accepts an array, hash, or string of sql conditions and
- #deals with them accordingly
+ # Accepts an array, hash, or string of sql conditions and sanitizes
+ # them into a valid SQL fragment.
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
# "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
def sanitize_sql(condition)
- return sanitize_sql_array(condition) if condition.is_a?(Array)
- return sanitize_sql_hash(condition) if condition.is_a?(Hash)
- condition
+ case condition
+ when Array; sanitize_sql_array(condition)
+ when Hash; sanitize_sql_hash(condition)
+ else condition
+ end
end
-
- # Accepts a hash of conditions. The hash has each key/value or attribute/value pair
- # sanitized and interpolated into the sql statement.
- # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id= 4"
- def sanitize_sql_hash(hash)
- hash.collect { |attrib, value|
- "#{table_name}.#{connection.quote_column_name(attrib)} = #{quote_value(value)}"
- }.join(" AND ")
+
+ # Sanitizes a hash of attribute/value pairs into SQL conditions.
+ # { :name => "foo'bar", :group_id => 4 }
+ # # => "name='foo''bar' and group_id= 4"
+ # { :status => nil, :group_id => [1,2,3] }
+ # # => "status IS NULL and group_id IN (1,2,3)"
+ def sanitize_sql_hash(attrs)
+ conditions = attrs.map do |attr, value|
+ "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
+ end.join(' AND ')
+
+ replace_bind_variables(conditions, attrs.values)
end
-
+
# Accepts an array of conditions. The array has each value
# sanitized and interpolated into the sql statement.
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
@@ -161,10 +161,22 @@ def test_hash_condition_find_malformed
Company.find(:first, :conditions => { :id => 2, :dhh => true })
}
end
-
+
def test_hash_condition_find_with_escaped_characters
Company.create("name" => "Ain't noth'n like' \#stuff")
- assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff"})
+ assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
+ end
+
+ def test_hash_condition_find_with_array
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
+ end
+
+ def test_hash_condition_find_with_nil
+ topic = Topic.find(:first, :conditions => { :last_read => nil } )
+ assert_not_nil topic
+ assert_nil topic.last_read
end
def test_bind_variables

0 comments on commit 87ef365

Please sign in to comment.