提交 5cec7ce3 编写于 作者: R Ryuta Kamizono

Support bulk insert/upsert on relation to preserve scope values

This allows to work `author.books.insert_all` as expected.
Co-authored-by: NJosef Šimánek <josef.simanek@gmail.com>
上级 587bfea7
* Support bulk insert/upsert on relation to preserve scope values.
*Josef Šimánek*, *Ryuta Kamizono*
* Preserve column comment value on changing column name on MySQL.
*Islam Taha*
......
......@@ -31,6 +31,18 @@ def create!(attributes = nil, &block)
scoping { @association.create!(attributes, &block) }
end
%w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
class_eval <<~RUBY
def #{method}(attributes, **kwargs)
if @association.reflection.through_reflection?
raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
end
scoping { klass.#{method}(attributes, **kwargs) }
end
RUBY
end
private
def exec_queries
super do |record|
......
......@@ -1096,7 +1096,9 @@ def reset_scope # :nodoc:
SpawnMethods,
].flat_map { |klass|
klass.public_instance_methods(false)
} - self.public_instance_methods(false) - [:select] + [:scoping, :values]
} - self.public_instance_methods(false) - [:select] + [
:scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
]
delegate(*delegate_methods, to: :scope)
......
......@@ -10,9 +10,15 @@ class InsertAll # :nodoc:
def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s).to_set
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
@on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
if model.scope_attributes?
@scope_attributes = model.scope_attributes
@keys |= @scope_attributes.keys
end
@keys = @keys.to_set
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
@returning = false if @returning == []
......@@ -49,6 +55,8 @@ def update_duplicates?
def map_key_with_value
inserts.map do |attributes|
attributes = attributes.stringify_keys
attributes.merge!(scope_attributes) if scope_attributes
verify_attributes(attributes)
keys.map do |key|
......@@ -58,6 +66,8 @@ def map_key_with_value
end
private
attr_reader :scope_attributes
def find_unique_index_for(unique_by)
name_or_columns = unique_by || model.primary_key
match = Array(name_or_columns).map(&:to_s)
......
# frozen_string_literal: true
require "cases/helper"
require "models/author"
require "models/book"
require "models/speedometer"
require "models/subscription"
require "models/subscriber"
class ReadonlyNameBook < Book
attr_readonly :name
......@@ -341,6 +344,62 @@ def test_insert_all_with_enum_values
assert_equal ["published", "proposed"], Book.where(isbn: ["1234566", "1234567"]).order(:id).pluck(:status)
end
def test_insert_all_on_relation
author = Author.create!(name: "Jimmy")
assert_difference "author.books.count", +1 do
author.books.insert_all!([{ name: "My little book", isbn: "1974522598" }])
end
end
def test_insert_all_on_relation_precedence
author = Author.create!(name: "Jimmy")
second_author = Author.create!(name: "Bob")
assert_difference "author.books.count", +1 do
author.books.insert_all!([{ name: "My little book", isbn: "1974522598", author_id: second_author.id }])
end
end
def test_insert_all_create_with
assert_difference "Book.where(format: 'X').count", +2 do
Book.create_with(format: "X").insert_all!([ { name: "A" }, { name: "B" } ])
end
end
def test_insert_all_has_many_through
book = Book.first
assert_raise(ArgumentError) { book.subscribers.insert_all!([ { nick: "Jimmy" } ]) }
end
def test_upsert_all_on_relation
author = Author.create!(name: "Jimmy")
assert_difference "author.books.count", +1 do
author.books.upsert_all([{ name: "My little book", isbn: "1974522598" }])
end
end
def test_upsert_all_on_relation_precedence
author = Author.create!(name: "Jimmy")
second_author = Author.create!(name: "Bob")
assert_difference "author.books.count", +1 do
author.books.upsert_all([{ name: "My little book", isbn: "1974522598", author_id: second_author.id }])
end
end
def test_upsert_all_create_with
assert_difference "Book.where(format: 'X').count", +2 do
Book.create_with(format: "X").upsert_all([ { name: "A" }, { name: "B" } ])
end
end
def test_upsert_all_has_many_through
book = Book.first
assert_raise(ArgumentError) { book.subscribers.upsert_all([ { nick: "Jimmy" } ]) }
end
private
def capture_log_output
output = StringIO.new
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册