From a524c99136ddc02bc85799d3b34c86fd566d99da Mon Sep 17 00:00:00 2001 From: Yuji Yaginuma Date: Fri, 15 Mar 2024 15:55:56 +0900 Subject: [PATCH] Introduce `drop-table-only` feature Basically, dropping tables are very dangerous operation. So Ridgepole disables drop tables by default. But of course we need to do drop sometimes. In that case, I would like to run only `drop tables` to avoid unexpected changes. This PR implements the feature for that. --- README.md | 1 + bin/ridgepole | 1 + lib/ridgepole/diff.rb | 14 +- spec/mysql/cli/ridgepole_spec.rb | 1 + .../migrate/migrate_drop_table_only_spec.rb | 135 ++++++++++++++++++ 5 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 spec/mysql/migrate/migrate_drop_table_only_spec.rb diff --git a/README.md b/README.md index 529ffc46..3300ce1e 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Usage: ridgepole [options] --dump-with-default-fk-name --index-removed-drop-column --drop-table + --drop-table-only --mysql-change-table-options --mysql-change-table-comment --check-relation-type DEF_PK diff --git a/bin/ridgepole b/bin/ridgepole index 8c1ef3a7..a62a0a92 100755 --- a/bin/ridgepole +++ b/bin/ridgepole @@ -137,6 +137,7 @@ ARGV.options do |opt| opt.on('', '--dump-with-default-fk-name') { options[:dump_with_default_fk_name] = true } opt.on('', '--index-removed-drop-column') { options[:index_removed_drop_column] = true } opt.on('', '--drop-table') { options[:force_drop_table] = true } + opt.on('', '--drop-table-only') { options[:drop_table_only] = true } opt.on('', '--mysql-change-table-options') { options[:mysql_change_table_options] = true } opt.on('', '--mysql-change-table-comment') { options[:mysql_change_table_comment] = true } opt.on('', '--check-relation-type DEF_PK') { |v| options[:check_relation_type] = v } diff --git a/lib/ridgepole/diff.rb b/lib/ridgepole/diff.rb index 097fa033..6f8404b0 100644 --- a/lib/ridgepole/diff.rb +++ b/lib/ridgepole/diff.rb @@ -28,12 +28,14 @@ def diff(from, to, options = {}) if (from_attrs = from.delete(table_name)) @logger.verbose_info("# #{table_name}") - unless (attrs_delta = diff_inspect(from_attrs, to_attrs)).empty? - @logger.verbose_info(attrs_delta) - end + unless @options[:drop_table_only] + unless (attrs_delta = diff_inspect(from_attrs, to_attrs)).empty? + @logger.verbose_info(attrs_delta) + end - scan_change(table_name, from_attrs, to_attrs, delta) - else + scan_change(table_name, from_attrs, to_attrs, delta) + end + elsif !@options[:drop_table_only] delta[:add] ||= {} delta[:add][table_name] = to_attrs end @@ -41,7 +43,7 @@ def diff(from, to, options = {}) scan_relation_info(relation_info) - if !@options[:merge] && @options[:force_drop_table] + if !@options[:merge] && (@options[:force_drop_table] || @options[:drop_table_only]) from.each do |table_name, from_attrs| next unless target?(table_name) diff --git a/spec/mysql/cli/ridgepole_spec.rb b/spec/mysql/cli/ridgepole_spec.rb index 2d9f5c15..8b7df004 100644 --- a/spec/mysql/cli/ridgepole_spec.rb +++ b/spec/mysql/cli/ridgepole_spec.rb @@ -48,6 +48,7 @@ def conn_spec_str(database) --dump-with-default-fk-name --index-removed-drop-column --drop-table + --drop-table-only --mysql-change-table-options --mysql-change-table-comment --check-relation-type DEF_PK diff --git a/spec/mysql/migrate/migrate_drop_table_only_spec.rb b/spec/mysql/migrate/migrate_drop_table_only_spec.rb new file mode 100644 index 00000000..3c57cd2a --- /dev/null +++ b/spec/mysql/migrate/migrate_drop_table_only_spec.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true + +describe 'Ridgepole::Client#diff -> migrate' do + context 'when drop table only' do + let(:dsl) do + erbh(<<-ERB) + create_table "clubs", force: :cascade do |t| + t.string "name", default: "", null: false + t.index ["name"], name: "idx_name", unique: true + end + + create_table "departments", primary_key: "dept_no", force: :cascade do |t| + t.string "dept_name", limit: 40, null: false + t.index ["dept_name"], name: "dept_name", unique: true + end + + create_table "dept_emp", id: false, force: :cascade do |t| + t.integer "emp_no", null: false + t.string "dept_no", null: false + t.date "from_date", null: false + t.date "to_date", null: false + t.index ["dept_no"], name: "dept_no" + t.index ["emp_no"], name: "emp_no" + end + + create_table "dept_manager", id: false, force: :cascade do |t| + t.string "dept_no", null: false + t.integer "emp_no", null: false + t.date "from_date", null: false + t.date "to_date", null: false + t.index ["dept_no"], name: "dept_no" + t.index ["emp_no"], name: "emp_no" + end + + create_table "employee_clubs", force: :cascade do |t| + t.integer "emp_no", null: false + t.integer "club_id", null: false + t.index ["emp_no", "club_id"], name: "idx_emp_no_club_id" + end + + create_table "employees", primary_key: "emp_no", force: :cascade do |t| + t.date "birth_date", null: false + t.string "first_name", limit: 14, null: false + t.string "last_name", limit: 16, null: false + t.string "gender", limit: 1, null: false + t.date "hire_date", null: false + end + ERB + end + + let(:migrate_dsl) do + erbh(<<-ERB) + create_table "departments", primary_key: "dept_no", force: :cascade do |t| + t.string "dept_name", limit: 40, null: false + t.date "from_date", null: false + t.date "to_date", null: false + t.index ["dept_name"], name: "dept_name", unique: true + end + + create_table "dept_manager", id: false, force: :cascade do |t| + t.string "dept_no", null: false + t.integer "emp_no", null: false + t.index ["dept_no"], name: "dept_no" + t.index ["emp_no"], name: "emp_no" + end + + create_table "employee_clubs", force: :cascade do |t| + t.string "emp_no", null: false + t.integer "club_id", null: false + t.index ["emp_no", "club_id"], name: "idx_emp_no_club_id" + end + + create_table "employees", primary_key: "emp_no", force: :cascade do |t| + t.date "birth_date", null: false + t.string "first_name", limit: 14, null: false + t.string "last_name", limit: 16, null: false + t.string "gender", limit: 1, null: false + t.date "hire_date", null: false + end + + create_table "salaries", id: false, force: :cascade do |t| + t.integer "emp_no", null: false + t.integer "salary", null: false + t.date "from_date", null: false + t.date "to_date", null: false + end + + add_index "salaries", ["emp_no"], name: "emp_no", using: :btree + ERB + end + + let(:expected_dsl) do + erbh(<<-ERB) + create_table "departments", primary_key: "dept_no", force: :cascade do |t| + t.string "dept_name", limit: 40, null: false + t.index ["dept_name"], name: "dept_name", unique: true + end + + create_table "dept_manager", id: false, force: :cascade do |t| + t.string "dept_no", null: false + t.integer "emp_no", null: false + t.date "from_date", null: false + t.date "to_date", null: false + t.index ["dept_no"], name: "dept_no" + t.index ["emp_no"], name: "emp_no" + end + + create_table "employee_clubs", force: :cascade do |t| + t.integer "emp_no", null: false + t.integer "club_id", null: false + t.index ["emp_no", "club_id"], name: "idx_emp_no_club_id" + end + + create_table "employees", primary_key: "emp_no", force: :cascade do |t| + t.date "birth_date", null: false + t.string "first_name", limit: 14, null: false + t.string "last_name", limit: 16, null: false + t.string "gender", limit: 1, null: false + t.date "hire_date", null: false + end + ERB + end + + before { client.diff(dsl).migrate } + subject { client(drop_table_only: true) } + + it { + delta = subject.diff(migrate_dsl) + expect(delta.differ?).to be_truthy + expect(subject.dump).to match_ruby dsl + delta.migrate + expect(subject.dump).to match_ruby expected_dsl + } + end +end