提交 e5190aca 编写于 作者: R Ryuta Kamizono

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]]

```
上级 dc47bb50
......@@ -379,19 +379,22 @@ def update(id = :all, attributes) # :nodoc:
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 @@ def load_records(records)
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
......
......@@ -41,5 +41,9 @@ def grouping(expr)
def lower(column)
Nodes::NamedFunction.new "LOWER", [Nodes.build_quoted(column)]
end
def coalesce(*exprs)
Nodes::NamedFunction.new "COALESCE", exprs
end
end
end
......@@ -637,7 +637,7 @@ def visit_Arel_Nodes_Or(o, collector)
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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册