2021-01-03 14:25:43 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
RSpec.describe Gitlab::Database::BulkUpdate do
|
|
|
|
describe 'error states' do
|
|
|
|
let(:columns) { %i[title] }
|
|
|
|
|
|
|
|
let_it_be(:mapping) do
|
|
|
|
create_default(:user)
|
|
|
|
create_default(:project)
|
|
|
|
|
|
|
|
i_a, i_b = create_list(:issue, 2)
|
|
|
|
|
|
|
|
{
|
2021-04-17 20:07:23 +05:30
|
|
|
i_a => { title: 'Issue a' },
|
|
|
|
i_b => { title: 'Issue b' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not raise errors on valid inputs' do
|
|
|
|
expect { described_class.execute(columns, mapping) }.not_to raise_error
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'expects a non-empty list of column names' do
|
|
|
|
expect { described_class.execute([], mapping) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'expects all columns to be symbols' do
|
|
|
|
expect { described_class.execute([1], mapping) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'expects all columns to be valid columns on the tables' do
|
|
|
|
expect { described_class.execute([:foo], mapping) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'refuses to set ID' do
|
|
|
|
expect { described_class.execute([:id], mapping) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'expects a non-empty mapping' do
|
|
|
|
expect { described_class.execute(columns, []) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'expects all map values to be Hash instances' do
|
|
|
|
bad_map = mapping.merge(build(:issue) => 2)
|
|
|
|
|
|
|
|
expect { described_class.execute(columns, bad_map) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'is possible to update all objects in a single query' do
|
|
|
|
users = create_list(:user, 3)
|
2021-04-17 20:07:23 +05:30
|
|
|
mapping = users.zip(%w[foo bar baz]).to_h do |u, name|
|
2021-01-03 14:25:43 +05:30
|
|
|
[u, { username: name, admin: true }]
|
|
|
|
end
|
|
|
|
|
|
|
|
expect do
|
|
|
|
described_class.execute(%i[username admin], mapping)
|
|
|
|
end.not_to exceed_query_limit(1)
|
|
|
|
|
|
|
|
# We have optimistically updated the values
|
|
|
|
expect(users).to all(be_admin)
|
2021-04-17 20:07:23 +05:30
|
|
|
expect(users.map(&:username)).to eq(%w[foo bar baz])
|
2021-01-03 14:25:43 +05:30
|
|
|
|
|
|
|
users.each(&:reset)
|
|
|
|
|
|
|
|
# The values are correct on reset
|
|
|
|
expect(users).to all(be_admin)
|
2021-04-17 20:07:23 +05:30
|
|
|
expect(users.map(&:username)).to eq(%w[foo bar baz])
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'is possible to update heterogeneous sets' do
|
|
|
|
create_default(:user)
|
|
|
|
create_default(:project)
|
|
|
|
|
|
|
|
mr_a = create(:merge_request)
|
|
|
|
i_a, i_b = create_list(:issue, 2)
|
|
|
|
|
|
|
|
mapping = {
|
|
|
|
mr_a => { title: 'MR a' },
|
2021-04-17 20:07:23 +05:30
|
|
|
i_a => { title: 'Issue a' },
|
|
|
|
i_b => { title: 'Issue b' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
expect do
|
|
|
|
described_class.execute(%i[title], mapping)
|
|
|
|
end.not_to exceed_query_limit(2)
|
|
|
|
|
|
|
|
expect([mr_a, i_a, i_b].map { |x| x.reset.title })
|
|
|
|
.to eq(['MR a', 'Issue a', 'Issue b'])
|
|
|
|
end
|
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
context 'validates prepared_statements support', :reestablished_active_record_base do
|
|
|
|
using RSpec::Parameterized::TableSyntax
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
where(:prepared_statements) do
|
|
|
|
[false, true]
|
|
|
|
end
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
before do
|
|
|
|
configuration_hash = ActiveRecord::Base.connection_db_config.configuration_hash
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2022-03-02 08:16:31 +05:30
|
|
|
ActiveRecord::Base.establish_connection( # rubocop: disable Database/EstablishConnection
|
2021-11-18 22:05:49 +05:30
|
|
|
configuration_hash.merge(prepared_statements: prepared_statements)
|
|
|
|
)
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
with_them do
|
|
|
|
it 'sets multiple values' do
|
|
|
|
create_default(:user)
|
|
|
|
create_default(:project)
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
i_a, i_b = create_list(:issue, 2)
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
mapping = {
|
|
|
|
i_a => { title: 'Issue a' },
|
|
|
|
i_b => { title: 'Issue b' }
|
|
|
|
}
|
2021-04-17 20:07:23 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
described_class.execute(%i[title], mapping)
|
2021-01-03 14:25:43 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
expect([i_a, i_b].map { |x| x.reset.title })
|
|
|
|
.to eq(['Issue a', 'Issue b'])
|
|
|
|
end
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|