Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow to update duplicates on conflict in PostgreSQL
  • Loading branch information
sobstel committed Aug 21, 2018
1 parent 861d5ed commit 501dd65
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 8 deletions.
15 changes: 11 additions & 4 deletions README.md
Expand Up @@ -149,22 +149,29 @@ Book.bulk_insert(*destination_columns, ignore: true) do |worker|
end
```

### Update Duplicates (MySQL)
### Update Duplicates (MySQL, PostgreSQL)

If you don't want to ignore duplicate rows but instead want to update them
then you can use the _update_duplicates_ option. Set this option to true
and when a duplicate row is found the row will be updated with your new
values. Default value for this option is false.
(MySQL) or list unique column names (PostgreSQL) and when a duplicate row
is found the row will be updated with your new values.
Default value for this option is false.

```ruby
destination_columns = [:title, :author]

# Update duplicate rows
# Update duplicate rows (MySQL)
Book.bulk_insert(*destination_columns, update_duplicates: true) do |worker|
worker.add(...)
worker.add(...)
# ...
end

# Update duplicate rows (PostgreSQL)
Book.bulk_insert(*destination_columns, update_duplicates: %w[title]) do |worker|
worker.add(...)
# ...
end
```

### Return Primary Keys (PostgreSQL, PostGIS)
Expand Down
8 changes: 7 additions & 1 deletion lib/bulk_insert/worker.rb
Expand Up @@ -150,8 +150,14 @@ def primary_key_return_statement
end

def on_conflict_statement
if (adapter_name =~ /\APost(?:greSQL|GIS)/i && ignore )
is_postgres = adapter_name =~ /\APost(?:greSQL|GIS)/i
if is_postgres && ignore
' ON CONFLICT DO NOTHING'
elsif is_postgres && update_duplicates
update_values = @columns.map do |column|
"#{column.name}=EXCLUDED.#{column.name}"
end.join(', ')
' ON CONFLICT(' + update_duplicates.join(', ') + ') DO UPDATE SET ' + update_values
elsif adapter_name =~ /^mysql/i && update_duplicates
update_values = @columns.map do |column|
"`#{column.name}`=VALUES(`#{column.name}`)"
Expand Down
6 changes: 3 additions & 3 deletions test/bulk_insert/worker_test.rb
Expand Up @@ -332,14 +332,14 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
'id',
%w(greeting age happy created_at updated_at color),
500, # batch size
true, # ignore
false, # update duplicates
false, # ignore
%w(greeting age happy), # update duplicates
true # return primary keys
)
pgsql_worker.adapter_name = 'PostgreSQL'
pgsql_worker.add ["Yo", 15, false, nil, nil]

assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON CONFLICT(greeting, age, happy) DO UPDATE SET greeting=EXCLUDED.greeting, age=EXCLUDED.age, happy=EXCLUDED.happy, created_at=EXCLUDED.created_at, updated_at=EXCLUDED.updated_at, color=EXCLUDED.color RETURNING id"
end

test "adapter dependent PostGIS methods" do
Expand Down

0 comments on commit 501dd65

Please sign in to comment.