tlab-jp/rakudax

View on GitHub
lib/rakudax/tasks/migrate.rb

Summary

Maintainability
F
3 days
Test Coverage
module Rakudax
  class Tasks
    def self.migrate
      puts "[start migrate]=============#{Time.now}"
      Rakudax::Settings.models.each do |migration|
        classname = migration.name
        classname_before = "#{classname}Before"
        model = migration.before
        gen_code = "
    class #{classname_before} < ActiveRecord::Base
      after_initialize :readonly!
      begin
        include GeneralAttributes
      rescue
      end
        "
        if !model.id.nil? && model.auto_numbering
          gen_code += "attr_accessor :id
          "
        end
        (model.associations || []).each do |asc| 
          next unless asc.method
          next unless asc.scope
          gen_code += "#{asc.method} :#{asc.scope}#{", #{asc.options}" unless asc.options.nil?}
          "
        end

        (model.aliases || {}).each do |k, v|
          next unless k
          next unless v
          gen_code += "alias_attribute :#{v}, :#{k}
          "
        end

        (model.modules || []).each do |mdl| 
          gen_code += "include #{mdl}
          "
        end
        gen_code += "
    end"

        puts gen_code if Rakudax::Base.debug
        eval gen_code
        const_get(classname_before).establish_connection Rakudax::Base.dbconfig[model.db]
        unless model.table.nil?
          const_get(classname_before).table_name = model.table
        else
          const_get(classname_before).table_name = classname.tableize
        end
        const_get(classname_before).primary_key = model.id.to_sym unless model.id.nil?
        const_get(classname_before).inheritance_column = nil if model.inheritance

        model = migration.after
        gen_code = "
  class #{classname} < ActiveRecord::Base
        "

        (model.associations || []).each do |asc|
          next unless asc.method
          next unless asc.scope
          gen_code += "#{asc.method} :#{asc.scope}#{", #{asc.options}" unless asc.options.nil?}
          "
        end

        (model.attrs || []).each do |attr| 
          next unless attr.method
          next unless attr.scope
          gen_code += "#{attr.method} :#{attr.scope}#{", #{attr.options}" unless attr.options.nil?}
          "
        end

        (model.modules || []).each do |mdl|
          gen_code += "include #{mdl}
          "
        end

        gen_code += "
  end
        "

        puts gen_code if Rakudax::Base.debug
        eval gen_code
        const_get(classname).establish_connection Rakudax::Base.dbconfig[model.db]
        const_get(classname).table_name = model.table unless model.table.nil?
        const_get(classname).primary_key = model.id.to_sym unless model.id.nil?
      end

      Rakudax::Settings.models.each do |migration|
        classname = migration.name
        classname_before = "#{classname}Before"
        model = migration.after

        classcount = 0
        print "Checking #{classname} ... "
        begin
          classcount = const_get(classname).count
          puts "Success (before count: #{classcount})"
        rescue
          puts "Fail"
          STDERR.puts "Fatal Error: class #{classname} not found"
          next
        end

        if Rakudax::Settings.force_reset
          print "Delete All #{classname}s ... "
          tablename = model.table || classname.tableize
          ActiveRecord::Base.establish_connection Rakudax::Base.dbconfig[model.db]
          case Rakudax::Base.dbconfig[model.db]["adapter"]
          when "sqlite3"
            ActiveRecord::Base.connection.execute("DELETE FROM #{tablename}")
            ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence WHERE name='#{tablename}';")
            ActiveRecord::Base.connection.execute("VACUUM")
          else
            ActiveRecord::Base.connection.execute("TRUNCATE #{tablename}")
          end
          if const_get(classname).count == 0
            classcount = 0
            puts "Success"
          else
            puts "Fail"
          end
        end

        scope = const_get(classname_before).order(const_get(classname_before).primary_key)
        data_count = scope.count
        print "Migrate #{const_get(classname).to_s}#{"s" if data_count > 1}(#{data_count}) ..."
        batch_size = Rakudax::Settings.batch_size || 1000
        (1+data_count/batch_size).times do |i|
          offset = (i * batch_size)
          limit = data_count - i*batch_size
          limit = batch_size if limit > batch_size
          next if limit == 0
          scope.offset(offset).limit(limit).each do |data|
            obj = const_get(classname).new
            if migration.auto_matching
              const_get(classname).attribute_names.each do |key|
                obj.send("#{key}=", data.send(key)) if data.attribute_names.include?(key)
              end
            end
            (migration.attributes || {}).each do |key1, key2|
              obj.send("#{key2}=", data.send(key1))
            end
            begin
              unless obj.save
                STDERR.puts "Fatal Error: New #{classname} cant create. #{obj.errors.full_messages}"
              end
            rescue => ex
              STDERR.puts "Fatal Error: New #{classname} cant create. #{hash} (#{ex.message})"
            end
          end
        end

        totalcount = const_get(classname).count
        createcount = totalcount - classcount
        if createcount == data_count
          puts " OK (succeed: #{createcount}/failed: 0/ total: #{totalcount})"
        else
          puts " NG (succeed: #{createcount}/failed: #{data_count - createcount}/ total: #{totalcount})"
        end
        value = nil
      end

      puts "[finish migrate]=============#{Time.now}"
    end
  end
end