From 94c2393c7e61cb51e4fe15713e116828264db602 Mon Sep 17 00:00:00 2001 From: Syed Faraaz Ahmad <113512303+faraaz-deepsource@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:14:05 +0530 Subject: [PATCH] Change table (#48) * ci: Update .deepsource.toml * create migrations for renaming and removing * handle renaming columns * fix * convert to sym * update version * remove pp --------- Co-authored-by: deepsource-totalanarchy[bot] <107136100+deepsource-totalanarchy[bot]@users.noreply.github.com> --- lib/trains/utils/migration_tailor.rb | 45 ++++++++++- lib/trains/version.rb | 2 +- lib/trains/visitor/migration.rb | 7 +- lib/trains/visitor/model.rb | 2 +- spec/fixtures/change_table.rb | 19 +++++ .../lib/trains/utils/migration_tailor_spec.rb | 76 ++++++++++++++++++- spec/lib/trains/visitor/migration_spec.rb | 65 ++++++++++++++++ 7 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 spec/fixtures/change_table.rb diff --git a/lib/trains/utils/migration_tailor.rb b/lib/trains/utils/migration_tailor.rb index efb46ba..9fdd6aa 100644 --- a/lib/trains/utils/migration_tailor.rb +++ b/lib/trains/utils/migration_tailor.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + module Trains module Utils + # Combine multiple migrations into models module MigrationTailor def self.stitch(models = {}, migrations) migrations.each do |mig| @@ -22,8 +25,46 @@ def self.stitch(models = {}, migrations) field.name == mig.fields.first.name end models[mig.table_name].fields.delete(column) + when :rename_column + column = + models[mig.table_name].fields.find do |field| + field.name == mig.fields.first.name + end + models[mig.table_name].fields.push( + Trains::DTO::Field.new( + name: mig.fields.first.type.to_sym, + type: column.type + ) + ) + models[mig.table_name].fields.delete(column) when :change_table - # TODO: handle renaming columns + mig.fields.each do |field| + case field.type + when :remove + column = + models[mig.table_name].fields.find do |mod_field| + mod_field.name == field.name + end + models[mig.table_name].fields.delete(column) + when :rename + # find the field and store temporarily + column = + models[mig.table_name].fields.find do |mod_field| + mod_field.name == field.name[0] + end + # Create new field from temp with new name + models[mig.table_name].fields.push( + Trains::DTO::Field.new( + name: field.name[1], + type: column.type + ) + ) + # Delete the field + models[mig.table_name].fields.delete(column) + else + models[mig.table_name].fields.push(field) + end + end when :change_column # get column column = @@ -34,6 +75,8 @@ def self.stitch(models = {}, migrations) models[mig.table_name].fields.delete(column) models[mig.table_name].fields << mig.fields.first + else + next end rescue NoMethodError diff --git a/lib/trains/version.rb b/lib/trains/version.rb index aea02d7..d600c14 100644 --- a/lib/trains/version.rb +++ b/lib/trains/version.rb @@ -1,3 +1,3 @@ module Trains - VERSION = '0.0.18'.freeze + VERSION = '0.0.19'.freeze end diff --git a/lib/trains/visitor/migration.rb b/lib/trains/visitor/migration.rb index d333ef5..262b9f0 100644 --- a/lib/trains/visitor/migration.rb +++ b/lib/trains/visitor/migration.rb @@ -22,6 +22,7 @@ class Migration < Base add_column_with_default change_column add_reference + rename_column remove_column ].freeze @@ -181,7 +182,11 @@ def parse_migration_field(node) # t.references type = :bigint value = "#{node.children[2].value}_id".to_sym - fields << DTO::Field.new(value.to_sym, type) + fields << DTO::Field.new(value, type) + when :rename + type = :rename + value = node.children[2..3].map { |field| field.value.to_sym } + fields << DTO::Field.new(value, type) when :index else # t.string, t.integer etc. diff --git a/lib/trains/visitor/model.rb b/lib/trains/visitor/model.rb index 3d6af0d..f659381 100644 --- a/lib/trains/visitor/model.rb +++ b/lib/trains/visitor/model.rb @@ -35,7 +35,7 @@ def parse_model(node) @result << DTO::Migration.new( @model_class, :add_column, - [DTO::Field.new(node.arguments.first.value, :bigint)], + [DTO::Field.new(node.arguments.first.value.to_sym, :bigint)], nil ) diff --git a/spec/fixtures/change_table.rb b/spec/fixtures/change_table.rb new file mode 100644 index 0000000..d45a94a --- /dev/null +++ b/spec/fixtures/change_table.rb @@ -0,0 +1,19 @@ +class ChangeTable < ActiveRecord::Migration[7.0] + def change + create_table :groups do |t| + t.string :title + + t.timestamps + end + add_column :groups, :name, :string + add_index :groups, :title, unique: true + + change_table :groups do |t| + t.remove :title + t.rename :name, :whatup + end + + rename_column :groups, :whatup, :name + remove_column :groups, :name + end +end diff --git a/spec/lib/trains/utils/migration_tailor_spec.rb b/spec/lib/trains/utils/migration_tailor_spec.rb index 9ea1c64..633b35d 100644 --- a/spec/lib/trains/utils/migration_tailor_spec.rb +++ b/spec/lib/trains/utils/migration_tailor_spec.rb @@ -7,7 +7,7 @@ 'Post' => Trains::DTO::Model.new( name: 'Post', fields: [ - Trains::DTO::Field.new(:name, :string), + Trains::DTO::Field.new(:name, :string) ], version: 6.3 ) @@ -36,7 +36,8 @@ end it 'creates a model and adds a column to it' do - models = Trains::Utils::MigrationTailor.stitch(models_from_schema, create_add_migs) + models = Trains::Utils::MigrationTailor.stitch(models_from_schema, + create_add_migs) expect(models).to eq( { 'Post' => @@ -135,4 +136,75 @@ ) end end + + context 'Given migrations with rename and remove column' do + let(:migs_with_rename) do + [ + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :create_table, + fields: [ + Trains::DTO::Field.new(:id, :bigint), + Trains::DTO::Field.new(:title, :string), + Trains::DTO::Field.new(:age, :integer), + Trains::DTO::Field.new(:created_at, :datetime), + Trains::DTO::Field.new(:updated_at, :datetime) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :add_column, + fields: [ + Trains::DTO::Field.new(:name, :string) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :change_table, + fields: [ + Trains::DTO::Field.new(:title, :remove), + Trains::DTO::Field.new(%i[name whatup], :rename) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :rename_column, + fields: [ + Trains::DTO::Field.new(:age, :alive_since) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :rename_column, + fields: [ + Trains::DTO::Field.new(:whatup, :name) + ], + version: 7.0 + ) + ] + end + + it 'generates models with renamed fields' do + models = Trains::Utils::MigrationTailor.stitch(migs_with_rename) + expect(models).to eq( + { + 'Group' => Trains::DTO::Model.new( + name: 'Group', + version: 7.0, + fields: [ + Trains::DTO::Field.new(:id, :bigint), + Trains::DTO::Field.new(:created_at, :datetime), + Trains::DTO::Field.new(:updated_at, :datetime), + Trains::DTO::Field.new(:alive_since, :integer), + Trains::DTO::Field.new(:name, :string) + ] + ) + } + ) + end + end end diff --git a/spec/lib/trains/visitor/migration_spec.rb b/spec/lib/trains/visitor/migration_spec.rb index 4dc27b9..5f44c88 100644 --- a/spec/lib/trains/visitor/migration_spec.rb +++ b/spec/lib/trains/visitor/migration_spec.rb @@ -31,6 +31,10 @@ File.expand_path "#{__FILE__}/../../../../fixtures/safety_assured.rb" end + let(:change_table) do + File.expand_path "#{__FILE__}/../../../../fixtures/change_table.rb" + end + context 'Given a valid DB migration file path' do it 'returns an object with its metadata' do parser = described_class.new @@ -298,4 +302,65 @@ end end end + + context 'Give a migration containing change_table migration' do + it 'create the appropriate migration objects' do + parser = described_class.new + file_ast = + RuboCop::AST::ProcessedSource.from_file( + change_table, + RUBY_VERSION.to_f + ).ast + file_ast.each_node { |node| parser.process(node) } + + expect(parser.result).to eq( + [ + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :create_table, + fields: [ + Trains::DTO::Field.new(:id, :bigint), + Trains::DTO::Field.new(:title, :string), + Trains::DTO::Field.new(:created_at, :datetime), + Trains::DTO::Field.new(:updated_at, :datetime) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :add_column, + fields: [ + Trains::DTO::Field.new(:name, :string) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :change_table, + fields: [ + Trains::DTO::Field.new(:title, :remove), + Trains::DTO::Field.new(%i[name whatup], :rename) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :rename_column, + fields: [ + Trains::DTO::Field.new(:whatup, :name) + ], + version: 7.0 + ), + Trains::DTO::Migration.new( + table_name: 'Group', + modifier: :remove_column, + fields: [ + Trains::DTO::Field.new(:name, nil) + ], + version: 7.0 + ) + ] + ) + end + end end