diff options
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r-- | activerecord/lib/active_record/aggregations.rb | 9 | ||||
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 56 |
2 files changed, 65 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index f0f34e9a99..cad8304bcf 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -108,6 +108,15 @@ module ActiveRecord # # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects # immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable + # + # == Finding records by a value object + # + # Once a +composed_of+ relationship is specified for a model, records can be loaded from the database by specifying an instance + # of the value object in the conditions hash. The following example finds all customers with +balance_amount+ equal to 20 and + # +balance_currency+ equal to "USD": + # + # Customer.find(:all, :conditions => {:balance => Money.new(20, "USD")}) + # module ClassMethods # Adds reader and writer methods for manipulating a value object: # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods. diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 7be51df0a4..2d2f2297ed 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1560,7 +1560,23 @@ module ActiveRecord #:nodoc: attributes end + # Similar in purpose to +expand_hash_conditions_for_aggregates+. + def expand_attribute_names_for_aggregates(attribute_names) + expanded_attribute_names = [] + attribute_names.each do |attribute_name| + unless (aggregation = reflect_on_aggregation(attribute_name.to_sym)).nil? + aggregate_mapping(aggregation).each do |field_attr, aggregate_attr| + expanded_attribute_names << field_attr + end + else + expanded_attribute_names << attribute_name + end + end + expanded_attribute_names + end + def all_attributes_exists?(attribute_names) + attribute_names = expand_attribute_names_for_aggregates(attribute_names) attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) } end @@ -1801,6 +1817,41 @@ module ActiveRecord #:nodoc: end end + def aggregate_mapping(reflection) + mapping = reflection.options[:mapping] || [reflection.name, reflection.name] + mapping.first.is_a?(Array) ? mapping : [mapping] + end + + # Accepts a hash of sql conditions and replaces those attributes + # that correspond to a +composed_of+ relationship with their expanded + # aggregate attribute values. + # Given: + # class Person < ActiveRecord::Base + # composed_of :address, :class_name => "Address", + # :mapping => [%w(address_street street), %w(address_city city)] + # end + # Then: + # { :address => Address.new("813 abc st.", "chicago") } + # # => { :address_street => "813 abc st.", :address_city => "chicago" } + def expand_hash_conditions_for_aggregates(attrs) + expanded_attrs = {} + attrs.each do |attr, value| + unless (aggregation = reflect_on_aggregation(attr.to_sym)).nil? + mapping = aggregate_mapping(aggregation) + mapping.each do |field_attr, aggregate_attr| + if mapping.size == 1 && !value.respond_to?(aggregate_attr) + expanded_attrs[field_attr] = value + else + expanded_attrs[field_attr] = value.send(aggregate_attr) + end + end + else + expanded_attrs[attr] = value + end + end + expanded_attrs + end + # Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause. # { :name => "foo'bar", :group_id => 4 } # # => "name='foo''bar' and group_id= 4" @@ -1810,7 +1861,12 @@ module ActiveRecord #:nodoc: # # => "age BETWEEN 13 AND 18" # { 'other_records.id' => 7 } # # => "`other_records`.`id` = 7" + # And for value objects on a composed_of relationship: + # { :address => Address.new("123 abc st.", "chicago") } + # # => "address_street='123 abc st.' and address_city='chicago'" def sanitize_sql_hash_for_conditions(attrs) + attrs = expand_hash_conditions_for_aggregates(attrs) + conditions = attrs.map do |attr, value| attr = attr.to_s |