diff options
Diffstat (limited to 'activerecord/lib')
8 files changed, 53 insertions, 31 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 6adaeb0121..615b2fa701 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -31,9 +31,11 @@ module ActiveRecord temp_method = "__temp__#{safe_name}" ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name + sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 def #{temp_method} + #{sync_with_transaction_state} name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} _read_attribute(name) { |n| missing_attribute(n, caller) } end @@ -57,6 +59,7 @@ module ActiveRecord end name = self.class.primary_key if name == "id".freeze && self.class.primary_key + sync_with_transaction_state if name == self.class.primary_key _read_attribute(name, &block) end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index fa01f832ac..62c5ce059b 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -15,10 +15,12 @@ module ActiveRecord def define_method_attribute=(name) safe_name = name.unpack("h*".freeze).first ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name + sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 def __temp__#{safe_name}=(value) name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} + #{sync_with_transaction_state} _write_attribute(name, value) end alias_method #{(name + '=').inspect}, :__temp__#{safe_name}= @@ -38,6 +40,7 @@ module ActiveRecord end name = self.class.primary_key if name == "id".freeze && self.class.primary_key + sync_with_transaction_state if name == self.class.primary_key _write_attribute(name, value) end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 8b97dbe5bf..cdd3b5114a 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -168,8 +168,7 @@ module ActiveRecord id = ids.first - return super if id.kind_of?(Array) || - id.is_a?(ActiveRecord::Base) + return super if StatementCache.unsupported_value?(id) key = primary_key @@ -194,7 +193,7 @@ module ActiveRecord hash = args.first return super if !(Hash === hash) || hash.values.any? { |v| - v.nil? || Array === v || Hash === v || Relation === v || Base === v + StatementCache.unsupported_value?(v) } # We can't cache Post.find_by(author: david) ...yet diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 182f654897..03824ffff9 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -135,19 +135,17 @@ module ActiveRecord if other.reordering_value # override any order specified in the original relation relation.reorder! other.order_values - elsif other.order_values + elsif other.order_values.any? # merge in order_values from relation relation.order! other.order_values end - relation.extend(*other.extending_values) unless other.extending_values.blank? + extensions = other.extensions - relation.extensions + relation.extending!(*extensions) if extensions.any? end def merge_single_values - if relation.from_clause.empty? - relation.from_clause = other.from_clause - end - relation.lock_value ||= other.lock_value + relation.lock_value ||= other.lock_value if other.lock_value unless other.create_with_value.blank? relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value) @@ -155,11 +153,15 @@ module ActiveRecord end def merge_clauses - CLAUSE_METHODS.each do |method| - clause = relation.get_value(method) - other_clause = other.get_value(method) - relation.set_value(method, clause.merge(other_clause)) + if relation.from_clause.empty? && !other.from_clause.empty? + relation.from_clause = other.from_clause end + + where_clause = relation.where_clause.merge(other.where_clause) + relation.where_clause = where_clause unless where_clause.empty? + + having_clause = relation.having_clause.merge(other.having_clause) + relation.having_clause = having_clause unless having_clause.empty? end end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index f7fe968b55..bdc5c27328 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -902,16 +902,17 @@ module ActiveRecord @arel ||= build_arel end - # Returns a relation value with a given name - def get_value(name) # :nodoc: - @values[name] || default_value_for(name) - end + protected + # Returns a relation value with a given name + def get_value(name) # :nodoc: + @values[name] || default_value_for(name) + end - # Sets the relation value with the given name - def set_value(name, value) # :nodoc: - assert_mutability! - @values[name] = value - end + # Sets the relation value with the given name + def set_value(name, value) # :nodoc: + assert_mutability! + @values[name] = value + end private diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index ef2bca9155..752bb38481 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -15,6 +15,12 @@ module ActiveRecord ) end + def -(other) + WhereClause.new( + predicates - other.predicates, + ) + end + def merge(other) WhereClause.new( predicates_unreferenced_by(other) + other.predicates, @@ -26,14 +32,17 @@ module ActiveRecord end def or(other) - if empty? - self - elsif other.empty? - other + left = self - other + common = self - left + right = other - common + + if left.empty? || right.empty? + common else - WhereClause.new( - [ast.or(other.ast)], + or_clause = WhereClause.new( + [left.ast.or(right.ast)], ) + common + or_clause end end diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb index 64657089b5..2af7d00246 100644 --- a/activerecord/lib/active_record/statement_cache.rb +++ b/activerecord/lib/active_record/statement_cache.rb @@ -108,6 +108,11 @@ module ActiveRecord klass.find_by_sql(sql, bind_values, preparable: true, &block) end - alias :call :execute + + def self.unsupported_value?(value) + case value + when NilClass, Array, Range, Hash, Relation, Base then true + end + end end end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 3e8a0789df..f91f0cdf12 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -432,8 +432,8 @@ module ActiveRecord @new_record = restore_state[:new_record] @destroyed = restore_state[:destroyed] pk = self.class.primary_key - if pk && read_attribute(pk) != restore_state[:id] - write_attribute(pk, restore_state[:id]) + if pk && _read_attribute(pk) != restore_state[:id] + _write_attribute(pk, restore_state[:id]) end freeze if restore_state[:frozen?] end |