diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2018-09-28 03:38:55 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2018-09-28 04:14:15 +0900 |
commit | e5190acacd1088211cfe6f128b782af216aa6570 (patch) | |
tree | bc4ef154a3f3dc42e6e0e0166c7d37e6cf884e6d | |
parent | dc47bb5091b058af45081499f67342c3890d6564 (diff) | |
download | rails-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]]
```
-rw-r--r-- | activerecord/lib/active_record/relation.rb | 23 | ||||
-rw-r--r-- | activerecord/lib/arel/factory_methods.rb | 4 | ||||
-rw-r--r-- | activerecord/lib/arel/visitors/to_sql.rb | 2 |
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 |