1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fix issue with expression index in insert_all

Based on the docs which state unique_by option of insert_all can use the
index name if desired, one would expect the method to work normally and
use the `unique_by` option to determine duplicates.

However, there's an issue where the insert_all expects a Set instead
of the string representing the index expression it is given. This causes
an error. Returning the string expression instead of attempting to
format it works perfectly though.
This commit is contained in:
Austen Madden 2020-06-02 18:18:27 -04:00
parent 751d46af4f
commit 3315cc76e0
5 changed files with 39 additions and 1 deletions

View file

@ -1,3 +1,24 @@
* Resolve issue with insert_all unique_by option when used with expression index.
When the `:unique_by` option of `ActiveRecord::Persistence.insert_all` and
`ActiveRecord::Persistence.upsert_all` was used with the name of an expression index, an error
was raised. Adding a guard around the formatting behavior for the `:unique_by` corrects this.
Usage:
```ruby
create_table :books, id: :integer, force: true do |t|
t.column :name, :string
t.index "lower(name)", unique: true
end
Book.insert_all [{ name: "MyTest" }], unique_by: :index_books_on_lower_name
```
Fixes #39516.
*Austen Madden*
* Add basic support for CHECK constraints to database migrations. * Add basic support for CHECK constraints to database migrations.
Usage: Usage:

View file

@ -195,7 +195,7 @@ module ActiveRecord
end end
def format_columns(columns) def format_columns(columns)
quote_columns(columns).join(",") columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
end end
def quote_columns(columns) def quote_columns(columns)

View file

@ -58,6 +58,7 @@ end
supports_savepoints? supports_savepoints?
supports_partial_index? supports_partial_index?
supports_partitioned_indexes? supports_partitioned_indexes?
supports_expression_index?
supports_insert_returning? supports_insert_returning?
supports_insert_on_duplicate_skip? supports_insert_on_duplicate_skip?
supports_insert_on_duplicate_update? supports_insert_on_duplicate_update?

View file

@ -178,6 +178,20 @@ class InsertAllTest < ActiveRecord::TestCase
end end
end end
def test_insert_all_and_upsert_all_with_expression_index
skip unless supports_expression_index? && supports_insert_conflict_target?
book = Book.create!(external_id: "abc")
assert_no_difference "Book.count" do
Book.insert_all [{ external_id: "ABC" }], unique_by: :index_books_on_lower_external_id
end
Book.upsert_all [{ external_id: "Abc" }], unique_by: :index_books_on_lower_external_id
assert_equal "Abc", book.reload.external_id
end
def test_insert_all_and_upsert_all_raises_when_index_is_missing def test_insert_all_and_upsert_all_raises_when_index_is_missing
skip unless supports_insert_conflict_target? skip unless supports_insert_conflict_target?

View file

@ -116,10 +116,12 @@ ActiveRecord::Schema.define do
t.column :difficulty, :integer, **default_zero t.column :difficulty, :integer, **default_zero
t.column :cover, :string, default: "hard" t.column :cover, :string, default: "hard"
t.string :isbn, **case_sensitive_options t.string :isbn, **case_sensitive_options
t.string :external_id
t.datetime :published_on t.datetime :published_on
t.boolean :boolean_status t.boolean :boolean_status
t.index [:author_id, :name], unique: true t.index [:author_id, :name], unique: true
t.index :isbn, where: "published_on IS NOT NULL", unique: true t.index :isbn, where: "published_on IS NOT NULL", unique: true
t.index "(lower(external_id))", unique: true if supports_expression_index?
t.datetime :created_at t.datetime :created_at
t.datetime :updated_at t.datetime :updated_at