1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
# frozen_string_literal: true
def should_support_sqlite3_import_functionality
if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
should_support_sqlite_upsert_functionality
end
describe "#supports_imports?" do
it "should support import" do
assert ActiveRecord::Base.supports_import?
end
end
describe "#import" do
it "imports with a single insert on SQLite 3.7.11 or higher" do
assert_difference "Topic.count", +507 do
result = Topic.import Build(7, :topics)
assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
assert_equal 7, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
result = Topic.import Build(500, :topics)
assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
assert_equal 507, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
end
end
it "imports with a two inserts on SQLite 3.7.11 or higher" do
assert_difference "Topic.count", +501 do
result = Topic.import Build(501, :topics)
assert_equal 2, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
assert_equal 501, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
end
end
it "imports with a five inserts on SQLite 3.7.11 or higher" do
assert_difference "Topic.count", +2500 do
result = Topic.import Build(2500, :topics)
assert_equal 5, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
assert_equal 2500, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
end
end
end
end
def should_support_sqlite_upsert_functionality
should_support_basic_on_duplicate_key_update
should_support_on_duplicate_key_ignore
describe "#import" do
extend ActiveSupport::TestCase::ImportAssertions
macro(:perform_import) { raise "supply your own #perform_import in a context below" }
macro(:updated_topic) { Topic.find(@topic.id) }
context "with :on_duplicate_key_ignore and validation checks turned off" do
let(:columns) { %w( id title author_name author_email_address parent_id ) }
let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
setup do
Topic.import columns, values, validate: false
end
it "should not update any records" do
result = Topic.import columns, updated_values, on_duplicate_key_ignore: true, validate: false
assert_equal [], result.ids
end
end
context "with :on_duplicate_key_update and validation checks turned off" do
asssertion_group(:should_support_on_duplicate_key_update) do
should_not_update_fields_not_mentioned
should_update_foreign_keys
should_not_update_created_at_on_timestamp_columns
should_update_updated_at_on_timestamp_columns
end
context "using a hash" do
context "with :columns a hash" do
let(:columns) { %w( id title author_name author_email_address parent_id ) }
let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
macro(:perform_import) do |*opts|
Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { conflict_target: :id, columns: update_columns }, validate: false)
end
setup do
Topic.import columns, values, validate: false
@topic = Topic.find 99
end
it "should not modify the passed in :on_duplicate_key_update columns array" do
assert_nothing_raised do
columns = %w(title author_name).freeze
Topic.import columns, [%w(foo, bar)], on_duplicate_key_update: { columns: columns }
end
end
context "using string hash map" do
let(:update_columns) { { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
should_support_on_duplicate_key_update
should_update_fields_mentioned
end
context "using string hash map, but specifying column mismatches" do
let(:update_columns) { { "title" => "author_email_address", "author_email_address" => "title", "parent_id" => "parent_id" } }
should_support_on_duplicate_key_update
should_update_fields_mentioned_with_hash_mappings
end
context "using symbol hash map" do
let(:update_columns) { { title: :title, author_email_address: :author_email_address, parent_id: :parent_id } }
should_support_on_duplicate_key_update
should_update_fields_mentioned
end
context "using symbol hash map, but specifying column mismatches" do
let(:update_columns) { { title: :author_email_address, author_email_address: :title, parent_id: :parent_id } }
should_support_on_duplicate_key_update
should_update_fields_mentioned_with_hash_mappings
end
end
context 'with :index_predicate' do
let(:columns) { %w( id device_id alarm_type status metadata ) }
let(:values) { [[99, 17, 1, 1, 'foo']] }
let(:updated_values) { [[99, 17, 1, 2, 'bar']] }
macro(:perform_import) do |*opts|
Alarm.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { conflict_target: [:device_id, :alarm_type], index_predicate: 'status <> 0', columns: [:status] }, validate: false)
end
macro(:updated_alarm) { Alarm.find(@alarm.id) }
setup do
Alarm.import columns, values, validate: false
@alarm = Alarm.find 99
end
context 'supports on duplicate key update for partial indexes' do
it 'should not update created_at timestamp columns' do
Timecop.freeze Chronic.parse("5 minutes from now") do
perform_import
assert_in_delta @alarm.created_at.to_i, updated_alarm.created_at.to_i, 1
end
end
it 'should update updated_at timestamp columns' do
time = Chronic.parse("5 minutes from now")
Timecop.freeze time do
perform_import
assert_in_delta time.to_i, updated_alarm.updated_at.to_i, 1
end
end
it 'should not update fields not mentioned' do
perform_import
assert_equal 'foo', updated_alarm.metadata
end
it 'should update fields mentioned with hash mappings' do
perform_import
assert_equal 2, updated_alarm.status
end
end
end
context 'with :condition' do
let(:columns) { %w( id device_id alarm_type status metadata) }
let(:values) { [[99, 17, 1, 1, 'foo']] }
let(:updated_values) { [[99, 17, 1, 1, 'bar']] }
macro(:perform_import) do |*opts|
Alarm.import(
columns,
updated_values,
opts.extract_options!.merge(
on_duplicate_key_update: {
conflict_target: [:id],
condition: "alarms.metadata NOT LIKE '%foo%'",
columns: [:metadata]
},
validate: false
)
)
end
macro(:updated_alarm) { Alarm.find(@alarm.id) }
setup do
Alarm.import columns, values, validate: false
@alarm = Alarm.find 99
end
it 'should not update fields not matched' do
perform_import
assert_equal 'foo', updated_alarm.metadata
end
end
context "with no :conflict_target" do
context "with no primary key" do
it "raises ArgumentError" do
error = assert_raises ArgumentError do
Rule.import Build(3, :rules), on_duplicate_key_update: [:condition_text], validate: false
end
assert_match(/Expected :conflict_target to be specified/, error.message)
end
end
end
context "with no :columns" do
let(:columns) { %w( id title author_name author_email_address ) }
let(:values) { [[100, "Book", "John Doe", "john@doe.com"]] }
let(:updated_values) { [[100, "Title Should Not Change", "Author Should Not Change", "john@nogo.com"]] }
macro(:perform_import) do |*opts|
Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { conflict_target: :id }, validate: false)
end
setup do
Topic.import columns, values, validate: false
@topic = Topic.find 100
end
should_update_updated_at_on_timestamp_columns
end
end
end
end
end
|