Skip to content

Commit

Permalink
Merge pull request #395 from smaximov/feat/upsert-conflict-where
Browse files Browse the repository at this point in the history
Allow setting index predicate for upserts w/ partial unique indices
  • Loading branch information
flash-gordon authored Mar 23, 2021
2 parents 0f970c1 + f491dfe commit 7766d14
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
7 changes: 6 additions & 1 deletion lib/rom/sql/extensions/postgres/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def update(tuple)
class Upsert < SQL::Commands::Create
adapter :sql

defines :constraint, :conflict_target, :update_statement, :update_where
defines :constraint, :conflict_target, :conflict_where, :update_statement, :update_where

# @!attribute [r] constraint
# @return [Symbol] the name of the constraint expected to be violated
Expand All @@ -95,6 +95,10 @@ class Upsert < SQL::Commands::Create
# @return [Object] the column or expression to handle a violation on
option :conflict_target, default: -> { self.class.conflict_target }

# @!attribute [r] conflict_where
# @return [Object] the index filter, when using a partial index to determine uniqueness
option :conflict_where, default: -> { self.class.conflict_where }

# @!attribute [r] update_statement
# @return [Object] the update statement which will be executed in case of a violation
option :update_statement, default: -> { self.class.update_statement }
Expand Down Expand Up @@ -123,6 +127,7 @@ def upsert_options
@upsert_options ||= {
constraint: constraint,
target: conflict_target,
conflict_where: conflict_where,
update_where: update_where,
update: update_statement
}
Expand Down
35 changes: 35 additions & 0 deletions spec/integration/commands/upsert_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,41 @@
it 'returns updated data' do
expect(command.call(excluded)).to eql(id: 1, user_id: 2, title: 'task 1')
end

context 'with index predicate' do
before do
conn.execute <<~SQL
ALTER TABLE tasks DROP CONSTRAINT tasks_title_key;
CREATE UNIQUE INDEX tasks_title_partial_index ON tasks (title)
WHERE user_id = 1;
SQL
end

let(:command_config) do
-> do
conflict_target :title
conflict_where user_id: 1
update_statement user_id: 2
end
end

context 'when predicate matches' do
let(:excluded) { task }

it 'returns updated data', :aggregate_failures do
expect(command.call(excluded)).to eql(id: 1, user_id: 2, title: 'task 1')
end
end

context 'when predicate does not match' do
let(:excluded) { task.update(user_id: 2) }

it 'creates new task', :aggregate_failures do
expect(command.call(excluded)).to eql(id: 2, user_id: 2, title: 'task 1')
end
end
end
end

context 'with constraint name' do
Expand Down

0 comments on commit 7766d14

Please sign in to comment.