Skip to content

Commit

Permalink
Avoid extra query attribute allocation in _insert_record/`_update_r…
Browse files Browse the repository at this point in the history
…ecord`

Since a `BindParam` object always has an attribute object as the value
in the Active Record usage, so `_insert_record`/`_update_record` could
be passed attribute set instead of wrapping casted value by a query
attribute.
  • Loading branch information
kamipo committed Mar 1, 2021
1 parent adc5eb6 commit 6ee96a8
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 22 deletions.
1 change: 0 additions & 1 deletion activemodel/lib/active_model/attribute_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def write_from_user(name, value)

def write_cast_value(name, value)
@attributes[name] = self[name].with_cast_value(value)
value
end

def freeze
Expand Down
4 changes: 1 addition & 3 deletions activerecord/lib/active_record/attribute_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,9 +384,7 @@ def attribute_method?(attr_name)
end

def attributes_with_values(attribute_names)
attribute_names.index_with do |name|
_read_attribute(name)
end
attribute_names.index_with { |name| @attributes[name] }
end

# Filters the primary keys and readonly attributes from the attribute names.
Expand Down
35 changes: 17 additions & 18 deletions activerecord/lib/active_record/persistence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -356,27 +356,27 @@ def _insert_record(values) # :nodoc:
primary_key = self.primary_key
primary_key_value = nil

if primary_key && Hash === values
primary_key_value = values[primary_key]

if !primary_key_value && prefetch_primary_key?
if prefetch_primary_key? && primary_key
values[primary_key] ||= begin
primary_key_value = next_sequence_value
values[primary_key] = primary_key_value
_default_attributes[primary_key].with_cast_value(primary_key_value)
end
end

im = Arel::InsertManager.new
im.into(arel_table)

if values.empty?
im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
im.into arel_table
im.insert(connection.empty_insert_statement_value(primary_key))
else
im = arel_table.compile_insert(_substitute_values(values))
im.insert(_substitute_values(values))
end

connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
end

def _update_record(values, constraints) # :nodoc:
constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
constraints = constraints.map { |name, value| predicate_builder[name, value] }

if default_scopes?(all_queries: true)
constraints << default_scoped(all_queries: true).where_clause.ast
Expand All @@ -386,15 +386,16 @@ def _update_record(values, constraints) # :nodoc:
constraints << current_scope.where_clause.ast
end

um = arel_table.where(
constraints.reduce(&:and)
).compile_update(_substitute_values(values), primary_key)
um = Arel::UpdateManager.new
um.table(arel_table)
um.set(_substitute_values(values))
um.wheres = constraints

connection.update(um, "#{self} Update")
end

def _delete_record(constraints) # :nodoc:
constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
constraints = constraints.map { |name, value| predicate_builder[name, value] }

if default_scopes?(all_queries: true)
constraints << default_scoped(all_queries: true).where_clause.ast
Expand Down Expand Up @@ -430,9 +431,7 @@ def discriminate_class_for_record(record)

def _substitute_values(values)
values.map do |name, value|
attr = arel_table[name]
bind = predicate_builder.build_bind_attribute(attr.name, value)
[attr, bind]
[ arel_table[name], Arel::Nodes::BindParam.new(value) ]
end
end
end
Expand Down Expand Up @@ -688,8 +687,8 @@ def update_columns(attributes)
end

update_constraints = _primary_key_constraints_hash
attributes.each do |k, v|
@attributes.write_cast_value(k, v)
attributes = attributes.each_with_object({}) do |(k, v), h|
h[k] = @attributes.write_cast_value(k, v)
clear_attribute_change(k)
end

Expand Down

0 comments on commit 6ee96a8

Please sign in to comment.