From 59eb5e24d4b1c4c9c99f94612789e9f255791df0 Mon Sep 17 00:00:00 2001 From: Will Bryant Date: Wed, 4 Feb 2009 13:01:03 +1300 Subject: [PATCH] support end-exclusive ... Ranges in SQL hash condition sanitization properly --- activerecord/lib/active_record/base.rb | 16 ++++++++++------ activerecord/lib/active_record/validations.rb | 2 +- activerecord/test/cases/finder_test.rb | 6 ++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index dcc8277..837cb7b 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1860,12 +1860,16 @@ module ActiveRecord #:nodoc: attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) } end - def attribute_condition(argument) + def attribute_condition(quoted_column_name, argument) case argument - when nil then "IS ?" - when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "IN (?)" - when Range then "BETWEEN ? AND ?" - else "= ?" + when nil then "#{quoted_column_name} IS ?" + when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "#{quoted_column_name} IN (?)" + when Range then if argument.exclude_end? + "#{quoted_column_name} >= ? AND #{quoted_column_name} < ?" + else + "#{quoted_column_name} BETWEEN ? AND ?" + end + else "#{quoted_column_name} = ?" end end @@ -2156,7 +2160,7 @@ module ActiveRecord #:nodoc: table_name = connection.quote_table_name(table_name) end - "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}" + attribute_condition("#{table_name}.#{connection.quote_column_name(attr)}", value) else sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s)) end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 9220eae..441e68b 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -744,7 +744,7 @@ module ActiveRecord if scope = configuration[:scope] Array(scope).map do |scope_item| scope_value = record.send(scope_item) - condition_sql << " AND #{record.class.quoted_table_name}.#{scope_item} #{attribute_condition(scope_value)}" + condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value) condition_params << scope_value end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 153880a..23827cd 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -291,6 +291,12 @@ class FinderTest < ActiveRecord::TestCase assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) } end + def test_find_on_hash_conditions_with_end_exclusive_range + assert_equal [1,2,3], Topic.find(:all, :conditions => { :id => 1..3 }).map(&:id).sort + assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1...3 }).map(&:id).sort + assert_raises(ActiveRecord::RecordNotFound) { Topic.find(3, :conditions => { :id => 2...3 }) } + end + def test_find_on_hash_conditions_with_multiple_ranges assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort -- 1.5.5.1