aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2018-09-28 03:38:55 +0900
committerRyuta Kamizono <kamipo@gmail.com>2018-09-28 04:14:15 +0900
commite5190acacd1088211cfe6f128b782af216aa6570 (patch)
treebc4ef154a3f3dc42e6e0e0166c7d37e6cf884e6d /activerecord
parentdc47bb5091b058af45081499f67342c3890d6564 (diff)
downloadrails-e5190acacd1088211cfe6f128b782af216aa6570.tar.gz
rails-e5190acacd1088211cfe6f128b782af216aa6570.tar.bz2
rails-e5190acacd1088211cfe6f128b782af216aa6570.zip
Make `update_counters` preparable
Before: ``` Topic Update All (0.4ms) UPDATE `topics` SET `topics`.`replies_count` = COALESCE(`topics`.`replies_count`, 0) + 1, `topics`.`updated_at` = '2018-09-27 18:34:05.068774' WHERE `topics`.`id` = ? [["id", 7]] ``` After: ``` Topic Update All (0.4ms) UPDATE `topics` SET `topics`.`replies_count` = COALESCE(`topics`.`replies_count`, 0) + ?, `topics`.`updated_at` = ? WHERE `topics`.`id` = ? [["replies_count", 1], ["updated_at", 2018-09-27 18:55:05 UTC], ["id", 7]] ```
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/relation.rb23
-rw-r--r--activerecord/lib/arel/factory_methods.rb4
-rw-r--r--activerecord/lib/arel/visitors/to_sql.rb2
3 files changed, 19 insertions, 10 deletions
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 771ca952e1..2fc0cb0597 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -379,19 +379,22 @@ module ActiveRecord
def update_counters(counters) # :nodoc:
touch = counters.delete(:touch)
- updates = counters.map do |counter_name, value|
- operator = value < 0 ? "-" : "+"
- quoted_column = connection.quote_table_name_for_assignment(table.name, counter_name)
- "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
+ updates = {}
+ counters.each do |counter_name, value|
+ attr = arel_attribute(counter_name)
+ bind = predicate_builder.build_bind_attribute(attr.name, value.abs)
+ expr = table.coalesce(Arel::Nodes::UnqualifiedColumn.new(attr), 0)
+ expr = value < 0 ? expr - bind : expr + bind
+ updates[counter_name] = expr.expr
end
if touch
names = touch if touch != true
touch_updates = klass.touch_attributes_with_time(*names)
- updates << klass.sanitize_sql_for_assignment(touch_updates, table.name) unless touch_updates.empty?
+ updates.merge!(touch_updates) unless touch_updates.empty?
end
- update_all updates.join(", ")
+ update_all updates
end
# Touches all records in the current relation without instantiating records first with the updated_at/on attributes
@@ -632,9 +635,11 @@ module ActiveRecord
def _substitute_values(values)
values.map do |name, value|
attr = arel_attribute(name)
- type = klass.type_for_attribute(attr.name)
- bind = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
- [attr, bind]
+ unless value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
+ type = klass.type_for_attribute(attr.name)
+ value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
+ end
+ [attr, value]
end
end
diff --git a/activerecord/lib/arel/factory_methods.rb b/activerecord/lib/arel/factory_methods.rb
index b828bc274e..83ec23e403 100644
--- a/activerecord/lib/arel/factory_methods.rb
+++ b/activerecord/lib/arel/factory_methods.rb
@@ -41,5 +41,9 @@ module Arel # :nodoc: all
def lower(column)
Nodes::NamedFunction.new "LOWER", [Nodes.build_quoted(column)]
end
+
+ def coalesce(*exprs)
+ Nodes::NamedFunction.new "COALESCE", exprs
+ end
end
end
diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb
index 81ca63f261..40c626c725 100644
--- a/activerecord/lib/arel/visitors/to_sql.rb
+++ b/activerecord/lib/arel/visitors/to_sql.rb
@@ -637,7 +637,7 @@ module Arel # :nodoc: all
def visit_Arel_Nodes_Assignment(o, collector)
case o.right
- when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute, Arel::Nodes::BindParam
+ when Arel::Nodes::Node, Arel::Attributes::Attribute
collector = visit o.left, collector
collector << " = "
visit o.right, collector