summaryrefslogtreecommitdiff
path: root/spec/models/concerns/safely_change_column_default_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/concerns/safely_change_column_default_spec.rb')
-rw-r--r--spec/models/concerns/safely_change_column_default_spec.rb75
1 files changed, 75 insertions, 0 deletions
diff --git a/spec/models/concerns/safely_change_column_default_spec.rb b/spec/models/concerns/safely_change_column_default_spec.rb
new file mode 100644
index 00000000000..36782170eaf
--- /dev/null
+++ b/spec/models/concerns/safely_change_column_default_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe SafelyChangeColumnDefault, feature_category: :database do
+ include Gitlab::Database::DynamicModelHelpers
+ before do
+ ApplicationRecord.connection.execute(<<~SQL)
+ CREATE TABLE _test_gitlab_main_data(
+ id bigserial primary key not null,
+ value bigint default 1
+ );
+ SQL
+ end
+
+ let!(:model) do
+ define_batchable_model('_test_gitlab_main_data', connection: ApplicationRecord.connection).tap do |model|
+ model.include(described_class)
+ model.columns_changing_default(:value)
+ model.columns # Force the schema cache to populate
+ end
+ end
+
+ def alter_default(new_default)
+ ApplicationRecord.connection.execute(<<~SQL)
+ ALTER TABLE _test_gitlab_main_data ALTER COLUMN value SET DEFAULT #{new_default}
+ SQL
+ end
+
+ def recorded_insert_queries(&block)
+ recorder = ActiveRecord::QueryRecorder.new
+ recorder.record(&block)
+
+ recorder.log.select { |q| q.include?('INSERT INTO') }
+ end
+
+ def query_includes_value_column?(query)
+ parsed = PgQuery.parse(query)
+ parsed.tree.stmts.first.stmt.insert_stmt.cols.any? { |node| node.res_target.name == 'value' }
+ end
+
+ it 'forces the column to be written on a change' do
+ queries = recorded_insert_queries do
+ model.create!(value: 1)
+ end
+
+ expect(queries.length).to eq(1)
+
+ expect(query_includes_value_column?(queries.first)).to be_truthy
+ end
+
+ it 'does not write the column without a change' do
+ queries = recorded_insert_queries do
+ model.create!
+ end
+
+ expect(queries.length).to eq(1)
+ expect(query_includes_value_column?(queries.first)).to be_falsey
+ end
+
+ it 'does not send the old column value if the default has changed' do
+ alter_default(2)
+ model.create!
+
+ expect(model.pluck(:value)).to contain_exactly(2)
+ end
+
+ it 'prevents writing new default in place of the old default' do
+ alter_default(2)
+
+ model.create!(value: 1)
+
+ expect(model.pluck(:value)).to contain_exactly(1)
+ end
+end