Commit cf168508 authored by Drew Blessing's avatar Drew Blessing Committed by Drew Blessing

Add cascading namespace setting database migration helper

Add a migration helper to simplify adding a new cascading setting.
The helper will create the four required columns, 2 each in
namespace_settings and application_settings.
parent 083f3824
---
title: Add cascading namespace setting database migration helper
merge_request: 58940
author:
type: added
# frozen_string_literal: true
module Gitlab
module Database
module MigrationHelpers
module CascadingNamespaceSettings
include Gitlab::Database::MigrationHelpers
# Creates the four required columns that constitutes a single cascading
# namespace settings attribute. This helper is only appropriate if the
# setting is not already present as a non-cascading attribute.
#
# Creates the `setting_name` column along with the `lock_setting_name`
# column in both `namespace_settings` and `application_settings`.
#
# This helper is not reversible and must be defined in conjunction with
# `remove_cascading_namespace_setting` in separate up and down directions.
#
# setting_name - The name of the cascading attribute - same as defined
# in `NamespaceSetting` with the `cascading_attr` method.
# type - The column type for the setting itself (:boolean, :integer, etc.)
# options - Standard Rails column options hash. Accepts keys such as
# `null` and `default`.
#
# `null` and `default` options will only be applied to the `application_settings`
# column. In most cases, a non-null default value should be specified.
def add_cascading_namespace_setting(setting_name, type, **options)
lock_column_name = "lock_#{setting_name}".to_sym
check_cascading_namespace_setting_consistency(setting_name, lock_column_name)
namespace_options = options.merge(null: true, default: nil)
with_lock_retries do
add_column(:namespace_settings, setting_name, type, namespace_options)
add_column(:namespace_settings, lock_column_name, :boolean, default: false, null: false)
end
add_column(:application_settings, setting_name, type, options)
add_column(:application_settings, lock_column_name, :boolean, default: false, null: false)
end
def remove_cascading_namespace_setting(setting_name)
lock_column_name = "lock_#{setting_name}".to_sym
with_lock_retries do
remove_column(:namespace_settings, setting_name) if column_exists?(:namespace_settings, setting_name)
remove_column(:namespace_settings, lock_column_name) if column_exists?(:namespace_settings, lock_column_name)
end
remove_column(:application_settings, setting_name) if column_exists?(:application_settings, setting_name)
remove_column(:application_settings, lock_column_name) if column_exists?(:application_settings, lock_column_name)
end
private
def check_cascading_namespace_setting_consistency(setting_name, lock_name)
existing_columns = []
%w(namespace_settings application_settings).each do |table|
existing_columns << "#{table}.#{setting_name}" if column_exists?(table.to_sym, setting_name)
existing_columns << "#{table}.#{lock_name}" if column_exists?(table.to_sym, lock_name)
end
return if existing_columns.empty?
raise <<~ERROR
One or more cascading namespace columns already exist. `add_cascading_namespace_setting` helper
can only be used for new settings, when none of the required columns already exist.
Existing columns: #{existing_columns.join(', ')}
ERROR
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings do
let(:migration) do
ActiveRecord::Migration.new.extend(described_class)
end
describe '#add_cascading_namespace_setting' do
it 'creates the required columns', :aggregate_failures do
expect(migration).to receive(:add_column).with(:namespace_settings, :some_setting, :integer, null: true, default: nil)
expect(migration).to receive(:add_column).with(:namespace_settings, :lock_some_setting, :boolean, null: false, default: false)
expect(migration).to receive(:add_column).with(:application_settings, :some_setting, :integer, null: false, default: 5)
expect(migration).to receive(:add_column).with(:application_settings, :lock_some_setting, :boolean, null: false, default: false)
migration.add_cascading_namespace_setting(:some_setting, :integer, null: false, default: 5)
end
context 'when columns already exist' do
before do
migration.add_column(:namespace_settings, :cascading_setting, :integer)
migration.add_column(:application_settings, :lock_cascading_setting, :boolean)
end
it 'raises an error when some columns already exist' do
expect do
migration.add_cascading_namespace_setting(:cascading_setting, :integer)
end.to raise_error %r/Existing columns: namespace_settings.cascading_setting, application_settings.lock_cascading_setting/
end
end
end
describe '#remove_cascading_namespace_setting' do
before do
allow(migration).to receive(:column_exists?).and_return(true)
end
it 'removes the columns', :aggregate_failures do
expect(migration).to receive(:remove_column).with(:namespace_settings, :some_setting)
expect(migration).to receive(:remove_column).with(:namespace_settings, :lock_some_setting)
expect(migration).to receive(:remove_column).with(:application_settings, :some_setting)
expect(migration).to receive(:remove_column).with(:application_settings, :lock_some_setting)
migration.remove_cascading_namespace_setting(:some_setting)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment